Dactyloidae/toolkit/components/places/tests/unit/test_keywords.js

548 lines
26 KiB
JavaScript

"use strict"
function* check_keyword(aExpectExists, aHref, aKeyword, aPostData = null) {
// Check case-insensitivity.
aKeyword = aKeyword.toUpperCase();
let entry = yield PlacesUtils.keywords.fetch(aKeyword);
Assert.deepEqual(entry, yield PlacesUtils.keywords.fetch({ keyword: aKeyword }));
if (aExpectExists) {
Assert.ok(!!entry, "A keyword should exist");
Assert.equal(entry.url.href, aHref);
Assert.equal(entry.postData, aPostData);
Assert.deepEqual(entry, yield PlacesUtils.keywords.fetch({ keyword: aKeyword, url: aHref }));
let entries = [];
yield PlacesUtils.keywords.fetch({ url: aHref }, e => entries.push(e));
Assert.ok(entries.some(e => e.url.href == aHref && e.keyword == aKeyword.toLowerCase()));
} else {
Assert.ok(!entry || entry.url.href != aHref,
"The given keyword entry should not exist");
Assert.equal(null, yield PlacesUtils.keywords.fetch({ keyword: aKeyword, url: aHref }));
}
}
/**
* Polls the keywords cache waiting for the given keyword entry.
*/
function* promiseKeyword(keyword, expectedHref) {
let href = null;
do {
yield new Promise(resolve => do_timeout(100, resolve));
let entry = yield PlacesUtils.keywords.fetch(keyword);
if (entry)
href = entry.url.href;
} while (href != expectedHref);
}
function* check_no_orphans() {
let db = yield PlacesUtils.promiseDBConnection();
let rows = yield db.executeCached(
`SELECT id FROM moz_keywords k
WHERE NOT EXISTS (SELECT 1 FROM moz_places WHERE id = k.place_id)
`);
Assert.equal(rows.length, 0);
}
function expectBookmarkNotifications() {
let notifications = [];
let observer = new Proxy(NavBookmarkObserver, {
get(target, name) {
if (name == "check") {
PlacesUtils.bookmarks.removeObserver(observer);
return expectedNotifications =>
Assert.deepEqual(notifications, expectedNotifications);
}
if (name.startsWith("onItemChanged")) {
return function(itemId, property) {
if (property != "keyword")
return;
let args = Array.from(arguments, arg => {
if (arg && arg instanceof Ci.nsIURI)
return new URL(arg.spec);
if (arg && typeof(arg) == "number" && arg >= Date.now() * 1000)
return new Date(parseInt(arg/1000));
return arg;
});
notifications.push({ name: name, arguments: args });
}
}
if (name in target)
return target[name];
return undefined;
}
});
PlacesUtils.bookmarks.addObserver(observer, false);
return observer;
}
add_task(function* test_invalid_input() {
Assert.throws(() => PlacesUtils.keywords.fetch(null),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch(5),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch(undefined),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch({ keyword: null }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch({ keyword: {} }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch({ keyword: 5 }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.fetch({}),
/At least keyword or url must be provided/);
Assert.throws(() => PlacesUtils.keywords.fetch({ keyword: "test" }, "test"),
/onResult callback must be a valid function/);
Assert.throws(() => PlacesUtils.keywords.fetch({ url: "test" }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.fetch({ url: {} }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.fetch({ url: null }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.fetch({ url: "" }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.insert(null),
/Input should be a valid object/);
Assert.throws(() => PlacesUtils.keywords.insert("test"),
/Input should be a valid object/);
Assert.throws(() => PlacesUtils.keywords.insert(undefined),
/Input should be a valid object/);
Assert.throws(() => PlacesUtils.keywords.insert({ }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: null }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: 5 }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "" }),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", postData: 5 }),
/Invalid POST data/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", postData: {} }),
/Invalid POST data/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test" }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", url: 5 }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", url: "" }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", url: null }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.insert({ keyword: "test", url: "mozilla" }),
/is not a valid URL/);
Assert.throws(() => PlacesUtils.keywords.remove(null),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.remove(""),
/Invalid keyword/);
Assert.throws(() => PlacesUtils.keywords.remove(5),
/Invalid keyword/);
});
add_task(function* test_addKeyword() {
yield check_keyword(false, "http://example.com/", "keyword");
let fc = yield foreign_count("http://example.com/");
let observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
observer.check([]);
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 1); // +1 keyword
// Now remove the keyword.
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
observer.check([]);
yield check_keyword(false, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc); // -1 keyword
// Check using URL.
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: new URL("http://example.com/") });
yield check_keyword(true, "http://example.com/", "keyword");
yield PlacesUtils.keywords.remove("keyword");
yield check_keyword(false, "http://example.com/", "keyword");
yield check_no_orphans();
});
add_task(function* test_addBookmarkAndKeyword() {
yield check_keyword(false, "http://example.com/", "keyword");
let fc = yield foreign_count("http://example.com/");
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark.guid)),
"keyword", false, "keyword",
bookmark.lastModified, bookmark.type,
(yield PlacesUtils.promiseItemId(bookmark.parentGuid)),
bookmark.guid, bookmark.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 2); // +1 bookmark +1 keyword
// Now remove the keyword.
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark.guid)),
"keyword", false, "",
bookmark.lastModified, bookmark.type,
(yield PlacesUtils.promiseItemId(bookmark.parentGuid)),
bookmark.guid, bookmark.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
yield check_keyword(false, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 1); // -1 keyword
// Add again the keyword, then remove the bookmark.
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
observer = expectBookmarkNotifications();
yield PlacesUtils.bookmarks.remove(bookmark.guid);
// the notification is synchronous but the removal process is async.
// Unfortunately there's nothing explicit we can wait for.
while ((yield foreign_count("http://example.com/")));
// We don't get any itemChanged notification since the bookmark has been
// removed already.
observer.check([]);
yield check_keyword(false, "http://example.com/", "keyword");
yield check_no_orphans();
});
add_task(function* test_addKeywordToURIHavingKeyword() {
yield check_keyword(false, "http://example.com/", "keyword");
let fc = yield foreign_count("http://example.com/");
let observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
observer.check([]);
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 1); // +1 keyword
yield PlacesUtils.keywords.insert({ keyword: "keyword2", url: "http://example.com/" });
yield check_keyword(true, "http://example.com/", "keyword");
yield check_keyword(true, "http://example.com/", "keyword2");
Assert.equal((yield foreign_count("http://example.com/")), fc + 2); // +1 keyword
let entries = [];
let entry = yield PlacesUtils.keywords.fetch({ url: "http://example.com/" }, e => entries.push(e));
Assert.equal(entries.length, 2);
Assert.deepEqual(entries[0], entry);
// Now remove the keywords.
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
yield PlacesUtils.keywords.remove("keyword2");
observer.check([]);
yield check_keyword(false, "http://example.com/", "keyword");
yield check_keyword(false, "http://example.com/", "keyword2");
Assert.equal((yield foreign_count("http://example.com/")), fc); // -1 keyword
yield check_no_orphans();
});
add_task(function* test_addBookmarkToURIHavingKeyword() {
yield check_keyword(false, "http://example.com/", "keyword");
let fc = yield foreign_count("http://example.com/");
let observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
observer.check([]);
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 1); // +1 keyword
observer = expectBookmarkNotifications();
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
Assert.equal((yield foreign_count("http://example.com/")), fc + 2); // +1 bookmark
observer.check([]);
observer = expectBookmarkNotifications();
yield PlacesUtils.bookmarks.remove(bookmark.guid);
// the notification is synchronous but the removal process is async.
// Unfortunately there's nothing explicit we can wait for.
while ((yield foreign_count("http://example.com/")));
// We don't get any itemChanged notification since the bookmark has been
// removed already.
observer.check([]);
yield check_keyword(false, "http://example.com/", "keyword");
yield check_no_orphans();
});
add_task(function* test_sameKeywordDifferentURL() {
let fc1 = yield foreign_count("http://example1.com/");
let bookmark1 = yield PlacesUtils.bookmarks.insert({ url: "http://example1.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let fc2 = yield foreign_count("http://example2.com/");
let bookmark2 = yield PlacesUtils.bookmarks.insert({ url: "http://example2.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example1.com/" });
yield check_keyword(true, "http://example1.com/", "keyword");
Assert.equal((yield foreign_count("http://example1.com/")), fc1 + 2); // +1 bookmark +1 keyword
yield check_keyword(false, "http://example2.com/", "keyword");
Assert.equal((yield foreign_count("http://example2.com/")), fc2 + 1); // +1 bookmark
// Assign the same keyword to another url.
let observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example2.com/" });
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark1.guid)),
"keyword", false, "",
bookmark1.lastModified, bookmark1.type,
(yield PlacesUtils.promiseItemId(bookmark1.parentGuid)),
bookmark1.guid, bookmark1.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] },
{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark2.guid)),
"keyword", false, "keyword",
bookmark2.lastModified, bookmark2.type,
(yield PlacesUtils.promiseItemId(bookmark2.parentGuid)),
bookmark2.guid, bookmark2.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
yield check_keyword(false, "http://example1.com/", "keyword");
Assert.equal((yield foreign_count("http://example1.com/")), fc1 + 1); // -1 keyword
yield check_keyword(true, "http://example2.com/", "keyword");
Assert.equal((yield foreign_count("http://example2.com/")), fc2 + 2); // +1 keyword
// Now remove the keyword.
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark2.guid)),
"keyword", false, "",
bookmark2.lastModified, bookmark2.type,
(yield PlacesUtils.promiseItemId(bookmark2.parentGuid)),
bookmark2.guid, bookmark2.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
yield check_keyword(false, "http://example1.com/", "keyword");
yield check_keyword(false, "http://example2.com/", "keyword");
Assert.equal((yield foreign_count("http://example1.com/")), fc1 + 1);
Assert.equal((yield foreign_count("http://example2.com/")), fc2 + 1); // -1 keyword
yield PlacesUtils.bookmarks.remove(bookmark1);
yield PlacesUtils.bookmarks.remove(bookmark2);
Assert.equal((yield foreign_count("http://example1.com/")), fc1); // -1 bookmark
while ((yield foreign_count("http://example2.com/"))); // -1 keyword
yield check_no_orphans();
});
add_task(function* test_sameURIDifferentKeyword() {
let fc = yield foreign_count("http://example.com/");
let observer = expectBookmarkNotifications();
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield PlacesUtils.keywords.insert({keyword: "keyword", url: "http://example.com/" });
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 2); // +1 bookmark +1 keyword
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark.guid)),
"keyword", false, "keyword",
bookmark.lastModified, bookmark.type,
(yield PlacesUtils.promiseItemId(bookmark.parentGuid)),
bookmark.guid, bookmark.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.insert({ keyword: "keyword2", url: "http://example.com/" });
yield check_keyword(true, "http://example.com/", "keyword");
yield check_keyword(true, "http://example.com/", "keyword2");
Assert.equal((yield foreign_count("http://example.com/")), fc + 3); // +1 keyword
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark.guid)),
"keyword", false, "keyword2",
bookmark.lastModified, bookmark.type,
(yield PlacesUtils.promiseItemId(bookmark.parentGuid)),
bookmark.guid, bookmark.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
// Add a third keyword.
yield PlacesUtils.keywords.insert({ keyword: "keyword3", url: "http://example.com/" });
yield check_keyword(true, "http://example.com/", "keyword");
yield check_keyword(true, "http://example.com/", "keyword2");
yield check_keyword(true, "http://example.com/", "keyword3");
Assert.equal((yield foreign_count("http://example.com/")), fc + 4); // +1 keyword
// Remove one of the keywords.
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
yield check_keyword(false, "http://example.com/", "keyword");
yield check_keyword(true, "http://example.com/", "keyword2");
yield check_keyword(true, "http://example.com/", "keyword3");
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark.guid)),
"keyword", false, "",
bookmark.lastModified, bookmark.type,
(yield PlacesUtils.promiseItemId(bookmark.parentGuid)),
bookmark.guid, bookmark.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
Assert.equal((yield foreign_count("http://example.com/")), fc + 3); // -1 keyword
// Now remove the bookmark.
yield PlacesUtils.bookmarks.remove(bookmark);
while ((yield foreign_count("http://example.com/")));
yield check_keyword(false, "http://example.com/", "keyword");
yield check_keyword(false, "http://example.com/", "keyword2");
yield check_keyword(false, "http://example.com/", "keyword3");
check_no_orphans();
});
add_task(function* test_deleteKeywordMultipleBookmarks() {
let fc = yield foreign_count("http://example.com/");
let observer = expectBookmarkNotifications();
let bookmark1 = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
let bookmark2 = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
yield check_keyword(true, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 3); // +2 bookmark +1 keyword
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark2.guid)),
"keyword", false, "keyword",
bookmark2.lastModified, bookmark2.type,
(yield PlacesUtils.promiseItemId(bookmark2.parentGuid)),
bookmark2.guid, bookmark2.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] },
{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark1.guid)),
"keyword", false, "keyword",
bookmark1.lastModified, bookmark1.type,
(yield PlacesUtils.promiseItemId(bookmark1.parentGuid)),
bookmark1.guid, bookmark1.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
observer = expectBookmarkNotifications();
yield PlacesUtils.keywords.remove("keyword");
yield check_keyword(false, "http://example.com/", "keyword");
Assert.equal((yield foreign_count("http://example.com/")), fc + 2); // -1 keyword
observer.check([{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark2.guid)),
"keyword", false, "",
bookmark2.lastModified, bookmark2.type,
(yield PlacesUtils.promiseItemId(bookmark2.parentGuid)),
bookmark2.guid, bookmark2.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] },
{ name: "onItemChanged",
arguments: [ (yield PlacesUtils.promiseItemId(bookmark1.guid)),
"keyword", false, "",
bookmark1.lastModified, bookmark1.type,
(yield PlacesUtils.promiseItemId(bookmark1.parentGuid)),
bookmark1.guid, bookmark1.parentGuid, "",
Ci.nsINavBookmarksService.SOURCE_DEFAULT ] } ]);
// Now remove the bookmarks.
yield PlacesUtils.bookmarks.remove(bookmark1);
yield PlacesUtils.bookmarks.remove(bookmark2);
Assert.equal((yield foreign_count("http://example.com/")), fc); // -2 bookmarks
check_no_orphans();
});
add_task(function* test_multipleKeywordsSamePostData() {
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/", postData: "postData1" });
yield check_keyword(true, "http://example.com/", "keyword", "postData1");
// Add another keyword with same postData, should fail.
yield Assert.rejects(PlacesUtils.keywords.insert({ keyword: "keyword2", url: "http://example.com/", postData: "postData1" }),
/constraint failed/);
yield check_keyword(false, "http://example.com/", "keyword2", "postData1");
yield PlacesUtils.keywords.remove("keyword");
check_no_orphans();
});
add_task(function* test_oldPostDataAPI() {
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com/" });
let itemId = yield PlacesUtils.promiseItemId(bookmark.guid);
yield PlacesUtils.setPostDataForBookmark(itemId, "postData");
yield check_keyword(true, "http://example.com/", "keyword", "postData");
Assert.equal(PlacesUtils.getPostDataForBookmark(itemId), "postData");
yield PlacesUtils.keywords.remove("keyword");
yield PlacesUtils.bookmarks.remove(bookmark);
check_no_orphans();
});
add_task(function* test_oldKeywordsAPI() {
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield check_keyword(false, "http://example.com/", "keyword");
let itemId = yield PlacesUtils.promiseItemId(bookmark.guid);
PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "keyword");
yield promiseKeyword("keyword", "http://example.com/");
// Remove the keyword.
PlacesUtils.bookmarks.setKeywordForBookmark(itemId, "");
yield promiseKeyword("keyword", null);
yield PlacesUtils.keywords.insert({ keyword: "keyword", url: "http://example.com" });
Assert.equal(PlacesUtils.bookmarks.getKeywordForBookmark(itemId), "keyword");
Assert.equal(PlacesUtils.bookmarks.getURIForKeyword("keyword").spec, "http://example.com/");
yield PlacesUtils.bookmarks.remove(bookmark);
check_no_orphans();
});
add_task(function* test_bookmarkURLChange() {
let fc1 = yield foreign_count("http://example1.com/");
let fc2 = yield foreign_count("http://example2.com/");
let bookmark = yield PlacesUtils.bookmarks.insert({ url: "http://example1.com/",
type: PlacesUtils.bookmarks.TYPE_BOOKMARK,
parentGuid: PlacesUtils.bookmarks.unfiledGuid });
yield PlacesUtils.keywords.insert({ keyword: "keyword",
url: "http://example1.com/" });
yield check_keyword(true, "http://example1.com/", "keyword");
Assert.equal((yield foreign_count("http://example1.com/")), fc1 + 2); // +1 bookmark +1 keyword
yield PlacesUtils.bookmarks.update({ guid: bookmark.guid,
url: "http://example2.com/"});
yield promiseKeyword("keyword", "http://example2.com/");
yield check_keyword(false, "http://example1.com/", "keyword");
yield check_keyword(true, "http://example2.com/", "keyword");
Assert.equal((yield foreign_count("http://example1.com/")), fc1); // -1 bookmark -1 keyword
Assert.equal((yield foreign_count("http://example2.com/")), fc2 + 2); // +1 bookmark +1 keyword
});