summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/browser-tips/browser_searchTips.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/browser-tips/browser_searchTips.js')
-rw-r--r--browser/components/urlbar/tests/browser-tips/browser_searchTips.js657
1 files changed, 657 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/browser-tips/browser_searchTips.js b/browser/components/urlbar/tests/browser-tips/browser_searchTips.js
new file mode 100644
index 0000000000..ff592bc831
--- /dev/null
+++ b/browser/components/urlbar/tests/browser-tips/browser_searchTips.js
@@ -0,0 +1,657 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+// Tests the Search Tips feature, which displays a prompt to use the Urlbar on
+// the newtab page and on the user's default search engine's homepage.
+// Specifically, it tests that the Tips appear when they should be appearing.
+// This doesn't test the max-shown-count limit or the restriction on tips when
+// we show the default browser prompt because those require restarting the
+// browser.
+
+"use strict";
+
+ChromeUtils.defineESModuleGetters(this, {
+ AppMenuNotifications: "resource://gre/modules/AppMenuNotifications.sys.mjs",
+ ProfileAge: "resource://gre/modules/ProfileAge.sys.mjs",
+ PromiseUtils: "resource://gre/modules/PromiseUtils.sys.mjs",
+ UrlbarPrefs: "resource:///modules/UrlbarPrefs.sys.mjs",
+ UrlbarProviderSearchTips:
+ "resource:///modules/UrlbarProviderSearchTips.sys.mjs",
+});
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ HttpServer: "resource://testing-common/httpd.js",
+});
+
+// These should match the same consts in UrlbarProviderSearchTips.jsm.
+const MAX_SHOWN_COUNT = 4;
+const LAST_UPDATE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
+
+// We test some of the bigger Google domains.
+const GOOGLE_DOMAINS = [
+ "www.google.com",
+ "www.google.ca",
+ "www.google.co.uk",
+ "www.google.com.au",
+ "www.google.co.nz",
+];
+
+// In order for the persist tip to appear, the scheme of the
+// search engine has to be the same as the scheme of the SERP url.
+// withDNSRedirect() loads an http: url while the searchform
+// of the default engine uses https. To enable the search term
+// to be shown, we use the Example engine because it doesn't require
+// a redirect.
+const SEARCH_SERP_URL = "https://example.com/?q=chocolate";
+
+add_setup(async function () {
+ await PlacesUtils.history.clear();
+ await PlacesUtils.bookmarks.eraseEverything();
+
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ [
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.ONBOARD}`,
+ 0,
+ ],
+ [
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.PERSIST}`,
+ 0,
+ ],
+ [
+ `browser.urlbar.tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.REDIRECT}`,
+ 0,
+ ],
+ ],
+ });
+
+ // Write an old profile age so tips are actually shown.
+ let age = await ProfileAge();
+ let originalTimes = age._times;
+ let date = Date.now() - LAST_UPDATE_THRESHOLD_MS - 30000;
+ age._times = { created: date, firstUse: date };
+ await age.writeTimes();
+
+ // Remove update history and the current active update so tips are shown.
+ let updateRootDir = Services.dirsvc.get("UpdRootD", Ci.nsIFile);
+ let updatesFile = updateRootDir.clone();
+ updatesFile.append("updates.xml");
+ let activeUpdateFile = updateRootDir.clone();
+ activeUpdateFile.append("active-update.xml");
+ try {
+ updatesFile.remove(false);
+ } catch (e) {}
+ try {
+ activeUpdateFile.remove(false);
+ } catch (e) {}
+
+ let defaultEngine = await Services.search.getDefault();
+ let defaultEngineName = defaultEngine.name;
+ Assert.equal(defaultEngineName, "Google", "Default engine should be Google.");
+
+ // Add a mock engine so we don't hit the network loading the SERP.
+ await SearchTestUtils.installSearchExtension();
+
+ registerCleanupFunction(async () => {
+ let age2 = await ProfileAge();
+ age2._times = originalTimes;
+ await age2.writeTimes();
+ await setDefaultEngine(defaultEngineName);
+ resetSearchTipsProvider();
+ });
+});
+
+// The onboarding tip should be shown on about:newtab.
+add_task(async function newtab() {
+ await checkTab(
+ window,
+ "about:newtab",
+ UrlbarProviderSearchTips.TIP_TYPE.ONBOARD
+ );
+});
+
+// The onboarding tip should be shown on about:home.
+add_task(async function home() {
+ await checkTab(
+ window,
+ "about:home",
+ UrlbarProviderSearchTips.TIP_TYPE.ONBOARD
+ );
+});
+
+// The redirect tip should be shown for www.google.com when it's the default
+// engine.
+add_task(async function google() {
+ await setDefaultEngine("Google");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT);
+ });
+ }
+});
+
+// The redirect tip should be shown for www.google.com/webhp when it's the
+// default engine.
+add_task(async function googleWebhp() {
+ await setDefaultEngine("Google");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/webhp", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT);
+ });
+ }
+});
+
+// The redirect tip should be shown for the Google homepage when query strings
+// are appended.
+add_task(async function googleQueryString() {
+ await setDefaultEngine("Google");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/webhp", async url => {
+ await checkTab(
+ window,
+ `${url}?hl=en`,
+ UrlbarProviderSearchTips.TIP_TYPE.REDIRECT
+ );
+ });
+ }
+});
+
+// The redirect tip should not be shown on Google results pages.
+add_task(async function googleResults() {
+ await setDefaultEngine("Google");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/search", async url => {
+ await checkTab(
+ window,
+ `${url}?q=firefox`,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+ });
+ }
+});
+
+// The redirect tip should not be shown for www.google.com when it's not the
+// default engine.
+add_task(async function googleNotDefault() {
+ await setDefaultEngine("Bing");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+ }
+});
+
+// The redirect tip should not be shown for www.google.com/webhp when it's not
+// the default engine.
+add_task(async function googleWebhpNotDefault() {
+ await setDefaultEngine("Bing");
+ for (let domain of GOOGLE_DOMAINS) {
+ await withDNSRedirect(domain, "/webhp", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+ }
+});
+
+// The redirect tip should be shown for www.bing.com when it's the default
+// engine.
+add_task(async function bing() {
+ await setDefaultEngine("Bing");
+ await withDNSRedirect("www.bing.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT);
+ });
+});
+
+// The redirect tip should be shown on the Bing homepage even when Bing appends
+// query strings.
+add_task(async function bingQueryString() {
+ await setDefaultEngine("Bing");
+ await withDNSRedirect("www.bing.com", "/", async url => {
+ await checkTab(
+ window,
+ `${url}?toWww=1`,
+ UrlbarProviderSearchTips.TIP_TYPE.REDIRECT
+ );
+ });
+});
+
+// The redirect tip should not be shown on Bing results pages.
+add_task(async function bingResults() {
+ await setDefaultEngine("Bing");
+ await withDNSRedirect("www.bing.com", "/search", async url => {
+ await checkTab(
+ window,
+ `${url}?q=firefox`,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+ });
+});
+
+// The redirect tip should not be shown for www.bing.com when it's not the
+// default engine.
+add_task(async function bingNotDefault() {
+ await setDefaultEngine("Google");
+ await withDNSRedirect("www.bing.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+});
+
+// The redirect tip should be shown for duckduckgo.com when it's the default
+// engine.
+add_task(async function ddg() {
+ await setDefaultEngine("DuckDuckGo");
+ await withDNSRedirect("duckduckgo.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT);
+ });
+});
+
+// The redirect tip should be shown for start.duckduckgo.com when it's the
+// default engine.
+add_task(async function ddgStart() {
+ await setDefaultEngine("DuckDuckGo");
+ await withDNSRedirect("start.duckduckgo.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.REDIRECT);
+ });
+});
+
+// The redirect tip should not be shown for duckduckgo.com when it's not the
+// default engine.
+add_task(async function ddgNotDefault() {
+ await setDefaultEngine("Google");
+ await withDNSRedirect("duckduckgo.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+});
+
+// The redirect tip should not be shown for start.duckduckgo.com when it's not
+// the default engine.
+add_task(async function ddgStartNotDefault() {
+ await setDefaultEngine("Google");
+ await withDNSRedirect("start.duckduckgo.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+});
+
+// The redirect tip should not be shown for duckduckgo.com/?q=foo, the search
+// results page, which happens to have the same domain and path as the home
+// page.
+add_task(async function ddgSearchResultsPage() {
+ await setDefaultEngine("DuckDuckGo");
+ await withDNSRedirect("duckduckgo.com", "/", async url => {
+ await checkTab(
+ window,
+ `${url}?q=test`,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+ });
+});
+
+// The redirect tip should not be shown on a non-engine page.
+add_task(async function nonEnginePage() {
+ await checkTab(
+ window,
+ "http://example.com/",
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+});
+
+// The persist tip should show on default SERPs.
+// This test also has an implied check that the SERP
+// is receiving an originalURI.
+// This is because the page the test is attempting to load
+// will differ from the page that's actually loaded due to
+// the DNS redirect.
+add_task(async function persistTipOnDefault() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+ await checkTab(
+ window,
+ SEARCH_SERP_URL,
+ UrlbarProviderSearchTips.TIP_TYPE.PERSIST
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+// The persist tip should not show on non-default SERPs.
+add_task(async function noPersistTipOnNonDefault() {
+ await setDefaultEngine("DuckDuckGo");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+ await checkTab(
+ window,
+ SEARCH_SERP_URL,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+// The persist tip should only show up once a session.
+add_task(async function persistTipOnceOnDefaultSerp() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+ await checkTab(
+ window,
+ SEARCH_SERP_URL,
+ UrlbarProviderSearchTips.TIP_TYPE.PERSIST
+ );
+ await checkTab(
+ window,
+ SEARCH_SERP_URL,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+ await SpecialPowers.popPrefEnv();
+});
+
+// The persist tip should not show in a window
+// with a selected tab containing a non-SERP url.
+add_task(async function noPersistTipInWindowWithNonSerpTab() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+
+ // Create a new window for the SERP to be loaded into.
+ let newWindow = await BrowserTestUtils.openNewBrowserWindow();
+
+ // Focus on the original window.
+ window.focus();
+ await waitForBrowserWindowActive(window);
+
+ // Load the SERP in the new window to initiate a background load.
+ let browserLoadedPromise = BrowserTestUtils.browserLoaded(
+ newWindow.gBrowser.selectedBrowser,
+ false,
+ SEARCH_SERP_URL
+ );
+ BrowserTestUtils.loadURIString(
+ newWindow.gBrowser.selectedBrowser,
+ SEARCH_SERP_URL
+ );
+ await browserLoadedPromise;
+
+ // Wait longer than the persist tip delay to check that the search tip
+ // doesn't show on the non-SERP tab.
+ await new Promise(resolve =>
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(resolve, UrlbarProviderSearchTips.SHOW_PERSIST_TIP_DELAY_MS * 2)
+ );
+ Assert.ok(!window.gURLBar.view.isOpen);
+
+ // Clean up.
+ await BrowserTestUtils.closeWindow(newWindow);
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+});
+
+// Tips should be shown at most once per session regardless of their type.
+add_task(async function oncePerSession() {
+ await setDefaultEngine("Google");
+ await checkTab(
+ window,
+ "about:newtab",
+ UrlbarProviderSearchTips.TIP_TYPE.ONBOARD,
+ false
+ );
+ await checkTab(
+ window,
+ "about:newtab",
+ UrlbarProviderSearchTips.TIP_TYPE.NONE,
+ false
+ );
+ await withDNSRedirect("www.google.com", "/", async url => {
+ await checkTab(window, url, UrlbarProviderSearchTips.TIP_TYPE.NONE);
+ });
+ await setDefaultEngine("Example");
+ await checkTab(
+ window,
+ SEARCH_SERP_URL,
+ UrlbarProviderSearchTips.TIP_TYPE.NONE
+ );
+});
+
+// The one-off search buttons should not be shown when
+// a search tip is shown even though the search string is empty.
+add_task(async function shortcut_buttons_with_tip() {
+ await checkTab(
+ window,
+ "about:newtab",
+ UrlbarProviderSearchTips.TIP_TYPE.ONBOARD
+ );
+});
+
+// Don't show the persist search tip when the browser loads
+// a different page from the page the tip was supposed to show on.
+add_task(async function noSearchTipWhileAnotherPageLoads() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+
+ // Create a slow endpoint.
+ const SLOW_PAGE =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "http://www.example.com"
+ ) + "slow-page.sjs";
+
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: SEARCH_SERP_URL,
+ });
+
+ // Load a slow URI to cause an onStateChange event but
+ // not an onLocationChange event.
+ BrowserTestUtils.loadURIString(tab.linkedBrowser, SLOW_PAGE);
+
+ // Wait roughly for the amount of time it would take for the
+ // persist search tip to show.
+ await new Promise(resolve =>
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(resolve, UrlbarProviderSearchTips.SHOW_PERSIST_TIP_DELAY_MS * 2)
+ );
+
+ // Check the search tip didn't show while the page was loading.
+ Assert.equal(
+ UrlbarPrefs.get(
+ `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.PERSIST}`
+ ),
+ 0,
+ "The shownCount pref should be 0."
+ );
+
+ Assert.equal(false, window.gURLBar.view.isOpen, "Urlbar should be closed.");
+
+ // Clean up.
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Show the persist search tip when the browser is still loading
+// resources from the page the tip is supposed to show on.
+add_task(async function searchTipWhilePageLoads() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+
+ // Create a search engine endpoint that will still
+ // be loading resources on the page load.
+ const SLOW_PAGE =
+ getRootDirectory(gTestPath).replace(
+ "chrome://mochitests/content",
+ "https://www.example.com"
+ ) + "slow-page.html";
+
+ await SearchTestUtils.installSearchExtension({
+ name: "Slow Engine",
+ search_url: SLOW_PAGE,
+ search_url_get_params: "search={searchTerms}",
+ });
+ await setDefaultEngine("Slow Engine");
+
+ let engine = Services.search.getEngineByName("Slow Engine");
+ let [expectedSearchUrl] = UrlbarUtils.getSearchQueryUrl(engine, "chocolate");
+
+ // Load a slow SERP.
+ await checkTab(
+ window,
+ expectedSearchUrl,
+ UrlbarProviderSearchTips.TIP_TYPE.PERSIST
+ );
+
+ // Clean up.
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+});
+
+// Search tips modify the userTypedValue of a tab. The next time
+// the pageproxystate is updated, the existence of the userTypedValue
+// can change the pageproxystate. In the case of the Persist Search Tip,
+// we don't want to change the pageproxystate while the Urlbar is non-focused,
+// so check that when an event causes the pageproxystate to update
+// (e.g. a SERP pushing state), the pageproxystate remains the same.
+add_task(async function persistSearchTipAfterPushState() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: SEARCH_SERP_URL,
+ });
+
+ // Ensure the search tip is visible.
+ await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.PERSIST, false);
+ Assert.equal(
+ gURLBar.getAttribute("pageproxystate"),
+ "valid",
+ "Urlbar is should be in a valid pageproxystate."
+ );
+
+ // Mock the default SERP using the History API on an exising website.
+ // This is to trigger another call to setURI.
+ await SpecialPowers.spawn(tab.linkedBrowser, [SEARCH_SERP_URL], async url => {
+ content.history.pushState({}, "", url);
+ });
+
+ Assert.equal(
+ gURLBar.getAttribute("pageproxystate"),
+ "valid",
+ "Urlbar is should be in a valid pageproxystate."
+ );
+
+ // Clean up.
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+ BrowserTestUtils.removeTab(tab);
+});
+
+// Ensure a the Persist Search Tip is non-visible when a PopupNotification
+// is already visible.
+add_task(async function persistSearchTipBeforePopupShown() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: SEARCH_SERP_URL,
+ });
+
+ let promisePopupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+ PopupNotifications.show(
+ gBrowser.selectedBrowser,
+ "test-notification",
+ "This is a sample popup.",
+ "geo-notification-icon"
+ );
+ await promisePopupShown;
+
+ // Wait roughly for the amount of time it would take for the
+ // persist search tip to show.
+ await new Promise(resolve =>
+ // eslint-disable-next-line mozilla/no-arbitrary-setTimeout
+ setTimeout(resolve, UrlbarProviderSearchTips.SHOW_PERSIST_TIP_DELAY_MS * 2)
+ );
+
+ // Check the search tip didn't show while the page was loading.
+ Assert.equal(
+ UrlbarPrefs.get(
+ `tipShownCount.${UrlbarProviderSearchTips.TIP_TYPE.PERSIST}`
+ ),
+ 0,
+ "The shownCount pref should be 0."
+ );
+ Assert.equal(false, window.gURLBar.view.isOpen, "Urlbar should be closed.");
+
+ // Clean up.
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+ BrowserTestUtils.removeTab(tab);
+});
+
+// The Persist Search Tip should be hidden when a PopupNotification appears.
+add_task(async function persistSearchTipAfterPopupShown() {
+ await setDefaultEngine("Example");
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.showSearchTerms.featureGate", true]],
+ });
+ let tab = await BrowserTestUtils.openNewForegroundTab({
+ gBrowser,
+ url: SEARCH_SERP_URL,
+ });
+
+ // Ensure the search tip is visible.
+ await checkTip(window, UrlbarProviderSearchTips.TIP_TYPE.PERSIST, false);
+
+ // Show a popup after the search tip is shown.
+ let promisePopupShown = BrowserTestUtils.waitForEvent(
+ PopupNotifications.panel,
+ "popupshown"
+ );
+ PopupNotifications.show(
+ gBrowser.selectedBrowser,
+ "test-notification",
+ "This is a sample popup.",
+ "geo-notification-icon"
+ );
+ await promisePopupShown;
+
+ // The search tip should not be visible.
+ Assert.equal(false, window.gURLBar.view.isOpen, "Urlbar should be closed.");
+ Assert.equal(
+ gURLBar.getAttribute("pageproxystate"),
+ "valid",
+ "Urlbar is should be in a valid pageproxystate."
+ );
+
+ // Clean up.
+ await SpecialPowers.popPrefEnv();
+ resetSearchTipsProvider();
+ BrowserTestUtils.removeTab(tab);
+});
+
+function waitForBrowserWindowActive(win) {
+ return new Promise(resolve => {
+ if (Services.focus.activeWindow == win) {
+ resolve();
+ } else {
+ win.addEventListener(
+ "activate",
+ () => {
+ resolve();
+ },
+ { once: true }
+ );
+ }
+ });
+}