diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /browser/components/newtab/tests/xpcshell | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-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')
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] |