summaryrefslogtreecommitdiffstats
path: root/browser/components/newtab/test/browser/head.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/newtab/test/browser/head.js')
-rw-r--r--browser/components/newtab/test/browser/head.js244
1 files changed, 244 insertions, 0 deletions
diff --git a/browser/components/newtab/test/browser/head.js b/browser/components/newtab/test/browser/head.js
new file mode 100644
index 0000000000..1dbae8af02
--- /dev/null
+++ b/browser/components/newtab/test/browser/head.js
@@ -0,0 +1,244 @@
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ ASRouter: "resource:///modules/asrouter/ASRouter.sys.mjs",
+
+ DiscoveryStreamFeed:
+ "resource://activity-stream/lib/DiscoveryStreamFeed.sys.mjs",
+
+ FeatureCallout: "resource:///modules/asrouter/FeatureCallout.sys.mjs",
+
+ FeatureCalloutBroker:
+ "resource:///modules/asrouter/FeatureCalloutBroker.sys.mjs",
+
+ FeatureCalloutMessages:
+ "resource:///modules/asrouter/FeatureCalloutMessages.sys.mjs",
+
+ ObjectUtils: "resource://gre/modules/ObjectUtils.sys.mjs",
+ PlacesTestUtils: "resource://testing-common/PlacesTestUtils.sys.mjs",
+ QueryCache: "resource:///modules/asrouter/ASRouterTargeting.sys.mjs",
+});
+
+// We import sinon here to make it available across all mochitest test files
+const { sinon } = ChromeUtils.importESModule(
+ "resource://testing-common/Sinon.sys.mjs"
+);
+
+function popPrefs() {
+ return SpecialPowers.popPrefEnv();
+}
+function pushPrefs(...prefs) {
+ return SpecialPowers.pushPrefEnv({ set: prefs });
+}
+
+// Toggle the feed off and on as a workaround to read the new prefs.
+async function toggleTopsitesPref() {
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.feeds.system.topsites",
+ false,
+ ]);
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.feeds.system.topsites",
+ true,
+ ]);
+}
+
+async function setDefaultTopSites() {
+ // The pref for TopSites is empty by default.
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.default.sites",
+ "https://www.youtube.com/,https://www.facebook.com/,https://www.amazon.com/,https://www.reddit.com/,https://www.wikipedia.org/,https://twitter.com/",
+ ]);
+ await toggleTopsitesPref();
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
+ true,
+ ]);
+}
+
+async function setTestTopSites() {
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.improvesearch.topSiteSearchShortcuts",
+ false,
+ ]);
+ // The pref for TopSites is empty by default.
+ // Using a topsite with example.com allows us to open the topsite without a network request.
+ await pushPrefs([
+ "browser.newtabpage.activity-stream.default.sites",
+ "https://example.com/",
+ ]);
+ await toggleTopsitesPref();
+}
+
+async function clearHistoryAndBookmarks() {
+ await PlacesUtils.bookmarks.eraseEverything();
+ await PlacesUtils.history.clear();
+ QueryCache.expireAll();
+}
+
+/**
+ * Helper to wait for potentially preloaded browsers to "load" where a preloaded
+ * page has already loaded and won't trigger "load", and a "load"ed page might
+ * not necessarily have had all its javascript/render logic executed.
+ */
+async function waitForPreloaded(browser) {
+ let readyState = await ContentTask.spawn(
+ browser,
+ null,
+ () => content.document.readyState
+ );
+ if (readyState !== "complete") {
+ await BrowserTestUtils.browserLoaded(browser);
+ }
+}
+
+/**
+ * Helper to force the HighlightsFeed to update.
+ */
+function refreshHighlightsFeed() {
+ // Toggling the pref will clear the feed cache and force a places query.
+ Services.prefs.setBoolPref(
+ "browser.newtabpage.activity-stream.feeds.section.highlights",
+ false
+ );
+ Services.prefs.setBoolPref(
+ "browser.newtabpage.activity-stream.feeds.section.highlights",
+ true
+ );
+}
+
+/**
+ * Helper to populate the Highlights section with bookmark cards.
+ * @param count Number of items to add.
+ */
+async function addHighlightsBookmarks(count) {
+ const bookmarks = new Array(count).fill(null).map((entry, i) => ({
+ parentGuid: PlacesUtils.bookmarks.unfiledGuid,
+ title: "foo",
+ url: `https://mozilla${i}.com/nowNew`,
+ }));
+
+ for (let placeInfo of bookmarks) {
+ await PlacesUtils.bookmarks.insert(placeInfo);
+ // Bookmarks need at least one visit to show up as highlights.
+ await PlacesTestUtils.addVisits(placeInfo.url);
+ }
+
+ // Force HighlightsFeed to make a request for the new items.
+ refreshHighlightsFeed();
+}
+
+/**
+ * Helper to add various helpers to the content process by injecting variables
+ * and functions to the `content` global.
+ */
+function addContentHelpers() {
+ const { document } = content;
+ Object.assign(content, {
+ /**
+ * Click the context menu button for an item and get its options list.
+ *
+ * @param selector {String} Selector to get an item (e.g., top site, card)
+ * @return {Array} The nodes for the options.
+ */
+ async openContextMenuAndGetOptions(selector) {
+ const item = document.querySelector(selector);
+ const contextButton = item.querySelector(".context-menu-button");
+ contextButton.click();
+ // Gives fluent-dom the time to render strings
+ await new Promise(r => content.requestAnimationFrame(r));
+
+ const contextMenu = item.querySelector(".context-menu");
+ const contextMenuList = contextMenu.querySelector(".context-menu-list");
+ return [...contextMenuList.getElementsByClassName("context-menu-item")];
+ },
+ });
+}
+
+/**
+ * Helper to run Activity Stream about:newtab test tasks in content.
+ *
+ * @param testInfo {Function|Object}
+ * {Function} This parameter will be used as if the function were called with
+ * an Object with this parameter as "test" key's value.
+ * {Object} The following keys are expected:
+ * before {Function} Optional. Runs before and returns an arg for "test"
+ * test {Function} The test to run in the about:newtab content task taking
+ * an arg from "before" and returns a result to "after"
+ * after {Function} Optional. Runs after and with the result of "test"
+ * @param browserURL {optional String}
+ * {String} This parameter is used to explicitly specify URL opened in new tab
+ */
+function test_newtab(testInfo, browserURL = "about:newtab") {
+ // Extract any test parts or default to just the single content task
+ let { before, test: contentTask, after } = testInfo;
+ if (!before) {
+ before = () => ({});
+ }
+ if (!contentTask) {
+ contentTask = testInfo;
+ }
+ if (!after) {
+ after = () => {};
+ }
+
+ // Helper to push prefs for just this test and pop them when done
+ let needPopPrefs = false;
+ let scopedPushPrefs = async (...args) => {
+ needPopPrefs = true;
+ await pushPrefs(...args);
+ };
+ let scopedPopPrefs = async () => {
+ if (needPopPrefs) {
+ await popPrefs();
+ }
+ };
+
+ // Make the test task with optional before/after and content task to run in a
+ // new tab that opens and closes.
+ let testTask = async () => {
+ // Open about:newtab without using the default load listener
+ let tab = await BrowserTestUtils.openNewForegroundTab(
+ gBrowser,
+ browserURL,
+ false
+ );
+
+ // Specially wait for potentially preloaded browsers
+ let browser = tab.linkedBrowser;
+ await waitForPreloaded(browser);
+
+ // Add shared helpers to the content process
+ SpecialPowers.spawn(browser, [], addContentHelpers);
+
+ // Wait for React to render something
+ await BrowserTestUtils.waitForCondition(
+ () =>
+ SpecialPowers.spawn(
+ browser,
+ [],
+ () => content.document.getElementById("root").children.length
+ ),
+ "Should render activity stream content"
+ );
+
+ // Chain together before -> contentTask -> after data passing
+ try {
+ let contentArg = await before({ pushPrefs: scopedPushPrefs, tab });
+ let contentResult = await SpecialPowers.spawn(
+ browser,
+ [contentArg],
+ contentTask
+ );
+ await after(contentResult);
+ } finally {
+ // Clean up for next tests
+ BrowserTestUtils.removeTab(tab);
+ await scopedPopPrefs();
+ }
+ };
+
+ // Copy the name of the content task to identify the test
+ Object.defineProperty(testTask, "name", { value: contentTask.name });
+ add_task(testTask);
+}