summaryrefslogtreecommitdiffstats
path: root/toolkit/components/places/tests/history/test_remove.js
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/places/tests/history/test_remove.js')
-rw-r--r--toolkit/components/places/tests/history/test_remove.js354
1 files changed, 354 insertions, 0 deletions
diff --git a/toolkit/components/places/tests/history/test_remove.js b/toolkit/components/places/tests/history/test_remove.js
new file mode 100644
index 0000000000..8c5e941fd0
--- /dev/null
+++ b/toolkit/components/places/tests/history/test_remove.js
@@ -0,0 +1,354 @@
+/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et: */
+
+// Tests for `History.remove`, as implemented in History.jsm
+
+"use strict";
+
+// Test removing a single page
+add_task(async function test_remove_single() {
+ await PlacesUtils.history.clear();
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ let WITNESS_URI = NetUtil.newURI(
+ "http://mozilla.com/test_browserhistory/test_remove/" + Math.random()
+ );
+ await PlacesTestUtils.addVisits(WITNESS_URI);
+ Assert.ok(page_in_database(WITNESS_URI));
+
+ let remover = async function (name, filter, options) {
+ info(name);
+ info(JSON.stringify(options));
+ info("Setting up visit");
+
+ let uri = NetUtil.newURI(
+ "http://mozilla.com/test_browserhistory/test_remove/" + Math.random()
+ );
+ let title = "Visit " + Math.random();
+ await PlacesTestUtils.addVisits({ uri, title });
+ Assert.ok(visits_in_database(uri), "History entry created");
+
+ let removeArg = await filter(uri);
+
+ if (options.addBookmark) {
+ await PlacesUtils.bookmarks.insert({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ url: uri,
+ title: "test bookmark",
+ });
+ }
+
+ let shouldRemove = !options.addBookmark;
+ let placesEventListener;
+ let promiseObserved = new Promise((resolve, reject) => {
+ placesEventListener = events => {
+ for (const event of events) {
+ switch (event.type) {
+ case "page-title-changed": {
+ reject(
+ "Unexpected page-title-changed event happens on " + event.url
+ );
+ break;
+ }
+ case "history-cleared": {
+ reject("Unexpected history-cleared event happens");
+ break;
+ }
+ case "pages-rank-changed": {
+ try {
+ Assert.ok(!shouldRemove, "Observing pages-rank-changed event");
+ } finally {
+ resolve();
+ }
+ break;
+ }
+ case "page-removed": {
+ Assert.equal(
+ event.isRemovedFromStore,
+ shouldRemove,
+ "Observe page-removed event with right removal type"
+ );
+ Assert.equal(
+ event.url,
+ uri.spec,
+ "Observing effect on the right uri"
+ );
+ resolve();
+ break;
+ }
+ }
+ }
+ };
+ });
+ PlacesObservers.addListener(
+ [
+ "page-title-changed",
+ "history-cleared",
+ "pages-rank-changed",
+ "page-removed",
+ ],
+ placesEventListener
+ );
+
+ info("Performing removal");
+ let removed = false;
+ if (options.useCallback) {
+ let onRowCalled = false;
+ let guid = await PlacesTestUtils.getDatabaseValue("moz_places", "guid", {
+ url: uri,
+ });
+ removed = await PlacesUtils.history.remove(removeArg, page => {
+ Assert.equal(onRowCalled, false, "Callback has not been called yet");
+ onRowCalled = true;
+ Assert.equal(
+ page.url.href,
+ uri.spec,
+ "Callback provides the correct url"
+ );
+ Assert.equal(page.guid, guid, "Callback provides the correct guid");
+ Assert.equal(page.title, title, "Callback provides the correct title");
+ });
+ Assert.ok(onRowCalled, "Callback has been called");
+ } else {
+ removed = await PlacesUtils.history.remove(removeArg);
+ }
+
+ await promiseObserved;
+ PlacesObservers.removeListener(
+ [
+ "page-title-changed",
+ "history-cleared",
+ "pages-rank-changed",
+ "page-removed",
+ ],
+ placesEventListener
+ );
+
+ Assert.equal(visits_in_database(uri), 0, "History entry has disappeared");
+ Assert.notEqual(
+ visits_in_database(WITNESS_URI),
+ 0,
+ "Witness URI still has visits"
+ );
+ Assert.notEqual(
+ page_in_database(WITNESS_URI),
+ 0,
+ "Witness URI is still here"
+ );
+ if (shouldRemove) {
+ Assert.ok(removed, "Something was removed");
+ Assert.equal(page_in_database(uri), 0, "Page has disappeared");
+ } else {
+ Assert.ok(!removed, "The page was not removed, as there was a bookmark");
+ Assert.notEqual(page_in_database(uri), 0, "The page is still present");
+ }
+ };
+
+ try {
+ for (let useCallback of [false, true]) {
+ for (let addBookmark of [false, true]) {
+ let options = { useCallback, addBookmark };
+ await remover(
+ "Testing History.remove() with a single URI",
+ x => x,
+ options
+ );
+ await remover(
+ "Testing History.remove() with a single string url",
+ x => x.spec,
+ options
+ );
+ await remover(
+ "Testing History.remove() with a single string guid",
+ async x =>
+ PlacesTestUtils.getDatabaseValue("moz_places", "guid", { url: x }),
+ options
+ );
+ await remover(
+ "Testing History.remove() with a single URI in an array",
+ x => [x],
+ options
+ );
+ await remover(
+ "Testing History.remove() with a single string url in an array",
+ x => [x.spec],
+ options
+ );
+ await remover(
+ "Testing History.remove() with a single string guid in an array",
+ x =>
+ PlacesTestUtils.getDatabaseValue("moz_places", "guid", { url: x }),
+ options
+ );
+ }
+ }
+ } finally {
+ await PlacesUtils.history.clear();
+ }
+});
+
+add_task(async function cleanup() {
+ await PlacesUtils.history.clear();
+ await PlacesUtils.bookmarks.eraseEverything();
+});
+
+// Test the various error cases
+add_task(async function test_error_cases() {
+ Assert.throws(
+ () => PlacesUtils.history.remove(),
+ /TypeError: Invalid url/,
+ "History.remove with no argument should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove(null),
+ /TypeError: Invalid url/,
+ "History.remove with `null` should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove(undefined),
+ /TypeError: Invalid url/,
+ "History.remove with `undefined` should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove("not a guid, obviously"),
+ /TypeError: .* is not a valid URL/,
+ "History.remove with an ill-formed guid/url argument should throw a TypeError"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.remove({
+ "not the kind of object we know how to handle": true,
+ }),
+ /TypeError: Invalid url/,
+ "History.remove with an unexpected object should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove([]),
+ /TypeError: Expected at least one page/,
+ "History.remove with an empty array should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove([null]),
+ /TypeError: Invalid url or guid/,
+ "History.remove with an array containing null should throw a TypeError"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.remove([
+ "http://example.org",
+ "not a guid, obviously",
+ ]),
+ /TypeError: .* is not a valid URL/,
+ "History.remove with an array containing an ill-formed guid/url argument should throw a TypeError"
+ );
+ Assert.throws(
+ () => PlacesUtils.history.remove(["0123456789ab" /* valid guid*/, null]),
+ /TypeError: Invalid url or guid: null/,
+ "History.remove with an array containing a guid and a second argument that is null should throw a TypeError"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.remove([
+ "http://example.org",
+ { "not the kind of object we know how to handle": true },
+ ]),
+ /TypeError: Invalid url/,
+ "History.remove with an array containing an unexpected objecgt should throw a TypeError"
+ );
+ Assert.throws(
+ () =>
+ PlacesUtils.history.remove(
+ "http://example.org",
+ "not a function, obviously"
+ ),
+ /TypeError: Invalid function/,
+ "History.remove with a second argument that is not a function argument should throw a TypeError"
+ );
+ try {
+ PlacesUtils.history.remove(
+ "http://example.org/I/have/clearly/not/been/added",
+ null
+ );
+ Assert.ok(true, "History.remove should ignore `null` as a second argument");
+ } catch (ex) {
+ Assert.ok(
+ false,
+ "History.remove should ignore `null` as a second argument"
+ );
+ }
+});
+
+add_task(async function test_orphans() {
+ let uri = NetUtil.newURI("http://moz.org/");
+ await PlacesTestUtils.addVisits({ uri });
+
+ PlacesUtils.favicons.setAndFetchFaviconForPage(
+ uri,
+ SMALLPNG_DATA_URI,
+ true,
+ PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
+ null,
+ Services.scriptSecurityManager.getSystemPrincipal()
+ );
+ // Also create a root icon.
+ let faviconURI = Services.io.newURI(uri.spec + "favicon.ico");
+ PlacesUtils.favicons.replaceFaviconDataFromDataURL(
+ faviconURI,
+ SMALLPNG_DATA_URI.spec,
+ 0,
+ Services.scriptSecurityManager.getSystemPrincipal()
+ );
+ PlacesUtils.favicons.setAndFetchFaviconForPage(
+ uri,
+ faviconURI,
+ true,
+ PlacesUtils.favicons.FAVICON_LOAD_NON_PRIVATE,
+ null,
+ Services.scriptSecurityManager.getSystemPrincipal()
+ );
+
+ await PlacesUtils.history.update({
+ url: uri,
+ annotations: new Map([["test", "restval"]]),
+ });
+
+ await PlacesUtils.history.remove(uri);
+ Assert.ok(
+ !(await PlacesTestUtils.isPageInDB(uri)),
+ "Page should have been removed"
+ );
+
+ let db = await PlacesUtils.promiseDBConnection();
+ let rows = await db.execute(`SELECT (SELECT count(*) FROM moz_annos) +
+ (SELECT count(*) FROM moz_icons) +
+ (SELECT count(*) FROM moz_pages_w_icons) +
+ (SELECT count(*) FROM moz_icons_to_pages) AS count`);
+ Assert.equal(rows[0].getResultByName("count"), 0, "Should not find orphans");
+});
+
+add_task(async function test_remove_backslash() {
+ // Backslash is an escape char in Sqlite, we must take care of that when
+ // removing a url containing a backslash.
+ const url = "https://www.mozilla.org/?test=\u005C";
+ await PlacesTestUtils.addVisits(url);
+ Assert.ok(await PlacesUtils.history.remove(url), "A page should be removed");
+ Assert.deepEqual(
+ await PlacesUtils.history.fetch(url),
+ null,
+ "The page should not be found"
+ );
+});
+
+add_task(async function test_url_with_apices() {
+ // Apices may confuse code and cause injection if mishandled.
+ // The ideal test would be with a javascript url, because it would not be
+ // encoded by URL(), unfortunately it would also not be added to history.
+ const url = `http://mozilla.org/\u0022\u0027`;
+ await PlacesTestUtils.addVisits(url);
+ Assert.ok(await PlacesUtils.history.remove(url), "A page should be removed");
+ Assert.deepEqual(
+ await PlacesUtils.history.fetch(url),
+ null,
+ "The page should not be found"
+ );
+});