summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/browser-tips/head.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /browser/components/urlbar/tests/browser-tips/head.js
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--browser/components/urlbar/tests/browser-tips/head.js771
1 files changed, 771 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/browser-tips/head.js b/browser/components/urlbar/tests/browser-tips/head.js
new file mode 100644
index 0000000000..d6797f5338
--- /dev/null
+++ b/browser/components/urlbar/tests/browser-tips/head.js
@@ -0,0 +1,771 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// This directory contains tests that check tips and interventions, and in
+// particular the update-related interventions.
+// We mock updates by using the test helpers in
+// toolkit/mozapps/update/tests/browser.
+
+"use strict";
+
+Services.scriptloader.loadSubScript(
+ "chrome://mochitests/content/browser/toolkit/mozapps/update/tests/browser/head.js",
+ this
+);
+
+ChromeUtils.defineESModuleGetters(this, {
+ ResetProfile: "resource://gre/modules/ResetProfile.sys.mjs",
+ TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs",
+ UrlbarProviderInterventions:
+ "resource:///modules/UrlbarProviderInterventions.sys.mjs",
+ UrlbarProvidersManager: "resource:///modules/UrlbarProvidersManager.sys.mjs",
+ UrlbarResult: "resource:///modules/UrlbarResult.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ HttpServer: "resource://testing-common/httpd.js",
+});
+
+XPCOMUtils.defineLazyGetter(this, "UrlbarTestUtils", () => {
+ const { UrlbarTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/UrlbarTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+XPCOMUtils.defineLazyGetter(this, "SearchTestUtils", () => {
+ const { SearchTestUtils: module } = ChromeUtils.importESModule(
+ "resource://testing-common/SearchTestUtils.sys.mjs"
+ );
+ module.init(this);
+ return module;
+});
+
+// For each intervention type, a search string that trigger the intervention.
+const SEARCH_STRINGS = {
+ CLEAR: "firefox history",
+ REFRESH: "firefox slow",
+ UPDATE: "firefox update",
+};
+
+registerCleanupFunction(() => {
+ // We need to reset the provider's appUpdater.status between tests so that
+ // each test doesn't interfere with the next.
+ UrlbarProviderInterventions.resetAppUpdater();
+});
+
+/**
+ * Override our binary path so that the update lock doesn't think more than one
+ * instance of this test is running.
+ * This is a heavily pared down copy of the function in xpcshellUtilsAUS.js.
+ */
+function adjustGeneralPaths() {
+ let dirProvider = {
+ getFile(aProp, aPersistent) {
+ // Set the value of persistent to false so when this directory provider is
+ // unregistered it will revert back to the original provider.
+ aPersistent.value = false;
+ // The sync manager only uses XRE_EXECUTABLE_FILE, so that's all we need
+ // to override, we won't bother handling anything else.
+ if (aProp == XRE_EXECUTABLE_FILE) {
+ // The temp directory that the mochitest runner creates is unique per
+ // test, so its path can serve to provide the unique key that the update
+ // sync manager requires (it doesn't need for this to be the actual
+ // path to any real file, it's only used as an opaque string).
+ let tempPath = Services.env.get("MOZ_PROCESS_LOG");
+ let file = Cc["@mozilla.org/file/local;1"].createInstance(Ci.nsIFile);
+ file.initWithPath(tempPath);
+ return file;
+ }
+ return null;
+ },
+ QueryInterface: ChromeUtils.generateQI(["nsIDirectoryServiceProvider"]),
+ };
+
+ let ds = Services.dirsvc.QueryInterface(Ci.nsIDirectoryService);
+ try {
+ ds.QueryInterface(Ci.nsIProperties).undefine(XRE_EXECUTABLE_FILE);
+ } catch (_ex) {
+ // We only override one property, so we have nothing to do if that fails.
+ return;
+ }
+ ds.registerProvider(dirProvider);
+ registerCleanupFunction(() => {
+ ds.unregisterProvider(dirProvider);
+ // Reset the update lock once again so that we know the lock we're
+ // interested in here will be closed properly (normally that happens during
+ // XPCOM shutdown, but that isn't consistent during tests).
+ let syncManager = Cc[
+ "@mozilla.org/updates/update-sync-manager;1"
+ ].getService(Ci.nsIUpdateSyncManager);
+ syncManager.resetLock();
+ });
+
+ // Now that we've overridden the directory provider, the name of the update
+ // lock needs to be changed to match the overridden path.
+ let syncManager = Cc["@mozilla.org/updates/update-sync-manager;1"].getService(
+ Ci.nsIUpdateSyncManager
+ );
+ syncManager.resetLock();
+}
+
+/**
+ * Initializes a mock app update. Adapted from runAboutDialogUpdateTest:
+ * https://searchfox.org/mozilla-central/source/toolkit/mozapps/update/tests/browser/head.js
+ *
+ * @param {object} params
+ * See the files in toolkit/mozapps/update/tests/browser.
+ */
+async function initUpdate(params) {
+ Services.env.set("MOZ_TEST_SLOW_SKIP_UPDATE_STAGE", "1");
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [PREF_APP_UPDATE_DISABLEDFORTESTING, false],
+ [PREF_APP_UPDATE_URL_MANUAL, gDetailsURL],
+ ],
+ });
+
+ adjustGeneralPaths();
+ await setupTestUpdater();
+
+ let queryString = params.queryString ? params.queryString : "";
+ let updateURL =
+ URL_HTTP_UPDATE_SJS +
+ "?detailsURL=" +
+ gDetailsURL +
+ queryString +
+ getVersionParams();
+ if (params.backgroundUpdate) {
+ setUpdateURL(updateURL);
+ gAUS.checkForBackgroundUpdates();
+ if (params.continueFile) {
+ await continueFileHandler(params.continueFile);
+ }
+ if (params.waitForUpdateState) {
+ let whichUpdate =
+ params.waitForUpdateState == STATE_DOWNLOADING
+ ? "downloadingUpdate"
+ : "readyUpdate";
+ await TestUtils.waitForCondition(
+ () =>
+ gUpdateManager[whichUpdate] &&
+ gUpdateManager[whichUpdate].state == params.waitForUpdateState,
+ "Waiting for update state: " + params.waitForUpdateState,
+ undefined,
+ 200
+ ).catch(e => {
+ // Instead of throwing let the check below fail the test so the panel
+ // ID and the expected panel ID is printed in the log.
+ logTestInfo(e);
+ });
+ // Display the UI after the update state equals the expected value.
+ Assert.equal(
+ gUpdateManager[whichUpdate].state,
+ params.waitForUpdateState,
+ "The update state value should equal " + params.waitForUpdateState
+ );
+ }
+ } else {
+ updateURL += "&slowUpdateCheck=1&useSlowDownloadMar=1";
+ setUpdateURL(updateURL);
+ }
+}
+
+/**
+ * Performs steps in a mock update. Adapted from runAboutDialogUpdateTest:
+ * https://searchfox.org/mozilla-central/source/toolkit/mozapps/update/tests/browser/head.js
+ *
+ * @param {Array} steps
+ * See the files in toolkit/mozapps/update/tests/browser.
+ */
+async function processUpdateSteps(steps) {
+ for (let step of steps) {
+ await processUpdateStep(step);
+ }
+}
+
+/**
+ * Performs a step in a mock update. Adapted from runAboutDialogUpdateTest:
+ * https://searchfox.org/mozilla-central/source/toolkit/mozapps/update/tests/browser/head.js
+ *
+ * @param {object} step
+ * See the files in toolkit/mozapps/update/tests/browser.
+ */
+async function processUpdateStep(step) {
+ if (typeof step == "function") {
+ step();
+ return;
+ }
+
+ const { panelId, checkActiveUpdate, continueFile, downloadInfo } = step;
+
+ if (
+ panelId == "downloading" &&
+ gAUS.currentState == Ci.nsIApplicationUpdateService.STATE_IDLE
+ ) {
+ // Now that `AUS.downloadUpdate` is async, we start showing the
+ // downloading panel while `AUS.downloadUpdate` is still resolving.
+ // But the below checks assume that this resolution has already
+ // happened. So we need to wait for things to actually resolve.
+ await gAUS.stateTransition;
+ }
+
+ if (checkActiveUpdate) {
+ let whichUpdate =
+ checkActiveUpdate.state == STATE_DOWNLOADING
+ ? "downloadingUpdate"
+ : "readyUpdate";
+ await TestUtils.waitForCondition(
+ () => gUpdateManager[whichUpdate],
+ "Waiting for active update"
+ );
+ Assert.ok(
+ !!gUpdateManager[whichUpdate],
+ "There should be an active update"
+ );
+ Assert.equal(
+ gUpdateManager[whichUpdate].state,
+ checkActiveUpdate.state,
+ "The active update state should equal " + checkActiveUpdate.state
+ );
+ } else {
+ Assert.ok(
+ !gUpdateManager.readyUpdate,
+ "There should not be a ready update"
+ );
+ Assert.ok(
+ !gUpdateManager.downloadingUpdate,
+ "There should not be a downloadingUpdate update"
+ );
+ }
+
+ if (panelId == "downloading") {
+ for (let i = 0; i < downloadInfo.length; ++i) {
+ let data = downloadInfo[i];
+ // The About Dialog tests always specify a continue file.
+ await continueFileHandler(continueFile);
+ let patch = getPatchOfType(
+ data.patchType,
+ gUpdateManager.downloadingUpdate
+ );
+ // The update is removed early when the last download fails so check
+ // that there is a patch before proceeding.
+ let isLastPatch = i == downloadInfo.length - 1;
+ if (!isLastPatch || patch) {
+ let resultName = data.bitsResult ? "bitsResult" : "internalResult";
+ patch.QueryInterface(Ci.nsIWritablePropertyBag);
+ await TestUtils.waitForCondition(
+ () => patch.getProperty(resultName) == data[resultName],
+ "Waiting for expected patch property " +
+ resultName +
+ " value: " +
+ data[resultName],
+ undefined,
+ 200
+ ).catch(e => {
+ // Instead of throwing let the check below fail the test so the
+ // property value and the expected property value is printed in
+ // the log.
+ logTestInfo(e);
+ });
+ Assert.equal(
+ patch.getProperty(resultName),
+ data[resultName],
+ "The patch property " +
+ resultName +
+ " value should equal " +
+ data[resultName]
+ );
+ }
+ }
+ } else if (continueFile) {
+ await continueFileHandler(continueFile);
+ }
+}
+
+/**
+ * Checks an intervention tip. This works by starting a search that should
+ * trigger a tip, picks the tip, and waits for the tip's action to happen.
+ *
+ * @param {object} options
+ * Options for the test
+ * @param {string} options.searchString
+ * The search string.
+ * @param {string} options.tip
+ * The expected tip type.
+ * @param {string | RegExp} options.title
+ * The expected tip title.
+ * @param {string | RegExp} options.button
+ * The expected button title.
+ * @param {Function} options.awaitCallback
+ * A function that checks the tip's action. Should return a promise (or be
+ * async).
+ * @returns {object}
+ * The value returned from `awaitCallback`.
+ */
+async function doUpdateTest({
+ searchString,
+ tip,
+ title,
+ button,
+ awaitCallback,
+} = {}) {
+ // Do a search that triggers the tip.
+ let [result, element] = await awaitTip(searchString);
+ Assert.strictEqual(result.payload.type, tip, "Tip type");
+ await element.ownerDocument.l10n.translateFragment(element);
+
+ let actualTitle = element._elements.get("title").textContent;
+ if (typeof title == "string") {
+ Assert.equal(actualTitle, title, "Title string");
+ } else {
+ // regexp
+ Assert.ok(title.test(actualTitle), "Title regexp");
+ }
+
+ let actualButton = element._buttons.get("0").textContent;
+ if (typeof button == "string") {
+ Assert.equal(actualButton, button, "Button string");
+ } else {
+ // regexp
+ Assert.ok(button.test(actualButton), "Button regexp");
+ }
+
+ if (UrlbarPrefs.get("resultMenu")) {
+ Assert.ok(element._buttons.has("menu"), "Tip has a menu button");
+ } else {
+ Assert.ok(element._buttons.has("help"), "Tip has a help button");
+ }
+
+ // Pick the tip and wait for the action.
+ let values = await Promise.all([awaitCallback(), pickTip()]);
+
+ // Check telemetry.
+ const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "urlbar.tips",
+ `${tip}-shown`,
+ 1
+ );
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "urlbar.tips",
+ `${tip}-picked`,
+ 1
+ );
+
+ return values[0] || null;
+}
+
+/**
+ * Starts a search and asserts that the second result is a tip.
+ *
+ * @param {string} searchString
+ * The search string.
+ * @param {window} win
+ * The window.
+ * @returns {(result| element)[]}
+ * The result and its element in the DOM.
+ */
+async function awaitTip(searchString, win = window) {
+ let context = await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window: win,
+ value: searchString,
+ waitForFocus,
+ fireInputEvent: true,
+ });
+ Assert.ok(context.results.length >= 2);
+ let result = context.results[1];
+ Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.TIP);
+ let element = await UrlbarTestUtils.waitForAutocompleteResultAt(win, 1);
+ return [result, element];
+}
+
+/**
+ * Picks the current tip's button. The view should be open and the second
+ * result should be a tip.
+ */
+async function pickTip() {
+ let result = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
+ let button = result.element.row._buttons.get("0");
+ await UrlbarTestUtils.promisePopupClose(window, () => {
+ EventUtils.synthesizeMouseAtCenter(button, {});
+ });
+}
+
+/**
+ * Waits for the quit-application-requested notification and cancels it (so that
+ * the app isn't actually restarted).
+ */
+async function awaitAppRestartRequest() {
+ await TestUtils.topicObserved(
+ "quit-application-requested",
+ (cancelQuit, data) => {
+ if (data == "restart") {
+ cancelQuit.QueryInterface(Ci.nsISupportsPRBool).data = true;
+ return true;
+ }
+ return false;
+ }
+ );
+}
+
+/**
+ * Sets up the profile so that it can be reset.
+ */
+function makeProfileResettable() {
+ // Make reset possible.
+ let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].getService(
+ Ci.nsIToolkitProfileService
+ );
+ let currentProfileDir = Services.dirsvc.get("ProfD", Ci.nsIFile);
+ let profileName = "mochitest-test-profile-temp-" + Date.now();
+ let tempProfile = profileService.createProfile(
+ currentProfileDir,
+ profileName
+ );
+ Assert.ok(
+ ResetProfile.resetSupported(),
+ "Should be able to reset from mochitest's temporary profile once it's in the profile manager."
+ );
+
+ registerCleanupFunction(() => {
+ tempProfile.remove(false);
+ Assert.ok(
+ !ResetProfile.resetSupported(),
+ "Shouldn't be able to reset from mochitest's temporary profile once removed from the profile manager."
+ );
+ });
+}
+
+/**
+ * Starts a search that should trigger a tip, picks the tip, and waits for the
+ * tip's action to happen.
+ *
+ * @param {object} options
+ * Options for the test
+ * @param {string} options.searchString
+ * The search string.
+ * @param {TIPS} options.tip
+ * The expected tip type.
+ * @param {string} options.title
+ * The expected tip title.
+ * @param {string} options.button
+ * The expected button title.
+ * @param {Function} options.awaitCallback
+ * A function that checks the tip's action. Should return a promise (or be
+ * async).
+ * @returns {*}
+ * The value returned from `awaitCallback`.
+ */
+function checkIntervention({
+ searchString,
+ tip,
+ title,
+ button,
+ awaitCallback,
+} = {}) {
+ // Opening modal dialogs confuses focus on Linux just after them, thus run
+ // these checks in separate tabs to better isolate them.
+ return BrowserTestUtils.withNewTab("about:blank", async () => {
+ // Do a search that triggers the tip.
+ let [result, element] = await awaitTip(searchString);
+ Assert.strictEqual(result.payload.type, tip);
+ await element.ownerDocument.l10n.translateFragment(element);
+
+ let actualTitle = element._elements.get("title").textContent;
+ if (typeof title == "string") {
+ Assert.equal(actualTitle, title, "Title string");
+ } else {
+ // regexp
+ Assert.ok(title.test(actualTitle), "Title regexp");
+ }
+
+ let actualButton = element._buttons.get("0").textContent;
+ if (typeof button == "string") {
+ Assert.equal(actualButton, button, "Button string");
+ } else {
+ // regexp
+ Assert.ok(button.test(actualButton), "Button regexp");
+ }
+
+ if (UrlbarPrefs.get("resultMenu")) {
+ let menuButton = element._buttons.get("menu");
+ Assert.ok(menuButton, "Menu button exists");
+ Assert.ok(
+ BrowserTestUtils.is_visible(menuButton),
+ "Menu button is visible"
+ );
+ } else {
+ let helpButton = element._buttons.get("help");
+ Assert.ok(helpButton, "Help button exists");
+ Assert.ok(
+ BrowserTestUtils.is_visible(helpButton),
+ "Help button is visible"
+ );
+ }
+
+ let values = await Promise.all([awaitCallback(), pickTip()]);
+ Assert.ok(true, "Refresh dialog opened");
+
+ // Ensure the urlbar is closed so that the engagement is ended.
+ await UrlbarTestUtils.promisePopupClose(window, () => gURLBar.blur());
+
+ const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "urlbar.tips",
+ `${tip}-shown`,
+ 1
+ );
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "urlbar.tips",
+ `${tip}-picked`,
+ 1
+ );
+
+ return values[0] || null;
+ });
+}
+
+/**
+ * Starts a search and asserts that there are no tips.
+ *
+ * @param {string} searchString
+ * The search string.
+ * @param {Window} win
+ * The host window.
+ */
+async function awaitNoTip(searchString, win = window) {
+ let context = await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window: win,
+ value: searchString,
+ waitForFocus,
+ fireInputEvent: true,
+ });
+ for (let result of context.results) {
+ Assert.notEqual(result.type, UrlbarUtils.RESULT_TYPE.TIP);
+ }
+}
+
+/**
+ * Search tips helper. Asserts that a particular search tip is shown or that no
+ * search tip is shown.
+ *
+ * @param {window} win
+ * A browser window.
+ * @param {UrlbarProviderSearchTips.TIP_TYPE} expectedTip
+ * The expected search tip. Pass a falsey value (like zero) for none.
+ * @param {boolean} closeView
+ * If true, this function closes the urlbar view before returning.
+ */
+async function checkTip(win, expectedTip, closeView = true) {
+ if (!expectedTip) {
+ // Wait a bit for the tip to not show up.
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ await new Promise(resolve => setTimeout(resolve, 100));
+ Assert.ok(!win.gURLBar.view.isOpen);
+ return;
+ }
+
+ // Wait for the view to open, and then check the tip result.
+ await UrlbarTestUtils.promisePopupOpen(win, () => {});
+ Assert.ok(true, "View opened");
+ Assert.equal(UrlbarTestUtils.getResultCount(win), 1);
+ let result = await UrlbarTestUtils.getDetailsOfResultAt(win, 0);
+ Assert.equal(result.type, UrlbarUtils.RESULT_TYPE.TIP);
+ let heuristic;
+ let title;
+ let name = Services.search.defaultEngine.name;
+ switch (expectedTip) {
+ case UrlbarProviderSearchTips.TIP_TYPE.ONBOARD:
+ heuristic = true;
+ title =
+ `Type less, find more: Search ${name} right from your ` +
+ `address bar.`;
+ break;
+ case UrlbarProviderSearchTips.TIP_TYPE.REDIRECT:
+ heuristic = false;
+ title =
+ `Start your search in the address bar to see suggestions from ` +
+ `${name} and your browsing history.`;
+ break;
+ case UrlbarProviderSearchTips.TIP_TYPE.PERSIST:
+ heuristic = false;
+ title =
+ "Searching just got simpler." +
+ " Try making your search more specific here in the address bar." +
+ " To show the URL instead, visit Search, in settings.";
+ break;
+ }
+ Assert.equal(result.heuristic, heuristic);
+ Assert.equal(result.displayed.title, title);
+ Assert.equal(
+ result.element.row._buttons.get("0").textContent,
+ expectedTip == UrlbarProviderSearchTips.TIP_TYPE.PERSIST
+ ? `Got it`
+ : `Okay, Got It`
+ );
+ Assert.ok(!result.element.row._buttons.has("help"));
+
+ const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true);
+ TelemetryTestUtils.assertKeyedScalar(
+ scalars,
+ "urlbar.tips",
+ `${expectedTip}-shown`,
+ 1
+ );
+
+ Assert.ok(
+ !UrlbarTestUtils.getOneOffSearchButtonsVisible(window),
+ "One-offs should be hidden when showing a search tip"
+ );
+
+ if (closeView) {
+ await UrlbarTestUtils.promisePopupClose(win);
+ }
+}
+
+function makeTipResult({ buttonUrl, helpUrl = undefined }) {
+ return new UrlbarResult(
+ UrlbarUtils.RESULT_TYPE.TIP,
+ UrlbarUtils.RESULT_SOURCE.OTHER_LOCAL,
+ {
+ helpUrl,
+ type: "test",
+ titleL10n: { id: "urlbar-search-tips-confirm" },
+ buttons: [
+ {
+ url: buttonUrl,
+ l10n: { id: "urlbar-search-tips-confirm" },
+ },
+ ],
+ }
+ );
+}
+
+/**
+ * Search tips helper. Opens a foreground tab and asserts that a particular
+ * search tip is shown or that no search tip is shown.
+ *
+ * @param {window} win
+ * A browser window.
+ * @param {string} url
+ * The URL to load in a new foreground tab.
+ * @param {UrlbarProviderSearchTips.TIP_TYPE} expectedTip
+ * The expected search tip. Pass a falsey value (like zero) for none.
+ * @param {boolean} reset
+ * If true, the search tips provider will be reset before this function
+ * returns. See resetSearchTipsProvider.
+ */
+async function checkTab(win, url, expectedTip, reset = true) {
+ // BrowserTestUtils.withNewTab always waits for tab load, which hangs on
+ // about:newtab for some reason, so don't use it.
+ let shownCount;
+ if (expectedTip) {
+ shownCount = UrlbarPrefs.get(`tipShownCount.${expectedTip}`);
+ }
+
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser: win.gBrowser,
+ url,
+ waitForLoad: url != "about:newtab",
+ });
+
+ await checkTip(win, expectedTip, true);
+ if (expectedTip) {
+ Assert.equal(
+ UrlbarPrefs.get(`tipShownCount.${expectedTip}`),
+ shownCount + 1,
+ "The shownCount pref should have been incremented by one."
+ );
+ }
+
+ if (reset) {
+ resetSearchTipsProvider();
+ }
+
+ BrowserTestUtils.removeTab(tab);
+}
+
+/**
+ * This lets us visit www.google.com (for example) and have it redirect to
+ * our test HTTP server instead of visiting the actual site.
+ *
+ * @param {string} domain
+ * The domain to which we are redirecting.
+ * @param {string} path
+ * The pathname on the domain.
+ * @param {Function} callback
+ * Executed when the test suite thinks `domain` is loaded.
+ */
+async function withDNSRedirect(domain, path, callback) {
+ // Some domains have special security requirements, like www.bing.com. We
+ // need to override them to successfully load them. This part is adapted from
+ // testing/marionette/cert.js.
+ const certOverrideService = Cc[
+ "@mozilla.org/security/certoverride;1"
+ ].getService(Ci.nsICertOverrideService);
+ Services.prefs.setBoolPref(
+ "network.stricttransportsecurity.preloadlist",
+ false
+ );
+ Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 0);
+ certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+ true
+ );
+
+ // Now set network.dns.localDomains to redirect the domain to localhost and
+ // set up an HTTP server.
+ Services.prefs.setCharPref("network.dns.localDomains", domain);
+
+ let server = new HttpServer();
+ server.registerPathHandler(path, (req, resp) => {
+ resp.write(`Test! http://${domain}${path}`);
+ });
+ server.start(-1);
+ server.identity.setPrimary("http", domain, server.identity.primaryPort);
+ let url = `http://${domain}:${server.identity.primaryPort}${path}`;
+
+ await callback(url);
+
+ // Reset network.dns.localDomains and stop the server.
+ Services.prefs.clearUserPref("network.dns.localDomains");
+ await new Promise(resolve => server.stop(resolve));
+
+ // Reset the security stuff.
+ certOverrideService.setDisableAllSecurityChecksAndLetAttackersInterceptMyData(
+ false
+ );
+ Services.prefs.clearUserPref("network.stricttransportsecurity.preloadlist");
+ Services.prefs.clearUserPref("security.cert_pinning.enforcement_level");
+ const sss = Cc["@mozilla.org/ssservice;1"].getService(
+ Ci.nsISiteSecurityService
+ );
+ sss.clearAll();
+}
+
+function resetSearchTipsProvider() {
+ Services.prefs.clearUserPref(
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}`
+ );
+ Services.prefs.clearUserPref(
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.PERSIST}`
+ );
+ Services.prefs.clearUserPref(
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}`
+ );
+ UrlbarProviderSearchTips.disableTipsForCurrentSession = false;
+}
+
+async function setDefaultEngine(name) {
+ let engine = (await Services.search.getEngines()).find(e => e.name == name);
+ Assert.ok(engine);
+ await Services.search.setDefault(
+ engine,
+ Ci.nsISearchService.CHANGE_REASON_UNKNOWN
+ );
+}