summaryrefslogtreecommitdiffstats
path: root/browser/components/urlbar/tests/quicksuggest/unit/test_weather.js
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /browser/components/urlbar/tests/quicksuggest/unit/test_weather.js
parentInitial commit. (diff)
downloadfirefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz
firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'browser/components/urlbar/tests/quicksuggest/unit/test_weather.js')
-rw-r--r--browser/components/urlbar/tests/quicksuggest/unit/test_weather.js765
1 files changed, 765 insertions, 0 deletions
diff --git a/browser/components/urlbar/tests/quicksuggest/unit/test_weather.js b/browser/components/urlbar/tests/quicksuggest/unit/test_weather.js
new file mode 100644
index 0000000000..c07fcef599
--- /dev/null
+++ b/browser/components/urlbar/tests/quicksuggest/unit/test_weather.js
@@ -0,0 +1,765 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// Tests the quick suggest weather feature.
+
+"use strict";
+
+const HISTOGRAM_LATENCY = "FX_URLBAR_MERINO_LATENCY_WEATHER_MS";
+const HISTOGRAM_RESPONSE = "FX_URLBAR_MERINO_RESPONSE_WEATHER";
+
+const { WEATHER_SUGGESTION } = MerinoTestUtils;
+
+add_task(async function init() {
+ await QuickSuggestTestUtils.ensureQuickSuggestInit();
+ UrlbarPrefs.set("quicksuggest.enabled", true);
+
+ await MerinoTestUtils.initWeather();
+});
+
+// The feature should be properly uninitialized when it's disabled and then
+// re-initialized when it's re-enabled. This task disables the feature using the
+// feature gate pref.
+add_task(async function disableAndEnable_featureGate() {
+ await doBasicDisableAndEnableTest("weather.featureGate");
+});
+
+// The feature should be properly uninitialized when it's disabled and then
+// re-initialized when it's re-enabled. This task disables the feature using the
+// suggest pref.
+add_task(async function disableAndEnable_suggestPref() {
+ await doBasicDisableAndEnableTest("suggest.weather");
+});
+
+async function doBasicDisableAndEnableTest(pref) {
+ // Sanity check initial state.
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ // Disable the feature. It should be immediately uninitialized.
+ UrlbarPrefs.set(pref, false);
+ assertDisabled({
+ message: "After disabling",
+ pendingFetchCount: 0,
+ });
+
+ // No suggestion should be returned for a search.
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ let histograms = MerinoTestUtils.getAndClearHistograms({
+ extraLatency: HISTOGRAM_LATENCY,
+ extraResponse: HISTOGRAM_RESPONSE,
+ });
+
+ // Re-enable the feature. It should be immediately initialized and a fetch
+ // should start.
+ info("Re-enable the feature");
+ let fetchPromise = QuickSuggest.weather.waitForFetches();
+ UrlbarPrefs.set(pref, true);
+ assertEnabled({
+ message: "Immediately after re-enabling",
+ hasSuggestion: false,
+ pendingFetchCount: 1,
+ });
+
+ await fetchPromise;
+ assertEnabled({
+ message: "After awaiting fetch",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ Assert.equal(
+ QuickSuggest.weather._test_merino.lastFetchStatus,
+ "success",
+ "The request successfully finished"
+ );
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: "success",
+ latencyRecorded: true,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ // The suggestion should be returned for a search.
+ context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [makeExpectedResult()],
+ });
+}
+
+// Disables and re-enables the feature without waiting for any intermediate
+// fetches to complete, using the following steps:
+//
+// 1. Disable
+// 2. Enable
+// 3. Disable again
+//
+// At this point, the fetch from step 2 will remain ongoing but once it finishes
+// it should be discarded since the feature is disabled.
+add_task(async function disableAndEnable_immediate1() {
+ // Sanity check initial state.
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ // Disable the feature. It should be immediately uninitialized.
+ UrlbarPrefs.set("weather.featureGate", false);
+ assertDisabled({
+ message: "After disabling",
+ pendingFetchCount: 0,
+ });
+
+ // Re-enable the feature. It should be immediately initialized and a fetch
+ // should start.
+ let fetchPromise = QuickSuggest.weather.waitForFetches();
+ UrlbarPrefs.set("weather.featureGate", true);
+ assertEnabled({
+ message: "Immediately after re-enabling",
+ hasSuggestion: false,
+ pendingFetchCount: 1,
+ });
+
+ // Disable it again. The fetch will remain ongoing since pending fetches
+ // aren't stopped when the feature is disabled.
+ UrlbarPrefs.set("weather.featureGate", false);
+ assertDisabled({
+ message: "After disabling again",
+ pendingFetchCount: 1,
+ });
+
+ // Wait for the fetch to finish.
+ await fetchPromise;
+
+ // The fetched suggestion should be discarded and the feature should remain
+ // uninitialized.
+ assertDisabled({
+ message: "After awaiting fetch",
+ pendingFetchCount: 0,
+ });
+
+ // Clean up by re-enabling the feature for the remaining tasks.
+ fetchPromise = QuickSuggest.weather.waitForFetches();
+ UrlbarPrefs.set("weather.featureGate", true);
+ await fetchPromise;
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// Disables and re-enables the feature without waiting for any intermediate
+// fetches to complete, using the following steps:
+//
+// 1. Disable
+// 2. Enable
+// 3. Disable again
+// 4. Enable again
+//
+// At this point, the fetches from steps 2 and 4 will remain ongoing. The fetch
+// from step 2 should be discarded.
+add_task(async function disableAndEnable_immediate2() {
+ // Sanity check initial state.
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ // Disable the feature. It should be immediately uninitialized.
+ UrlbarPrefs.set("weather.featureGate", false);
+ assertDisabled({
+ message: "After disabling",
+ pendingFetchCount: 0,
+ });
+
+ // Re-enable the feature. It should be immediately initialized and a fetch
+ // should start.
+ UrlbarPrefs.set("weather.featureGate", true);
+ assertEnabled({
+ message: "Immediately after re-enabling",
+ hasSuggestion: false,
+ pendingFetchCount: 1,
+ });
+
+ // Disable it again. The fetch will remain ongoing since pending fetches
+ // aren't stopped when the feature is disabled.
+ UrlbarPrefs.set("weather.featureGate", false);
+ assertDisabled({
+ message: "After disabling again",
+ pendingFetchCount: 1,
+ });
+
+ // Re-enable it. A new fetch should start, so now there will be two pending
+ // fetches.
+ let fetchPromise = QuickSuggest.weather.waitForFetches();
+ UrlbarPrefs.set("weather.featureGate", true);
+ assertEnabled({
+ message: "Immediately after re-enabling again",
+ hasSuggestion: false,
+ pendingFetchCount: 2,
+ });
+
+ // Wait for both fetches to finish.
+ await fetchPromise;
+ assertEnabled({
+ message: "Immediately after re-enabling again",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// A fetch that doesn't return a suggestion should cause the last-fetched
+// suggestion to be discarded.
+add_task(async function noSuggestion() {
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ let histograms = MerinoTestUtils.getAndClearHistograms({
+ extraLatency: HISTOGRAM_LATENCY,
+ extraResponse: HISTOGRAM_RESPONSE,
+ });
+
+ let { suggestions } = MerinoTestUtils.server.response.body;
+ MerinoTestUtils.server.response.body.suggestions = [];
+
+ await QuickSuggest.weather._test_fetch();
+
+ assertEnabled({
+ message: "After fetch",
+ hasSuggestion: false,
+ pendingFetchCount: 0,
+ });
+ Assert.equal(
+ QuickSuggest.weather._test_merino.lastFetchStatus,
+ "no_suggestion",
+ "The request successfully finished without suggestions"
+ );
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: "no_suggestion",
+ latencyRecorded: true,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ MerinoTestUtils.server.response.body.suggestions = suggestions;
+
+ // Clean up by forcing another fetch so the suggestion is non-null for the
+ // remaining tasks.
+ await QuickSuggest.weather._test_fetch();
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// A network error should cause the last-fetched suggestion to be discarded.
+add_task(async function networkError() {
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ let histograms = MerinoTestUtils.getAndClearHistograms({
+ extraLatency: HISTOGRAM_LATENCY,
+ extraResponse: HISTOGRAM_RESPONSE,
+ });
+
+ // Set the weather fetch timeout high enough that the network error exception
+ // will happen first. See `MerinoTestUtils.withNetworkError()`.
+ QuickSuggest.weather._test_setTimeoutMs(10000);
+
+ await MerinoTestUtils.server.withNetworkError(async () => {
+ await QuickSuggest.weather._test_fetch();
+ });
+
+ QuickSuggest.weather._test_setTimeoutMs(-1);
+
+ assertEnabled({
+ message: "After fetch",
+ hasSuggestion: false,
+ pendingFetchCount: 0,
+ });
+ Assert.equal(
+ QuickSuggest.weather._test_merino.lastFetchStatus,
+ "network_error",
+ "The request failed with a network error"
+ );
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: "network_error",
+ latencyRecorded: false,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ // Clean up by forcing another fetch so the suggestion is non-null for the
+ // remaining tasks.
+ await QuickSuggest.weather._test_fetch();
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// An HTTP error should cause the last-fetched suggestion to be discarded.
+add_task(async function httpError() {
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ let histograms = MerinoTestUtils.getAndClearHistograms({
+ extraLatency: HISTOGRAM_LATENCY,
+ extraResponse: HISTOGRAM_RESPONSE,
+ });
+
+ MerinoTestUtils.server.response = { status: 500 };
+ await QuickSuggest.weather._test_fetch();
+
+ assertEnabled({
+ message: "After fetch",
+ hasSuggestion: false,
+ pendingFetchCount: 0,
+ });
+ Assert.equal(
+ QuickSuggest.weather._test_merino.lastFetchStatus,
+ "http_error",
+ "The request failed with an HTTP error"
+ );
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: "http_error",
+ latencyRecorded: true,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ // Clean up by forcing another fetch so the suggestion is non-null for the
+ // remaining tasks.
+ MerinoTestUtils.server.reset();
+ MerinoTestUtils.server.response.body.suggestions = [WEATHER_SUGGESTION];
+ await QuickSuggest.weather._test_fetch();
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// A fetch that doesn't return a suggestion due to a client timeout should cause
+// the last-fetched suggestion to be discarded.
+add_task(async function clientTimeout() {
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ let histograms = MerinoTestUtils.getAndClearHistograms({
+ extraLatency: HISTOGRAM_LATENCY,
+ extraResponse: HISTOGRAM_RESPONSE,
+ });
+
+ // Make the server return a delayed response so the Merino client times out
+ // waiting for it.
+ MerinoTestUtils.server.response.delay = 400;
+
+ // Make the client time out immediately.
+ QuickSuggest.weather._test_setTimeoutMs(1);
+
+ // Set up a promise that will be resolved when the client finally receives the
+ // response.
+ let responsePromise = QuickSuggest.weather._test_merino.waitForNextResponse();
+
+ await QuickSuggest.weather._test_fetch();
+
+ assertEnabled({
+ message: "After fetch",
+ hasSuggestion: false,
+ pendingFetchCount: 0,
+ });
+ Assert.equal(
+ QuickSuggest.weather._test_merino.lastFetchStatus,
+ "timeout",
+ "The request timed out"
+ );
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: "timeout",
+ latencyRecorded: false,
+ latencyStopwatchRunning: true,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ // Await the response.
+ await responsePromise;
+
+ // The `checkAndClearHistograms()` call above cleared the histograms. After
+ // that, nothing else should have been recorded for the response.
+ MerinoTestUtils.checkAndClearHistograms({
+ histograms,
+ response: null,
+ latencyRecorded: true,
+ client: QuickSuggest.weather._test_merino,
+ });
+
+ QuickSuggest.weather._test_setTimeoutMs(-1);
+ delete MerinoTestUtils.server.response.delay;
+
+ // Clean up by forcing another fetch so the suggestion is non-null for the
+ // remaining tasks.
+ await QuickSuggest.weather._test_fetch();
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+// Locale task for when this test runs on an en-US OS.
+add_task(async function locale_enUS() {
+ await doLocaleTest({
+ shouldRunTask: osLocale => osLocale == "en-US",
+ osUnit: "f",
+ unitsByLocale: {
+ "en-US": "f",
+ // When the app's locale is set to any en-* locale, F will be used because
+ // `regionalPrefsLocales` will prefer the en-US OS locale.
+ "en-CA": "f",
+ "en-GB": "f",
+ de: "c",
+ },
+ });
+});
+
+// Locale task for when this test runs on a non-US English OS.
+add_task(async function locale_nonUSEnglish() {
+ await doLocaleTest({
+ shouldRunTask: osLocale => osLocale.startsWith("en") && osLocale != "en-US",
+ osUnit: "c",
+ unitsByLocale: {
+ // When the app's locale is set to en-US, C will be used because
+ // `regionalPrefsLocales` will prefer the non-US English OS locale.
+ "en-US": "c",
+ "en-CA": "c",
+ "en-GB": "c",
+ de: "c",
+ },
+ });
+});
+
+// Locale task for when this test runs on a non-English OS.
+add_task(async function locale_nonEnglish() {
+ await doLocaleTest({
+ shouldRunTask: osLocale => !osLocale.startsWith("en"),
+ osUnit: "c",
+ unitsByLocale: {
+ "en-US": "f",
+ "en-CA": "c",
+ "en-GB": "c",
+ de: "c",
+ },
+ });
+});
+
+/**
+ * Testing locales is tricky due to the weather feature's use of
+ * `Services.locale.regionalPrefsLocales`. By default `regionalPrefsLocales`
+ * prefers the OS locale if its language is the same as the app locale's
+ * language; otherwise it prefers the app locale. For example, assuming the OS
+ * locale is en-CA, then if the app locale is en-US it will prefer en-CA since
+ * both are English, but if the app locale is de it will prefer de. If the pref
+ * `intl.regional_prefs.use_os_locales` is set, then the OS locale is always
+ * preferred.
+ *
+ * This function tests a given set of locales with and without
+ * `intl.regional_prefs.use_os_locales` set.
+ *
+ * @param {object} options
+ * Options
+ * @param {Function} options.shouldRunTask
+ * Called with the OS locale. Should return true if the function should run.
+ * Use this to skip tasks that don't target a desired OS locale.
+ * @param {string} options.osUnit
+ * The expected "c" or "f" unit for the OS locale.
+ * @param {object} options.unitsByLocale
+ * The expected "c" or "f" unit when the app's locale is set to particular
+ * locales. This should be an object that maps locales to expected units. For
+ * each locale in the object, the app's locale is set to that locale and the
+ * actual unit is expected to be the unit in the object.
+ */
+async function doLocaleTest({ shouldRunTask, osUnit, unitsByLocale }) {
+ Services.prefs.setBoolPref("intl.regional_prefs.use_os_locales", true);
+ let osLocale = Services.locale.regionalPrefsLocales[0];
+ Services.prefs.clearUserPref("intl.regional_prefs.use_os_locales");
+
+ if (!shouldRunTask(osLocale)) {
+ info("Skipping task, should not run for this OS locale");
+ return;
+ }
+
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ // Sanity check initial locale info.
+ Assert.equal(
+ Services.locale.appLocaleAsBCP47,
+ "en-US",
+ "Initial app locale should be en-US"
+ );
+ Assert.ok(
+ !Services.prefs.getBoolPref("intl.regional_prefs.use_os_locales"),
+ "intl.regional_prefs.use_os_locales should be false initially"
+ );
+
+ // Check locales.
+ for (let [locale, expectedUnit] of Object.entries(unitsByLocale)) {
+ await QuickSuggestTestUtils.withLocales([locale], async () => {
+ info("Checking locale: " + locale);
+ await check_results({
+ context: createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ }),
+ matches: [makeExpectedResult(expectedUnit)],
+ });
+
+ info(
+ "Checking locale with intl.regional_prefs.use_os_locales: " + locale
+ );
+ Services.prefs.setBoolPref("intl.regional_prefs.use_os_locales", true);
+ await check_results({
+ context: createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ }),
+ matches: [makeExpectedResult(osUnit)],
+ });
+ Services.prefs.clearUserPref("intl.regional_prefs.use_os_locales");
+ });
+ }
+}
+
+// A weather suggestion should not be returned for a non-empty search string.
+add_task(async function nonEmptySearchString() {
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+
+ // Do a search.
+ let context = createContext("this shouldn't match anything", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+});
+
+// Blocks a result and makes sure the weather pref is disabled.
+add_task(async function block() {
+ // Sanity check initial state.
+ assertEnabled({
+ message: "Sanity check initial state",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+ Assert.ok(
+ UrlbarPrefs.get("suggest.weather"),
+ "Sanity check: suggest.weather is true initially"
+ );
+
+ // Do a search so we can get an actual result.
+ let context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [makeExpectedResult()],
+ });
+
+ // Block the result.
+ UrlbarProviderQuickSuggest.blockResult(context, context.results[0]);
+ Assert.ok(
+ !UrlbarPrefs.get("suggest.weather"),
+ "suggest.weather is false after blocking the result"
+ );
+
+ // Do a second search. Nothing should be returned.
+ context = createContext("", {
+ providers: [UrlbarProviderQuickSuggest.name],
+ isPrivate: false,
+ });
+ await check_results({
+ context,
+ matches: [],
+ });
+
+ // Re-enable the pref and clean up.
+ let fetchPromise = QuickSuggest.weather.waitForFetches();
+ UrlbarPrefs.set("suggest.weather", true);
+ await fetchPromise;
+ assertEnabled({
+ message: "On cleanup",
+ hasSuggestion: true,
+ pendingFetchCount: 0,
+ });
+});
+
+function assertEnabled({ message, hasSuggestion, pendingFetchCount }) {
+ info("Asserting feature is enabled");
+ if (message) {
+ info(message);
+ }
+
+ Assert.equal(
+ !!QuickSuggest.weather.suggestion,
+ hasSuggestion,
+ "Suggestion is null or non-null as expected"
+ );
+ Assert.notEqual(
+ QuickSuggest.weather._test_fetchInterval,
+ 0,
+ "Fetch interval is non-zero"
+ );
+ Assert.ok(QuickSuggest.weather._test_merino, "Merino client is non-null");
+ Assert.equal(
+ QuickSuggest.weather._test_pendingFetchCount,
+ pendingFetchCount,
+ "Expected pending fetch count"
+ );
+}
+
+function assertDisabled({ message, pendingFetchCount }) {
+ info("Asserting feature is disabled");
+ if (message) {
+ info(message);
+ }
+
+ Assert.strictEqual(
+ QuickSuggest.weather.suggestion,
+ null,
+ "Suggestion is null"
+ );
+ Assert.strictEqual(
+ QuickSuggest.weather._test_fetchInterval,
+ 0,
+ "Fetch interval is zero"
+ );
+ Assert.strictEqual(
+ QuickSuggest.weather._test_merino,
+ null,
+ "Merino client is null"
+ );
+ Assert.equal(
+ QuickSuggest.weather._test_pendingFetchCount,
+ pendingFetchCount,
+ "Expected pending fetch count"
+ );
+}
+
+function makeExpectedResult(temperatureUnit = undefined) {
+ if (!temperatureUnit) {
+ temperatureUnit =
+ Services.locale.regionalPrefsLocales[0] == "en-US" ? "f" : "c";
+ }
+
+ return {
+ type: UrlbarUtils.RESULT_TYPE.DYNAMIC,
+ source: UrlbarUtils.RESULT_SOURCE.SEARCH,
+ heuristic: false,
+ payload: {
+ temperatureUnit,
+ url: WEATHER_SUGGESTION.url,
+ iconId: "6",
+ helpUrl: QuickSuggest.HELP_URL,
+ helpL10n: {
+ id: "firefox-suggest-urlbar-learn-more",
+ },
+ isBlockable: true,
+ blockL10n: {
+ id: "firefox-suggest-urlbar-block",
+ },
+ requestId: MerinoTestUtils.server.response.body.request_id,
+ source: "merino",
+ merinoProvider: "accuweather",
+ dynamicType: "weather",
+ city: WEATHER_SUGGESTION.city_name,
+ temperature:
+ WEATHER_SUGGESTION.current_conditions.temperature[temperatureUnit],
+ currentConditions: WEATHER_SUGGESTION.current_conditions.summary,
+ forecast: WEATHER_SUGGESTION.forecast.summary,
+ high: WEATHER_SUGGESTION.forecast.high[temperatureUnit],
+ low: WEATHER_SUGGESTION.forecast.low[temperatureUnit],
+ isWeather: true,
+ shouldNavigate: true,
+ },
+ };
+}