summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/tests/xpcshell
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /browser/components/newtab/tests/xpcshell
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'browser/components/newtab/tests/xpcshell')
-rw-r--r--browser/components/newtab/tests/xpcshell/.eslintrc.js7
-rw-r--r--browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js236
-rw-r--r--browser/components/newtab/tests/xpcshell/test_NewTabPrefsProvider.js50
-rw-r--r--browser/components/newtab/tests/xpcshell/test_NewTabSearchProvider.js82
-rw-r--r--browser/components/newtab/tests/xpcshell/test_NewTabURL.js52
-rw-r--r--browser/components/newtab/tests/xpcshell/test_PlacesProvider.js358
-rw-r--r--browser/components/newtab/tests/xpcshell/xpcshell.ini11
7 files changed, 796 insertions, 0 deletions
diff --git a/browser/components/newtab/tests/xpcshell/.eslintrc.js b/browser/components/newtab/tests/xpcshell/.eslintrc.js
new file mode 100644
index 000000000..d35787cd2
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/.eslintrc.js
@@ -0,0 +1,7 @@
+"use strict";
+
+module.exports = {
+ "extends": [
+ "../../../../../testing/xpcshell/xpcshell.eslintrc.js"
+ ]
+};
diff --git a/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
new file mode 100644
index 000000000..21f68ab70
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/test_AboutNewTabService.js
@@ -0,0 +1,236 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* globals Services, XPCOMUtils, NewTabPrefsProvider, Preferences, aboutNewTabService, do_register_cleanup */
+
+"use strict";
+
+const {utils: Cu} = Components;
+Cu.import("resource://gre/modules/Services.jsm");
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
+ "resource:///modules/NewTabPrefsProvider.jsm");
+
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+ "@mozilla.org/browser/aboutnewtab-service;1",
+ "nsIAboutNewTabService");
+
+XPCOMUtils.defineLazyModuleGetter(this, "Locale",
+ "resource://gre/modules/Locale.jsm");
+
+const DEFAULT_HREF = aboutNewTabService.generateRemoteURL();
+const DEFAULT_CHROME_URL = "chrome://browser/content/newtab/newTab.xhtml";
+const DOWNLOADS_URL = "chrome://browser/content/downloads/contentAreaDownloadsView.xul";
+const DEFAULT_VERSION = aboutNewTabService.remoteVersion;
+
+function cleanup() {
+ Services.prefs.setBoolPref("browser.newtabpage.remote", false);
+ Services.prefs.setCharPref("browser.newtabpage.remote.version", DEFAULT_VERSION);
+ aboutNewTabService.resetNewTabURL();
+ NewTabPrefsProvider.prefs.uninit();
+}
+
+do_register_cleanup(cleanup);
+
+/**
+ * Test the overriding of the default URL
+ */
+add_task(function* test_override_remote_disabled() {
+ NewTabPrefsProvider.prefs.init();
+ let notificationPromise;
+ Services.prefs.setBoolPref("browser.newtabpage.remote", false);
+
+ // tests default is the local newtab resource
+ Assert.equal(aboutNewTabService.defaultURL, DEFAULT_CHROME_URL,
+ `Default newtab URL should be ${DEFAULT_CHROME_URL}`);
+
+ // override with some remote URL
+ let url = "http://example.com/";
+ notificationPromise = nextChangeNotificationPromise(url);
+ aboutNewTabService.newTabURL = url;
+ yield notificationPromise;
+ Assert.ok(aboutNewTabService.overridden, "Newtab URL should be overridden");
+ Assert.ok(!aboutNewTabService.remoteEnabled, "Newtab remote should not be enabled");
+ Assert.equal(aboutNewTabService.newTabURL, url, "Newtab URL should be the custom URL");
+
+ // test reset with remote disabled
+ notificationPromise = nextChangeNotificationPromise("about:newtab");
+ aboutNewTabService.resetNewTabURL();
+ yield notificationPromise;
+ Assert.ok(!aboutNewTabService.overridden, "Newtab URL should not be overridden");
+ Assert.equal(aboutNewTabService.newTabURL, "about:newtab", "Newtab URL should be the default");
+
+ // test override to a chrome URL
+ notificationPromise = nextChangeNotificationPromise(DOWNLOADS_URL);
+ aboutNewTabService.newTabURL = DOWNLOADS_URL;
+ yield notificationPromise;
+ Assert.ok(aboutNewTabService.overridden, "Newtab URL should be overridden");
+ Assert.equal(aboutNewTabService.newTabURL, DOWNLOADS_URL, "Newtab URL should be the custom URL");
+
+ cleanup();
+});
+
+add_task(function* test_override_remote_enabled() {
+ NewTabPrefsProvider.prefs.init();
+ let notificationPromise;
+ // change newtab page to remote
+ notificationPromise = nextChangeNotificationPromise("about:newtab");
+ Services.prefs.setBoolPref("browser.newtabpage.remote", true);
+ yield notificationPromise;
+ let remoteHref = aboutNewTabService.generateRemoteURL();
+ Assert.equal(aboutNewTabService.defaultURL, remoteHref, "Newtab URL should be the default remote URL");
+ Assert.ok(!aboutNewTabService.overridden, "Newtab URL should not be overridden");
+ Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
+
+ // change to local newtab page while remote is enabled
+ notificationPromise = nextChangeNotificationPromise(DEFAULT_CHROME_URL);
+ aboutNewTabService.newTabURL = DEFAULT_CHROME_URL;
+ yield notificationPromise;
+ Assert.equal(aboutNewTabService.newTabURL, DEFAULT_CHROME_URL,
+ "Newtab URL set to chrome url");
+ Assert.equal(aboutNewTabService.defaultURL, DEFAULT_CHROME_URL,
+ "Newtab URL defaultURL set to the default chrome URL");
+ Assert.ok(aboutNewTabService.overridden, "Newtab URL should be overridden");
+ Assert.ok(!aboutNewTabService.remoteEnabled, "Newtab remote should not be enabled");
+
+ cleanup();
+});
+
+/**
+ * Tests reponse to updates to prefs
+ */
+add_task(function* test_updates() {
+ /*
+ * Simulates a "cold-boot" situation, with some pref already set before testing a series
+ * of changes.
+ */
+ Preferences.set("browser.newtabpage.remote", true);
+ aboutNewTabService.resetNewTabURL(); // need to set manually because pref notifs are off
+ let notificationPromise;
+ let productionModeBaseUrl = "https://content.cdn.mozilla.net";
+ let testModeBaseUrl = "https://example.com";
+ let expectedPath = `/newtab` +
+ `/v${aboutNewTabService.remoteVersion}` +
+ `/${aboutNewTabService.remoteReleaseName}` +
+ "/en-GB" +
+ "/index.html";
+ let expectedHref = productionModeBaseUrl + expectedPath;
+ Preferences.set("intl.locale.matchOS", true);
+ Preferences.set("general.useragent.locale", "en-GB");
+ Preferences.set("browser.newtabpage.remote.mode", "production");
+ NewTabPrefsProvider.prefs.init();
+
+ // test update checks for prefs
+ notificationPromise = nextChangeNotificationPromise(
+ expectedHref, "Remote href should be updated");
+ Preferences.set("intl.locale.matchOS", false);
+ yield notificationPromise;
+
+ notificationPromise = nextChangeNotificationPromise(
+ DEFAULT_HREF, "Remote href changes back to default");
+ Preferences.set("general.useragent.locale", "en-US");
+ yield notificationPromise;
+
+ // test update fires when mode is changed
+ expectedPath = expectedPath.replace("/en-GB/", "/en-US/");
+ notificationPromise = nextChangeNotificationPromise(
+ testModeBaseUrl + expectedPath, "Remote href changes back to origin of test mode");
+ Preferences.set("browser.newtabpage.remote.mode", "test");
+ yield notificationPromise;
+
+ // test invalid mode ends up pointing to production url
+ notificationPromise = nextChangeNotificationPromise(
+ DEFAULT_HREF, "Remote href changes back to production default");
+ Preferences.set("browser.newtabpage.remote.mode", "invalid");
+ yield notificationPromise;
+
+ // test update fires on override and reset
+ let testURL = "https://example.com/";
+ notificationPromise = nextChangeNotificationPromise(
+ testURL, "a notification occurs on override");
+ aboutNewTabService.newTabURL = testURL;
+ yield notificationPromise;
+
+ // from overridden to default
+ notificationPromise = nextChangeNotificationPromise(
+ "about:newtab", "a notification occurs on reset");
+ aboutNewTabService.resetNewTabURL();
+ Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
+ Assert.equal(aboutNewTabService.defaultURL, DEFAULT_HREF, "Default URL should be the remote page");
+ yield notificationPromise;
+
+ // override to default URL from default URL
+ notificationPromise = nextChangeNotificationPromise(
+ testURL, "a notification only occurs for a change in overridden urls");
+ aboutNewTabService.newTabURL = aboutNewTabService.generateRemoteURL();
+ Assert.ok(aboutNewTabService.remoteEnabled, "Newtab remote should be enabled");
+ aboutNewTabService.newTabURL = testURL;
+ yield notificationPromise;
+ Assert.ok(!aboutNewTabService.remoteEnabled, "Newtab remote should not be enabled");
+
+ // reset twice, only one notification for default URL
+ notificationPromise = nextChangeNotificationPromise(
+ "about:newtab", "reset occurs");
+ aboutNewTabService.resetNewTabURL();
+ yield notificationPromise;
+
+ cleanup();
+});
+
+/**
+ * Verifies that releaseFromUpdateChannel
+ * Returns the correct release names
+ */
+add_task(function* test_release_names() {
+ let valid_channels = ["esr", "release", "beta", "aurora", "nightly"];
+ let invalid_channels = new Set(["default", "invalid"]);
+
+ for (let channel of valid_channels) {
+ Assert.equal(channel, aboutNewTabService.releaseFromUpdateChannel(channel),
+ "release == channel name when valid");
+ }
+
+ for (let channel of invalid_channels) {
+ Assert.equal("nightly", aboutNewTabService.releaseFromUpdateChannel(channel),
+ "release == nightly when invalid");
+ }
+});
+
+/**
+ * Verifies that remote version updates changes the remote newtab url
+ */
+add_task(function* test_version_update() {
+ NewTabPrefsProvider.prefs.init();
+
+ Services.prefs.setBoolPref("browser.newtabpage.remote", true);
+ Assert.ok(aboutNewTabService.remoteEnabled, "remote mode enabled");
+
+ let productionModeBaseUrl = "https://content.cdn.mozilla.net";
+ let version_incr = String(parseInt(DEFAULT_VERSION) + 1);
+ let expectedPath = `/newtab` +
+ `/v${version_incr}` +
+ `/${aboutNewTabService.remoteReleaseName}` +
+ `/${Locale.getLocale()}` +
+ `/index.html`;
+ let expectedHref = productionModeBaseUrl + expectedPath;
+
+ let notificationPromise;
+ notificationPromise = nextChangeNotificationPromise(expectedHref);
+ Preferences.set("browser.newtabpage.remote.version", version_incr);
+ yield notificationPromise;
+
+ cleanup();
+});
+
+function nextChangeNotificationPromise(aNewURL, testMessage) {
+ return new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint unused:false
+ Services.obs.removeObserver(observer, aTopic);
+ Assert.equal(aData, aNewURL, testMessage);
+ resolve();
+ }, "newtab-url-changed", false);
+ });
+}
diff --git a/browser/components/newtab/tests/xpcshell/test_NewTabPrefsProvider.js b/browser/components/newtab/tests/xpcshell/test_NewTabPrefsProvider.js
new file mode 100644
index 000000000..f364d0300
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/test_NewTabPrefsProvider.js
@@ -0,0 +1,50 @@
+"use strict";
+
+/* global XPCOMUtils, equal, Preferences, NewTabPrefsProvider, run_next_test */
+/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
+
+const Cu = Components.utils;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Preferences.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
+ "resource:///modules/NewTabPrefsProvider.jsm");
+
+function run_test() {
+ run_next_test();
+}
+
+add_task(function* test_observe() {
+ let prefsMap = NewTabPrefsProvider.prefs.prefsMap;
+ for (let prefName of prefsMap.keys()) {
+ let prefValueType = prefsMap.get(prefName);
+
+ let beforeVal;
+ let afterVal;
+
+ switch (prefValueType) {
+ case "bool":
+ beforeVal = false;
+ afterVal = true;
+ Preferences.set(prefName, beforeVal);
+ break;
+ case "localized":
+ case "str":
+ beforeVal = "";
+ afterVal = "someStr";
+ Preferences.set(prefName, beforeVal);
+ break;
+ }
+ NewTabPrefsProvider.prefs.init();
+ let promise = new Promise(resolve => {
+ NewTabPrefsProvider.prefs.once(prefName, (name, data) => { // jshint ignore:line
+ resolve([name, data]);
+ });
+ });
+ Preferences.set(prefName, afterVal);
+ let [actualName, actualData] = yield promise;
+ equal(prefName, actualName, `emitter sent the correct pref: ${prefName}`);
+ equal(afterVal, actualData, `emitter collected correct pref data for ${prefName}`);
+ NewTabPrefsProvider.prefs.uninit();
+ }
+});
diff --git a/browser/components/newtab/tests/xpcshell/test_NewTabSearchProvider.js b/browser/components/newtab/tests/xpcshell/test_NewTabSearchProvider.js
new file mode 100644
index 000000000..3e60b282a
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/test_NewTabSearchProvider.js
@@ -0,0 +1,82 @@
+"use strict";
+
+/* global XPCOMUtils, NewTabSearchProvider, run_next_test, ok, equal, do_check_true, do_get_profile, Services */
+/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
+
+const Cu = Components.utils;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabSearchProvider",
+ "resource:///modules/NewTabSearchProvider.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "ContentSearch",
+ "resource:///modules/ContentSearch.jsm");
+
+// ensure a profile exists
+do_get_profile();
+
+function run_test() {
+ run_next_test();
+}
+
+function hasProp(obj) {
+ return function(aProp) {
+ ok(obj.hasOwnProperty(aProp), `expect to have property ${aProp}`);
+ };
+}
+
+add_task(function* test_search() {
+ ContentSearch.init();
+ let observerPromise = new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ if (aData === "init-complete" && aTopic === "browser-search-service") {
+ Services.obs.removeObserver(observer, "browser-search-service");
+ resolve();
+ }
+ }, "browser-search-service", false);
+ });
+ Services.search.init();
+ yield observerPromise;
+ do_check_true(Services.search.isInitialized);
+
+ // get initial state of search and check it has correct properties
+ let state = yield NewTabSearchProvider.search.asyncGetState();
+ let stateProps = hasProp(state);
+ ["engines", "currentEngine"].forEach(stateProps);
+
+ // check that the current engine is correct and has correct properties
+ let {currentEngine} = state;
+ equal(currentEngine.name, Services.search.currentEngine.name, "Current engine has been correctly set");
+ var engineProps = hasProp(currentEngine);
+ ["name", "placeholder", "iconBuffer"].forEach(engineProps);
+
+ // create dummy test engines to test observer
+ Services.search.addEngineWithDetails("TestSearch1", "", "", "", "GET",
+ "http://example.com/?q={searchTerms}");
+ Services.search.addEngineWithDetails("TestSearch2", "", "", "", "GET",
+ "http://example.com/?q={searchTerms}");
+
+ // set one of the dummy test engines to the default engine
+ Services.search.defaultEngine = Services.search.getEngineByName("TestSearch1");
+
+ // test that the event emitter is working by setting a new current engine "TestSearch2"
+ let engineName = "TestSearch2";
+ NewTabSearchProvider.search.init();
+
+ // event emitter will fire when current engine is changed
+ let promise = new Promise(resolve => {
+ NewTabSearchProvider.search.once("browser-search-engine-modified", (name, data) => { // jshint ignore:line
+ resolve([name, data.name]);
+ });
+ });
+
+ // set a new current engine
+ Services.search.currentEngine = Services.search.getEngineByName(engineName);
+ let expectedEngineName = Services.search.currentEngine.name;
+
+ // emitter should fire and return the new engine
+ let [eventName, actualEngineName] = yield promise;
+ equal(eventName, "browser-search-engine-modified", `emitter sent the correct event ${eventName}`);
+ equal(expectedEngineName, actualEngineName, `emitter set the correct engine ${expectedEngineName}`);
+ NewTabSearchProvider.search.uninit();
+});
diff --git a/browser/components/newtab/tests/xpcshell/test_NewTabURL.js b/browser/components/newtab/tests/xpcshell/test_NewTabURL.js
new file mode 100644
index 000000000..1505e638c
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/test_NewTabURL.js
@@ -0,0 +1,52 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/
+ */
+
+/* globals Services, NewTabURL, XPCOMUtils, aboutNewTabService, NewTabPrefsProvider */
+"use strict";
+
+const {utils: Cu} = Components;
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+Cu.import("resource:///modules/NewTabURL.jsm");
+Cu.import("resource://gre/modules/Services.jsm");
+XPCOMUtils.defineLazyModuleGetter(this, "NewTabPrefsProvider",
+ "resource:///modules/NewTabPrefsProvider.jsm");
+XPCOMUtils.defineLazyServiceGetter(this, "aboutNewTabService",
+ "@mozilla.org/browser/aboutnewtab-service;1",
+ "nsIAboutNewTabService");
+
+add_task(function*() {
+ let defaultURL = aboutNewTabService.newTabURL;
+ Services.prefs.setBoolPref("browser.newtabpage.remote", false);
+
+ Assert.equal(NewTabURL.get(), defaultURL, `Default newtab URL should be ${defaultURL}`);
+ let url = "http://example.com/";
+ let notificationPromise = promiseNewtabURLNotification(url);
+ NewTabURL.override(url);
+ yield notificationPromise;
+ Assert.ok(NewTabURL.overridden, "Newtab URL should be overridden");
+ Assert.equal(NewTabURL.get(), url, "Newtab URL should be the custom URL");
+
+ notificationPromise = promiseNewtabURLNotification(defaultURL);
+ NewTabURL.reset();
+ yield notificationPromise;
+ Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
+ Assert.equal(NewTabURL.get(), defaultURL, "Newtab URL should be the default");
+
+ // change newtab page to remote
+ NewTabPrefsProvider.prefs.init();
+ Services.prefs.setBoolPref("browser.newtabpage.remote", true);
+ Assert.equal(NewTabURL.get(), "about:newtab", `Newtab URL should be about:newtab`);
+ Assert.ok(!NewTabURL.overridden, "Newtab URL should not be overridden");
+ NewTabPrefsProvider.prefs.uninit();
+});
+
+function promiseNewtabURLNotification(aNewURL) {
+ return new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) { // jshint ignore:line
+ Services.obs.removeObserver(observer, aTopic);
+ Assert.equal(aData, aNewURL, "Data for newtab-url-changed notification should be new URL.");
+ resolve();
+ }, "newtab-url-changed", false);
+ });
+}
diff --git a/browser/components/newtab/tests/xpcshell/test_PlacesProvider.js b/browser/components/newtab/tests/xpcshell/test_PlacesProvider.js
new file mode 100644
index 000000000..22815741b
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/test_PlacesProvider.js
@@ -0,0 +1,358 @@
+"use strict";
+
+/* global XPCOMUtils, PlacesUtils, PlacesTestUtils, PlacesProvider, NetUtil */
+/* global do_get_profile, run_next_test, add_task */
+/* global equal, ok */
+
+const {
+ utils: Cu,
+ interfaces: Ci,
+} = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesProvider",
+ "resource:///modules/PlacesProvider.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesUtils",
+ "resource://gre/modules/PlacesUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "PlacesTestUtils",
+ "resource://testing-common/PlacesTestUtils.jsm");
+
+XPCOMUtils.defineLazyModuleGetter(this, "NetUtil",
+ "resource://gre/modules/NetUtil.jsm");
+
+// ensure a profile exists
+do_get_profile();
+
+function run_test() {
+ PlacesProvider.links.init();
+ run_next_test();
+}
+
+// url prefix for test history population
+const TEST_URL = "https://mozilla.com/";
+// time when the test starts execution
+const TIME_NOW = (new Date()).getTime();
+
+// utility function to compute past timestap
+function timeDaysAgo(numDays) {
+ return TIME_NOW - (numDays * 24 * 60 * 60 * 1000);
+}
+
+// utility function to make a visit for insetion into places db
+function makeVisit(index, daysAgo, isTyped, domain=TEST_URL) {
+ let {
+ TRANSITION_TYPED,
+ TRANSITION_LINK
+ } = PlacesUtils.history;
+
+ return {
+ uri: NetUtil.newURI(`${domain}${index}`),
+ visitDate: timeDaysAgo(daysAgo),
+ transition: (isTyped) ? TRANSITION_TYPED : TRANSITION_LINK,
+ };
+}
+
+/** Test LinkChecker **/
+
+add_task(function test_LinkChecker_securityCheck() {
+
+ let urls = [
+ {url: "javascript:alert('hello')", expected: false}, // jshint ignore:line
+ {url: "data:image/png;base64,XXX", expected: false},
+ {url: "about:newtab", expected: true},
+ {url: "https://example.com", expected: true},
+ {url: "ftp://example.com", expected: true},
+ {url: "file://home/file/image.png", expected: true},
+ {url: "resource:///modules/PlacesProvider.jsm", expected: true},
+ ];
+ for (let {url, expected} of urls) {
+ let observed = PlacesProvider.LinkChecker.checkLoadURI(url);
+ equal(observed, expected, `can load "${url}"?`);
+ }
+});
+
+/** Test Provider **/
+
+add_task(function* test_Links_getLinks() {
+ yield PlacesTestUtils.clearHistory();
+ let provider = PlacesProvider.links;
+
+ let links = yield provider.getLinks();
+ equal(links.length, 0, "empty history yields empty links");
+
+ // add a visit
+ let testURI = NetUtil.newURI("http://mozilla.com");
+ yield PlacesTestUtils.addVisits(testURI);
+
+ links = yield provider.getLinks();
+ equal(links.length, 1, "adding a visit yields a link");
+ equal(links[0].url, testURI.spec, "added visit corresponds to added url");
+});
+
+add_task(function* test_Links_getLinks_Order() {
+ yield PlacesTestUtils.clearHistory();
+ let provider = PlacesProvider.links;
+
+ // all four visits must come from different domains to avoid deduplication
+ let visits = [
+ makeVisit(0, 0, true, "http://bar.com/"), // frecency 200, today
+ makeVisit(1, 0, true, "http://foo.com/"), // frecency 200, today
+ makeVisit(2, 2, true, "http://buz.com/"), // frecency 200, 2 days ago
+ makeVisit(3, 2, false, "http://aaa.com/"), // frecency 10, 2 days ago, transition
+ ];
+
+ let links = yield provider.getLinks();
+ equal(links.length, 0, "empty history yields empty links");
+ yield PlacesTestUtils.addVisits(visits);
+
+ links = yield provider.getLinks();
+ equal(links.length, visits.length, "number of links added is the same as obtain by getLinks");
+ for (let i = 0; i < links.length; i++) {
+ equal(links[i].url, visits[i].uri.spec, "links are obtained in the expected order");
+ }
+});
+
+add_task(function* test_Links_getLinks_Deduplication() {
+ yield PlacesTestUtils.clearHistory();
+ let provider = PlacesProvider.links;
+
+ // all for visits must come from different domains to avoid deduplication
+ let visits = [
+ makeVisit(0, 2, true, "http://bar.com/"), // frecency 200, 2 days ago
+ makeVisit(1, 0, true, "http://bar.com/"), // frecency 200, today
+ makeVisit(2, 0, false, "http://foo.com/"), // frecency 10, today
+ makeVisit(3, 0, true, "http://foo.com/"), // frecency 200, today
+ ];
+
+ let links = yield provider.getLinks();
+ equal(links.length, 0, "empty history yields empty links");
+ yield PlacesTestUtils.addVisits(visits);
+
+ links = yield provider.getLinks();
+ equal(links.length, 2, "only two links must be left after deduplication");
+ equal(links[0].url, visits[1].uri.spec, "earliest link is present");
+ equal(links[1].url, visits[3].uri.spec, "most fresent link is present");
+});
+
+add_task(function* test_Links_onLinkChanged() {
+ let provider = PlacesProvider.links;
+
+ let url = "https://example.com/onFrecencyChanged1";
+ let linkChangedMsgCount = 0;
+
+ let linkChangedPromise = new Promise(resolve => {
+ let handler = (_, link) => { // jshint ignore:line
+ /* There are 3 linkChanged events:
+ * 1. visit insertion (-1 frecency by default)
+ * 2. frecency score update (after transition type calculation etc)
+ * 3. title change
+ */
+ if (link.url === url) {
+ equal(link.url, url, `expected url on linkChanged event`);
+ linkChangedMsgCount += 1;
+ if (linkChangedMsgCount === 3) {
+ ok(true, `all linkChanged events captured`);
+ provider.off("linkChanged", this);
+ resolve();
+ }
+ }
+ };
+ provider.on("linkChanged", handler);
+ });
+
+ // add a visit
+ let testURI = NetUtil.newURI(url);
+ yield PlacesTestUtils.addVisits(testURI);
+ yield linkChangedPromise;
+
+ yield PlacesTestUtils.clearHistory();
+});
+
+add_task(function* test_Links_onClearHistory() {
+ let provider = PlacesProvider.links;
+
+ let clearHistoryPromise = new Promise(resolve => {
+ let handler = () => {
+ ok(true, `clearHistory event captured`);
+ provider.off("clearHistory", handler);
+ resolve();
+ };
+ provider.on("clearHistory", handler);
+ });
+
+ // add visits
+ for (let i = 0; i <= 10; i++) {
+ let url = `https://example.com/onClearHistory${i}`;
+ let testURI = NetUtil.newURI(url);
+ yield PlacesTestUtils.addVisits(testURI);
+ }
+ yield PlacesTestUtils.clearHistory();
+ yield clearHistoryPromise;
+});
+
+add_task(function* test_Links_onDeleteURI() {
+ let provider = PlacesProvider.links;
+
+ let testURL = "https://example.com/toDelete";
+
+ let deleteURIPromise = new Promise(resolve => {
+ let handler = (_, {url}) => { // jshint ignore:line
+ equal(testURL, url, "deleted url and expected url are the same");
+ provider.off("deleteURI", handler);
+ resolve();
+ };
+
+ provider.on("deleteURI", handler);
+ });
+
+ let testURI = NetUtil.newURI(testURL);
+ yield PlacesTestUtils.addVisits(testURI);
+ yield PlacesUtils.history.remove(testURL);
+ yield deleteURIPromise;
+});
+
+add_task(function* test_Links_onManyLinksChanged() {
+ let provider = PlacesProvider.links;
+
+ let promise = new Promise(resolve => {
+ let handler = () => {
+ ok(true);
+ provider.off("manyLinksChanged", handler);
+ resolve();
+ };
+
+ provider.on("manyLinksChanged", handler);
+ });
+
+ let testURL = "https://example.com/toDelete";
+ let testURI = NetUtil.newURI(testURL);
+ yield PlacesTestUtils.addVisits(testURI);
+
+ // trigger DecayFrecency
+ PlacesUtils.history.QueryInterface(Ci.nsIObserver).
+ observe(null, "idle-daily", "");
+
+ yield promise;
+});
+
+add_task(function* test_Links_execute_query() {
+ yield PlacesTestUtils.clearHistory();
+ let provider = PlacesProvider.links;
+
+ let visits = [
+ makeVisit(0, 0, true), // frecency 200, today
+ makeVisit(1, 0, true), // frecency 200, today
+ makeVisit(2, 2, true), // frecency 200, 2 days ago
+ makeVisit(3, 2, false), // frecency 10, 2 days ago, transition
+ ];
+
+ yield PlacesTestUtils.addVisits(visits);
+
+ function testItemValue(results, index, value) {
+ equal(results[index][0], `${TEST_URL}${value}`, "raw url");
+ equal(results[index][1], `test visit for ${TEST_URL}${value}`, "raw title");
+ }
+
+ function testItemObject(results, index, columnValues) {
+ Object.keys(columnValues).forEach(name => {
+ equal(results[index][name], columnValues[name], "object name " + name);
+ });
+ }
+
+ // select all 4 records
+ let results = yield provider.executePlacesQuery("select url, title from moz_places");
+ equal(results.length, 4, "expect 4 items");
+ // check for insert order sequence
+ for (let i = 0; i < results.length; i++) {
+ testItemValue(results, i, i);
+ }
+
+ // test parameter passing
+ results = yield provider.executePlacesQuery(
+ "select url, title from moz_places limit :limit",
+ {params: {limit: 2}}
+ );
+ equal(results.length, 2, "expect 2 items");
+ for (let i = 0; i < results.length; i++) {
+ testItemValue(results, i, i);
+ }
+
+ // test extracting items by name
+ results = yield provider.executePlacesQuery(
+ "select url, title from moz_places limit :limit",
+ {columns: ["url", "title"], params: {limit: 4}}
+ );
+ equal(results.length, 4, "expect 4 items");
+ for (let i = 0; i < results.length; i++) {
+ testItemObject(results, i, {
+ "url": `${TEST_URL}${i}`,
+ "title": `test visit for ${TEST_URL}${i}`,
+ });
+ }
+
+ // test ordering
+ results = yield provider.executePlacesQuery(
+ "select url, title, last_visit_date, frecency from moz_places " +
+ "order by frecency DESC, last_visit_date DESC, url DESC limit :limit",
+ {columns: ["url", "title", "last_visit_date", "frecency"], params: {limit: 4}}
+ );
+ equal(results.length, 4, "expect 4 items");
+ testItemObject(results, 0, {url: `${TEST_URL}1`});
+ testItemObject(results, 1, {url: `${TEST_URL}0`});
+ testItemObject(results, 2, {url: `${TEST_URL}2`});
+ testItemObject(results, 3, {url: `${TEST_URL}3`});
+
+ // test callback passing
+ results = [];
+ function handleRow(aRow) {
+ results.push({
+ url: aRow.getResultByName("url"),
+ title: aRow.getResultByName("title"),
+ last_visit_date: aRow.getResultByName("last_visit_date"),
+ frecency: aRow.getResultByName("frecency")
+ });
+ }
+ yield provider.executePlacesQuery(
+ "select url, title, last_visit_date, frecency from moz_places " +
+ "order by frecency DESC, last_visit_date DESC, url DESC",
+ {callback: handleRow}
+ );
+ equal(results.length, 4, "expect 4 items");
+ testItemObject(results, 0, {url: `${TEST_URL}1`});
+ testItemObject(results, 1, {url: `${TEST_URL}0`});
+ testItemObject(results, 2, {url: `${TEST_URL}2`});
+ testItemObject(results, 3, {url: `${TEST_URL}3`});
+
+ // negative test cases
+ // bad sql
+ try {
+ yield provider.executePlacesQuery("select from moz");
+ do_throw("bad sql should've thrown");
+ }
+ catch (e) {
+ do_check_true("expected failure - bad sql");
+ }
+ // missing bindings
+ try {
+ yield provider.executePlacesQuery("select * from moz_places limit :limit");
+ do_throw("bad sql should've thrown");
+ }
+ catch (e) {
+ do_check_true("expected failure - missing bidning");
+ }
+ // non-existent column name
+ try {
+ yield provider.executePlacesQuery("select * from moz_places limit :limit",
+ {columns: ["no-such-column"], params: {limit: 4}});
+ do_throw("bad sql should've thrown");
+ }
+ catch (e) {
+ do_check_true("expected failure - wrong column name");
+ }
+
+ // cleanup
+ yield PlacesTestUtils.clearHistory();
+});
diff --git a/browser/components/newtab/tests/xpcshell/xpcshell.ini b/browser/components/newtab/tests/xpcshell/xpcshell.ini
new file mode 100644
index 000000000..c249ee3e2
--- /dev/null
+++ b/browser/components/newtab/tests/xpcshell/xpcshell.ini
@@ -0,0 +1,11 @@
+[DEFAULT]
+head =
+tail =
+firefox-appdir = browser
+skip-if = toolkit == 'android'
+
+[test_AboutNewTabService.js]
+[test_NewTabPrefsProvider.js]
+[test_NewTabSearchProvider.js]
+[test_NewTabURL.js]
+[test_PlacesProvider.js]