summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
diff options
context:
space:
mode:
Diffstat (limited to 'browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js')
-rw-r--r--browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js560
1 files changed, 560 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
new file mode 100644
index 0000000000..e0b75d0e9b
--- /dev/null
+++ b/browser/components/urlbar/tests/quicksuggest/browser/browser_quicksuggest_addons.js
@@ -0,0 +1,560 @@
+/* Any copyright is dedicated to the Public Domain.
+ * http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+// Test for addon suggestions.
+
+const TEST_MERINO_SUGGESTIONS = [
+ {
+ provider: "amo",
+ icon: "https://example.com/first.svg",
+ url: "https://example.com/first-addon",
+ title: "First Addon",
+ description: "This is a first addon",
+ custom_details: {
+ amo: {
+ rating: "5",
+ number_of_ratings: "1234567",
+ guid: "first@addon",
+ },
+ },
+ is_top_pick: true,
+ },
+ {
+ provider: "amo",
+ icon: "https://example.com/second.png",
+ url: "https://example.com/second-addon",
+ title: "Second Addon",
+ description: "This is a second addon",
+ custom_details: {
+ amo: {
+ rating: "4.5",
+ number_of_ratings: "123",
+ guid: "second@addon",
+ },
+ },
+ is_sponsored: true,
+ is_top_pick: false,
+ },
+ {
+ provider: "amo",
+ icon: "https://example.com/third.svg",
+ url: "https://example.com/third-addon",
+ title: "Third Addon",
+ description: "This is a third addon",
+ custom_details: {
+ amo: {
+ rating: "0",
+ number_of_ratings: "0",
+ guid: "third@addon",
+ },
+ },
+ is_top_pick: false,
+ },
+ {
+ provider: "amo",
+ icon: "https://example.com/fourth.svg",
+ url: "https://example.com/fourth-addon",
+ title: "Fourth Addon",
+ description: "This is a fourth addon",
+ custom_details: {
+ amo: {
+ rating: "4",
+ number_of_ratings: "4",
+ guid: "fourth@addon",
+ },
+ },
+ },
+];
+
+add_setup(async function () {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.quicksuggest.enabled", true],
+ ["browser.urlbar.quicksuggest.remoteSettings.enabled", false],
+ ["browser.urlbar.bestMatch.enabled", true],
+ ],
+ });
+
+ await SearchTestUtils.installSearchExtension({}, { setAsDefault: true });
+
+ await QuickSuggestTestUtils.ensureQuickSuggestInit({
+ merinoSuggestions: TEST_MERINO_SUGGESTIONS,
+ });
+});
+
+add_task(async function basic() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", true]],
+ });
+
+ for (const merinoSuggestion of TEST_MERINO_SUGGESTIONS) {
+ MerinoTestUtils.server.response.body.suggestions = [merinoSuggestion];
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "only match the Merino suggestion",
+ });
+ Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
+
+ const { element, result } = await UrlbarTestUtils.getDetailsOfResultAt(
+ window,
+ 1
+ );
+ const row = element.row;
+ const icon = row.querySelector(".urlbarView-dynamic-addons-icon");
+ Assert.equal(icon.src, merinoSuggestion.icon);
+ const url = row.querySelector(".urlbarView-dynamic-addons-url");
+ Assert.equal(url.textContent, merinoSuggestion.url);
+ const title = row.querySelector(".urlbarView-dynamic-addons-title");
+ Assert.equal(title.textContent, merinoSuggestion.title);
+ const description = row.querySelector(
+ ".urlbarView-dynamic-addons-description"
+ );
+ Assert.equal(description.textContent, merinoSuggestion.description);
+ const reviews = row.querySelector(".urlbarView-dynamic-addons-reviews");
+ Assert.equal(
+ reviews.textContent,
+ `${new Intl.NumberFormat().format(
+ Number(merinoSuggestion.custom_details.amo.number_of_ratings)
+ )} reviews`
+ );
+
+ const isTopPick = merinoSuggestion.is_top_pick ?? true;
+ if (isTopPick) {
+ Assert.equal(result.suggestedIndex, 1);
+ } else if (merinoSuggestion.is_sponsored) {
+ Assert.equal(
+ result.suggestedIndex,
+ UrlbarPrefs.get("quickSuggestSponsoredIndex")
+ );
+ } else {
+ Assert.equal(
+ result.suggestedIndex,
+ UrlbarPrefs.get("quickSuggestNonSponsoredIndex")
+ );
+ }
+
+ const onLoad = BrowserTestUtils.browserLoaded(
+ gBrowser.selectedBrowser,
+ false,
+ merinoSuggestion.url
+ );
+ EventUtils.synthesizeMouseAtCenter(row, {});
+ await onLoad;
+ Assert.ok(true, "Expected page is loaded");
+
+ await PlacesUtils.history.clear();
+ }
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function ratings() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", true]],
+ });
+
+ const testRating = [
+ "0",
+ "0.24",
+ "0.25",
+ "0.74",
+ "0.75",
+ "1",
+ "1.24",
+ "1.25",
+ "1.74",
+ "1.75",
+ "2",
+ "2.24",
+ "2.25",
+ "2.74",
+ "2.75",
+ "3",
+ "3.24",
+ "3.25",
+ "3.74",
+ "3.75",
+ "4",
+ "4.24",
+ "4.25",
+ "4.74",
+ "4.75",
+ "5",
+ ];
+ const baseMerinoSuggestion = JSON.parse(
+ JSON.stringify(TEST_MERINO_SUGGESTIONS[0])
+ );
+
+ for (const rating of testRating) {
+ baseMerinoSuggestion.custom_details.amo.rating = rating;
+ MerinoTestUtils.server.response.body.suggestions = [baseMerinoSuggestion];
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "only match the Merino suggestion",
+ });
+ Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
+
+ const { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
+
+ const ratingElements = element.row.querySelectorAll(
+ ".urlbarView-dynamic-addons-rating"
+ );
+ Assert.equal(ratingElements.length, 5);
+
+ for (let i = 0; i < ratingElements.length; i++) {
+ const ratingElement = ratingElements[i];
+
+ const distanceToFull = Number(rating) - i;
+ let fill = "full";
+ if (distanceToFull < 0.25) {
+ fill = "empty";
+ } else if (distanceToFull < 0.75) {
+ fill = "half";
+ }
+ Assert.equal(ratingElement.getAttribute("fill"), fill);
+ }
+ }
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function disable() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", false]],
+ });
+
+ // Restore AdmWikipedia suggestions.
+ MerinoTestUtils.server.reset();
+ // Add one Addon suggestion that is higher score than AdmWikipedia.
+ MerinoTestUtils.server.response.body.suggestions.push(
+ Object.assign({}, TEST_MERINO_SUGGESTIONS[0], { score: 2 })
+ );
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "only match the Merino suggestion",
+ });
+ Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
+
+ const { result } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
+ Assert.equal(result.payload.telemetryType, "adm_sponsored");
+
+ MerinoTestUtils.server.response.body.suggestions = TEST_MERINO_SUGGESTIONS;
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function resultMenu_showLessFrequently() {
+ await SpecialPowers.pushPrefEnv({
+ set: [
+ ["browser.urlbar.addons.featureGate", true],
+ ["browser.urlbar.addons.showLessFrequentlyCount", 0],
+ ],
+ });
+
+ const cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature({
+ addonsShowLessFrequentlyCap: 3,
+ });
+
+ // Sanity check.
+ Assert.equal(UrlbarPrefs.get("addonsShowLessFrequentlyCap"), 3);
+ Assert.equal(UrlbarPrefs.get("addons.showLessFrequentlyCount"), 0);
+
+ await doShowLessFrequently({
+ input: "aaa b",
+ expected: {
+ isSuggestionShown: true,
+ isMenuItemShown: true,
+ },
+ });
+ Assert.equal(UrlbarPrefs.get("addons.showLessFrequentlyCount"), 1);
+
+ await doShowLessFrequently({
+ input: "aaa b",
+ expected: {
+ isSuggestionShown: true,
+ isMenuItemShown: true,
+ },
+ });
+ Assert.equal(UrlbarPrefs.get("addons.showLessFrequentlyCount"), 2);
+
+ await doShowLessFrequently({
+ input: "aaa b",
+ expected: {
+ isSuggestionShown: true,
+ isMenuItemShown: true,
+ },
+ });
+ Assert.equal(UrlbarPrefs.get("addons.showLessFrequentlyCount"), 3);
+
+ await doShowLessFrequently({
+ input: "aaa b",
+ expected: {
+ // The suggestion should not display since addons.showLessFrequentlyCount
+ // is 3 and the substring (" b") after the first word ("aaa") is 2 chars
+ // long.
+ isSuggestionShown: false,
+ },
+ });
+
+ await doShowLessFrequently({
+ input: "aaa bb",
+ expected: {
+ // The suggestion should display, but item should not shown since the
+ // addons.showLessFrequentlyCount reached to addonsShowLessFrequentlyCap
+ // already.
+ isSuggestionShown: true,
+ isMenuItemShown: false,
+ },
+ });
+
+ await cleanUpNimbus();
+ await SpecialPowers.popPrefEnv();
+});
+
+// Tests the "Not interested" result menu dismissal command.
+add_task(async function resultMenu_notInterested() {
+ await doDismissTest("not_interested");
+});
+
+// Tests the "Not relevant" result menu dismissal command.
+add_task(async function notRelevant() {
+ await doDismissTest("not_relevant");
+});
+
+add_task(async function rowLabel() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", true]],
+ });
+
+ const testCases = [
+ {
+ bestMatch: true,
+ expected: "Firefox extension",
+ },
+ {
+ bestMatch: false,
+ expected: "Firefox Suggest",
+ },
+ ];
+
+ for (const { bestMatch, expected } of testCases) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.bestMatch.enabled", bestMatch]],
+ });
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "only match the Merino suggestion",
+ });
+ Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
+
+ const { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
+ const row = element.row;
+ Assert.equal(row.getAttribute("label"), expected);
+
+ await SpecialPowers.popPrefEnv();
+ }
+
+ await SpecialPowers.popPrefEnv();
+});
+
+add_task(async function treatmentB() {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", true]],
+ });
+
+ const cleanUpNimbus = await UrlbarTestUtils.initNimbusFeature({
+ addonsUITreatment: "b",
+ });
+ // Sanity check.
+ Assert.equal(UrlbarPrefs.get("addonsUITreatment"), "b");
+
+ const merinoSuggestion = TEST_MERINO_SUGGESTIONS[0];
+ MerinoTestUtils.server.response.body.suggestions = [merinoSuggestion];
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "only match the Merino suggestion",
+ });
+ Assert.equal(UrlbarTestUtils.getResultCount(window), 2);
+
+ const { element } = await UrlbarTestUtils.getDetailsOfResultAt(window, 1);
+ const row = element.row;
+ const icon = row.querySelector(".urlbarView-dynamic-addons-icon");
+ Assert.equal(icon.src, merinoSuggestion.icon);
+ const url = row.querySelector(".urlbarView-dynamic-addons-url");
+ Assert.equal(url.textContent, merinoSuggestion.url);
+ const title = row.querySelector(".urlbarView-dynamic-addons-title");
+ Assert.equal(title.textContent, merinoSuggestion.title);
+ const description = row.querySelector(
+ ".urlbarView-dynamic-addons-description"
+ );
+ Assert.equal(description.textContent, merinoSuggestion.description);
+ const ratingContainer = row.querySelector(
+ ".urlbarView-dynamic-addons-ratingContainer"
+ );
+ Assert.ok(BrowserTestUtils.is_hidden(ratingContainer));
+ const reviews = row.querySelector(".urlbarView-dynamic-addons-reviews");
+ Assert.equal(reviews.textContent, "Recommended");
+
+ await cleanUpNimbus();
+ await SpecialPowers.popPrefEnv();
+});
+
+async function doShowLessFrequently({ input, expected }) {
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: input,
+ });
+
+ if (!expected.isSuggestionShown) {
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ const details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ Assert.notEqual(
+ details.result.payload.dynamicType,
+ "addons",
+ `Addons suggestion should be absent (checking index ${i})`
+ );
+ }
+
+ return;
+ }
+
+ const resultIndex = 1;
+ const details = await UrlbarTestUtils.getDetailsOfResultAt(
+ window,
+ resultIndex
+ );
+ Assert.equal(
+ details.result.payload.dynamicType,
+ "addons",
+ `Addons suggestion should be present at expected index after ${input} search`
+ );
+
+ // Click the command.
+ try {
+ await UrlbarTestUtils.openResultMenuAndClickItem(
+ window,
+ "show_less_frequently",
+ {
+ resultIndex,
+ }
+ );
+ Assert.ok(expected.isMenuItemShown);
+ Assert.ok(
+ gURLBar.view.isOpen,
+ "The view should remain open clicking the command"
+ );
+ Assert.ok(
+ details.element.row.hasAttribute("feedback-acknowledgment"),
+ "Row should have feedback acknowledgment after clicking command"
+ );
+ } catch (e) {
+ Assert.ok(!expected.isMenuItemShown);
+ Assert.ok(
+ !details.element.row.hasAttribute("feedback-acknowledgment"),
+ "Row should not have feedback acknowledgment after clicking command"
+ );
+ Assert.equal(
+ e.message,
+ "Menu item not found for command: show_less_frequently"
+ );
+ }
+
+ await UrlbarTestUtils.promisePopupClose(window);
+}
+
+async function doDismissTest(command) {
+ await SpecialPowers.pushPrefEnv({
+ set: [["browser.urlbar.addons.featureGate", true]],
+ });
+
+ await UrlbarTestUtils.promiseAutocompleteResultPopup({
+ window,
+ value: "123",
+ });
+
+ const resultCount = UrlbarTestUtils.getResultCount(window);
+ const resultIndex = 1;
+ let details = await UrlbarTestUtils.getDetailsOfResultAt(window, resultIndex);
+ Assert.equal(
+ details.result.payload.dynamicType,
+ "addons",
+ "Addons suggestion should be present"
+ );
+
+ // Sanity check.
+ Assert.ok(UrlbarPrefs.get("suggest.addons"));
+
+ // Click the command.
+ await UrlbarTestUtils.openResultMenuAndClickItem(
+ window,
+ ["[data-l10n-id=firefox-suggest-command-dont-show-this]", command],
+ { resultIndex, openByMouse: true }
+ );
+
+ Assert.ok(
+ !UrlbarPrefs.get("suggest.addons"),
+ "suggest.addons pref should be set to false after dismissal"
+ );
+
+ // The row should be a tip now.
+ Assert.ok(gURLBar.view.isOpen, "The view should remain open after dismissal");
+ Assert.equal(
+ UrlbarTestUtils.getResultCount(window),
+ resultCount,
+ "The result count should not haved changed after dismissal"
+ );
+ details = await UrlbarTestUtils.getDetailsOfResultAt(window, resultIndex);
+ Assert.equal(
+ details.type,
+ UrlbarUtils.RESULT_TYPE.TIP,
+ "Row should be a tip after dismissal"
+ );
+ Assert.equal(
+ details.result.payload.type,
+ "dismissalAcknowledgment",
+ "Tip type should be dismissalAcknowledgment"
+ );
+ Assert.ok(
+ !details.element.row.hasAttribute("feedback-acknowledgment"),
+ "Row should not have feedback acknowledgment after dismissal"
+ );
+
+ // Get the dismissal acknowledgment's "Got it" button and click it.
+ let gotItButton = UrlbarTestUtils.getButtonForResultIndex(
+ window,
+ "0",
+ resultIndex
+ );
+ Assert.ok(gotItButton, "Row should have a 'Got it' button");
+ EventUtils.synthesizeMouseAtCenter(gotItButton, {}, window);
+
+ // The view should remain open and the tip row should be gone.
+ Assert.ok(
+ gURLBar.view.isOpen,
+ "The view should remain open clicking the 'Got it' button"
+ );
+ Assert.equal(
+ UrlbarTestUtils.getResultCount(window),
+ resultCount - 1,
+ "The result count should be one less after clicking 'Got it' button"
+ );
+ for (let i = 0; i < UrlbarTestUtils.getResultCount(window); i++) {
+ details = await UrlbarTestUtils.getDetailsOfResultAt(window, i);
+ Assert.ok(
+ details.type != UrlbarUtils.RESULT_TYPE.TIP &&
+ details.result.payload.dynamicType !== "addons",
+ "Tip result and addon result should not be present"
+ );
+ }
+
+ await UrlbarTestUtils.promisePopupClose(window);
+
+ await SpecialPowers.popPrefEnv();
+ UrlbarPrefs.clear("suggest.addons");
+}