From 9e3c08db40b8916968b9f30096c7be3f00ce9647 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 21 Apr 2024 13:44:51 +0200 Subject: Adding upstream version 1:115.7.0. Signed-off-by: Daniel Baumann --- browser/components/search/.eslintrc.js | 13 + .../search/BrowserSearchTelemetry.sys.mjs | 293 +++++ browser/components/search/SearchOneOffs.sys.mjs | 1130 +++++++++++++++++ .../components/search/SearchSERPTelemetry.sys.mjs | 1312 ++++++++++++++++++++ browser/components/search/SearchUIUtils.sys.mjs | 122 ++ .../search/content/autocomplete-popup.js | 289 +++++ .../search/content/contentSearchHandoffUI.js | 152 +++ .../components/search/content/contentSearchUI.css | 160 +++ .../components/search/content/contentSearchUI.js | 1021 +++++++++++++++ browser/components/search/content/searchbar.js | 895 +++++++++++++ browser/components/search/docs/Preferences.rst | 28 + .../search/docs/application-search-engines.rst | 41 + browser/components/search/docs/index.rst | 23 + browser/components/search/docs/telemetry.rst | 183 +++ .../components/search/extensions/1und1/favicon.ico | Bin 0 -> 159 bytes .../search/extensions/1und1/manifest.json | 24 + .../search/extensions/allegro-pl/favicon.ico | Bin 0 -> 1150 bytes .../search/extensions/allegro-pl/manifest.json | 24 + .../extensions/amazon/_locales/au/messages.json | 23 + .../extensions/amazon/_locales/ca/messages.json | 23 + .../extensions/amazon/_locales/de/messages.json | 23 + .../extensions/amazon/_locales/en-GB/messages.json | 23 + .../amazon/_locales/france/messages.json | 23 + .../extensions/amazon/_locales/in/messages.json | 23 + .../extensions/amazon/_locales/it/messages.json | 23 + .../extensions/amazon/_locales/jp/messages.json | 23 + .../extensions/amazon/_locales/nl/messages.json | 23 + .../extensions/amazon/_locales/spain/messages.json | 23 + .../amazon/_locales/sweden/messages.json | 23 + .../search/extensions/amazon/favicon.ico | Bin 0 -> 1407 bytes .../search/extensions/amazon/manifest.json | 28 + .../amazondotcn/_locales/default/messages.json | 8 + .../_locales/mozillaonline/messages.json | 8 + .../search/extensions/amazondotcn/favicon.ico | Bin 0 -> 1407 bytes .../search/extensions/amazondotcn/manifest.json | 26 + .../amazondotcom/_locales/en/messages.json | 20 + .../amazondotcom/_locales/us/messages.json | 20 + .../search/extensions/amazondotcom/favicon.ico | Bin 0 -> 1407 bytes .../search/extensions/amazondotcom/manifest.json | 27 + .../search/extensions/azerdict/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/azerdict/manifest.json | 26 + .../components/search/extensions/baidu/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/baidu/manifest.json | 27 + .../components/search/extensions/bing/favicon.ico | Bin 0 -> 4286 bytes .../search/extensions/bing/manifest.json | 59 + .../search/extensions/bok-NO/favicon.png | Bin 0 -> 530 bytes .../search/extensions/bok-NO/manifest.json | 24 + .../search/extensions/ceneji/favicon.png | Bin 0 -> 283 bytes .../search/extensions/ceneji/manifest.json | 24 + .../search/extensions/coccoc/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/coccoc/manifest.json | 25 + .../search/extensions/daum-kr/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/daum-kr/manifest.json | 26 + .../components/search/extensions/ddg/favicon.ico | Bin 0 -> 2799 bytes .../components/search/extensions/ddg/manifest.json | 27 + .../extensions/ebay/_locales/at/messages.json | 20 + .../extensions/ebay/_locales/au/messages.json | 20 + .../extensions/ebay/_locales/be/messages.json | 20 + .../extensions/ebay/_locales/ca/messages.json | 20 + .../extensions/ebay/_locales/ch/messages.json | 20 + .../extensions/ebay/_locales/de/messages.json | 20 + .../extensions/ebay/_locales/en/messages.json | 20 + .../extensions/ebay/_locales/es/messages.json | 20 + .../extensions/ebay/_locales/fr/messages.json | 20 + .../extensions/ebay/_locales/ie/messages.json | 20 + .../extensions/ebay/_locales/it/messages.json | 20 + .../extensions/ebay/_locales/nl/messages.json | 20 + .../extensions/ebay/_locales/uk/messages.json | 20 + .../components/search/extensions/ebay/favicon.ico | Bin 0 -> 1455 bytes .../search/extensions/ebay/manifest.json | 28 + .../search/extensions/ecosia/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/ecosia/manifest.json | 26 + .../search/extensions/eudict/favicon.ico | Bin 0 -> 1785 bytes .../search/extensions/eudict/manifest.json | 24 + .../search/extensions/faclair-beag/favicon.ico | Bin 0 -> 1091 bytes .../search/extensions/faclair-beag/manifest.json | 23 + .../extensions/gmx/_locales/de/messages.json | 17 + .../extensions/gmx/_locales/en-GB/messages.json | 17 + .../extensions/gmx/_locales/es/messages.json | 17 + .../extensions/gmx/_locales/fr/messages.json | 17 + .../extensions/gmx/_locales/shopping/messages.json | 17 + .../components/search/extensions/gmx/favicon.png | Bin 0 -> 1122 bytes .../components/search/extensions/gmx/manifest.json | 26 + .../extensions/google/_locales/en/messages.json | 23 + .../google/_locales/region-by/messages.json | 20 + .../google/_locales/region-kz/messages.json | 20 + .../google/_locales/region-ru/messages.json | 20 + .../google/_locales/region-tr/messages.json | 20 + .../search/extensions/google/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/google/manifest.json | 34 + .../search/extensions/gulesider-NO/favicon.ico | Bin 0 -> 1150 bytes .../search/extensions/gulesider-NO/manifest.json | 24 + .../search/extensions/leo_ende_de/favicon.png | Bin 0 -> 749 bytes .../search/extensions/leo_ende_de/manifest.json | 25 + .../search/extensions/longdo/favicon.ico | Bin 0 -> 252 bytes .../search/extensions/longdo/manifest.json | 26 + .../search/extensions/mailcom/favicon.ico | Bin 0 -> 1150 bytes .../search/extensions/mailcom/manifest.json | 25 + .../mailru/_locales/default/messages.json | 11 + .../mailru/_locales/mailru001/messages.json | 11 + .../mailru/_locales/okru-az/messages.json | 11 + .../mailru/_locales/okru-en-US/messages.json | 11 + .../mailru/_locales/okru-hy-AM/messages.json | 11 + .../mailru/_locales/okru-kk/messages.json | 11 + .../mailru/_locales/okru-ro/messages.json | 11 + .../mailru/_locales/okru-ru/messages.json | 11 + .../mailru/_locales/okru-tr/messages.json | 11 + .../mailru/_locales/okru-uk/messages.json | 11 + .../mailru/_locales/okru-uz/messages.json | 11 + .../search/extensions/mailru/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/mailru/manifest.json | 27 + .../search/extensions/mapy-cz/favicon.ico | Bin 0 -> 1812 bytes .../search/extensions/mapy-cz/manifest.json | 24 + .../mercadolibre/_locales/ar/messages.json | 17 + .../mercadolibre/_locales/cl/messages.json | 17 + .../mercadolibre/_locales/mx/messages.json | 17 + .../search/extensions/mercadolibre/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/mercadolibre/manifest.json | 25 + .../search/extensions/mercadolivre/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/mercadolivre/manifest.json | 24 + .../search/extensions/naver-kr/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/naver-kr/manifest.json | 26 + .../search/extensions/odpiralni/favicon.png | Bin 0 -> 2639 bytes .../search/extensions/odpiralni/manifest.json | 23 + .../search/extensions/pazaruvaj/favicon.ico | Bin 0 -> 2584 bytes .../search/extensions/pazaruvaj/manifest.json | 24 + .../search/extensions/priberam/favicon.png | Bin 0 -> 790 bytes .../search/extensions/priberam/manifest.json | 25 + .../search/extensions/prisjakt-sv-SE/favicon.ico | Bin 0 -> 1406 bytes .../search/extensions/prisjakt-sv-SE/manifest.json | 26 + .../components/search/extensions/qwant/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/qwant/manifest.json | 26 + .../search/extensions/qwantjr/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/qwantjr/manifest.json | 25 + .../search/extensions/rakuten/favicon.ico | Bin 0 -> 2053 bytes .../search/extensions/rakuten/manifest.json | 25 + .../search/extensions/readmoo/favicon.ico | Bin 0 -> 2468 bytes .../search/extensions/readmoo/manifest.json | 24 + .../search/extensions/salidzinilv/favicon.ico | Bin 0 -> 3638 bytes .../search/extensions/salidzinilv/manifest.json | 26 + .../search/extensions/seznam-cz/favicon.ico | Bin 0 -> 1743 bytes .../search/extensions/seznam-cz/manifest.json | 26 + .../search/extensions/tyda-sv-SE/favicon.ico | Bin 0 -> 379 bytes .../search/extensions/tyda-sv-SE/manifest.json | 24 + .../search/extensions/vatera/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/vatera/manifest.json | 25 + .../components/search/extensions/webde/favicon.ico | Bin 0 -> 3638 bytes .../search/extensions/webde/manifest.json | 24 + .../extensions/wikipedia/_locales/NN/messages.json | 20 + .../extensions/wikipedia/_locales/NO/messages.json | 20 + .../extensions/wikipedia/_locales/af/messages.json | 20 + .../extensions/wikipedia/_locales/an/messages.json | 20 + .../extensions/wikipedia/_locales/ar/messages.json | 20 + .../wikipedia/_locales/ast/messages.json | 20 + .../extensions/wikipedia/_locales/az/messages.json | 20 + .../wikipedia/_locales/be-tarask/messages.json | 20 + .../extensions/wikipedia/_locales/be/messages.json | 20 + .../extensions/wikipedia/_locales/bg/messages.json | 20 + .../extensions/wikipedia/_locales/bn/messages.json | 20 + .../extensions/wikipedia/_locales/br/messages.json | 20 + .../extensions/wikipedia/_locales/bs/messages.json | 20 + .../extensions/wikipedia/_locales/ca/messages.json | 20 + .../extensions/wikipedia/_locales/cy/messages.json | 20 + .../extensions/wikipedia/_locales/cz/messages.json | 20 + .../extensions/wikipedia/_locales/da/messages.json | 20 + .../extensions/wikipedia/_locales/de/messages.json | 20 + .../wikipedia/_locales/dsb/messages.json | 20 + .../extensions/wikipedia/_locales/el/messages.json | 20 + .../extensions/wikipedia/_locales/en/messages.json | 20 + .../extensions/wikipedia/_locales/eo/messages.json | 20 + .../extensions/wikipedia/_locales/es/messages.json | 20 + .../extensions/wikipedia/_locales/et/messages.json | 20 + .../extensions/wikipedia/_locales/eu/messages.json | 20 + .../extensions/wikipedia/_locales/fa/messages.json | 20 + .../extensions/wikipedia/_locales/fi/messages.json | 20 + .../extensions/wikipedia/_locales/fr/messages.json | 20 + .../wikipedia/_locales/fy-NL/messages.json | 20 + .../wikipedia/_locales/ga-IE/messages.json | 20 + .../extensions/wikipedia/_locales/gd/messages.json | 20 + .../extensions/wikipedia/_locales/gl/messages.json | 20 + .../extensions/wikipedia/_locales/gn/messages.json | 20 + .../extensions/wikipedia/_locales/gu/messages.json | 20 + .../extensions/wikipedia/_locales/he/messages.json | 20 + .../extensions/wikipedia/_locales/hi/messages.json | 20 + .../extensions/wikipedia/_locales/hr/messages.json | 20 + .../wikipedia/_locales/hsb/messages.json | 20 + .../extensions/wikipedia/_locales/hu/messages.json | 20 + .../extensions/wikipedia/_locales/hy/messages.json | 20 + .../extensions/wikipedia/_locales/ia/messages.json | 20 + .../extensions/wikipedia/_locales/id/messages.json | 20 + .../extensions/wikipedia/_locales/is/messages.json | 20 + .../extensions/wikipedia/_locales/it/messages.json | 20 + .../extensions/wikipedia/_locales/ja/messages.json | 20 + .../extensions/wikipedia/_locales/ka/messages.json | 20 + .../wikipedia/_locales/kab/messages.json | 20 + .../extensions/wikipedia/_locales/kk/messages.json | 20 + .../extensions/wikipedia/_locales/km/messages.json | 20 + .../extensions/wikipedia/_locales/kn/messages.json | 20 + .../extensions/wikipedia/_locales/kr/messages.json | 20 + .../wikipedia/_locales/lij/messages.json | 20 + .../extensions/wikipedia/_locales/lo/messages.json | 20 + .../extensions/wikipedia/_locales/lt/messages.json | 20 + .../wikipedia/_locales/ltg/messages.json | 20 + .../extensions/wikipedia/_locales/lv/messages.json | 20 + .../extensions/wikipedia/_locales/mk/messages.json | 20 + .../extensions/wikipedia/_locales/mr/messages.json | 20 + .../extensions/wikipedia/_locales/ms/messages.json | 20 + .../extensions/wikipedia/_locales/my/messages.json | 20 + .../extensions/wikipedia/_locales/ne/messages.json | 20 + .../extensions/wikipedia/_locales/nl/messages.json | 20 + .../extensions/wikipedia/_locales/oc/messages.json | 20 + .../extensions/wikipedia/_locales/pa/messages.json | 20 + .../extensions/wikipedia/_locales/pl/messages.json | 20 + .../extensions/wikipedia/_locales/pt/messages.json | 20 + .../extensions/wikipedia/_locales/rm/messages.json | 20 + .../extensions/wikipedia/_locales/ro/messages.json | 20 + .../extensions/wikipedia/_locales/ru/messages.json | 20 + .../extensions/wikipedia/_locales/si/messages.json | 20 + .../extensions/wikipedia/_locales/sk/messages.json | 20 + .../extensions/wikipedia/_locales/sl/messages.json | 20 + .../extensions/wikipedia/_locales/sq/messages.json | 20 + .../extensions/wikipedia/_locales/sr/messages.json | 20 + .../wikipedia/_locales/sv-SE/messages.json | 20 + .../extensions/wikipedia/_locales/ta/messages.json | 20 + .../extensions/wikipedia/_locales/te/messages.json | 20 + .../extensions/wikipedia/_locales/th/messages.json | 20 + .../extensions/wikipedia/_locales/tl/messages.json | 20 + .../extensions/wikipedia/_locales/tr/messages.json | 20 + .../extensions/wikipedia/_locales/uk/messages.json | 20 + .../extensions/wikipedia/_locales/ur/messages.json | 20 + .../extensions/wikipedia/_locales/uz/messages.json | 20 + .../extensions/wikipedia/_locales/vi/messages.json | 20 + .../extensions/wikipedia/_locales/wo/messages.json | 20 + .../wikipedia/_locales/zh-CN/messages.json | 20 + .../wikipedia/_locales/zh-TW/messages.json | 20 + .../search/extensions/wikipedia/favicon.ico | Bin 0 -> 884 bytes .../search/extensions/wikipedia/manifest.json | 27 + .../wiktionary/_locales/oc/messages.json | 20 + .../wiktionary/_locales/te/messages.json | 20 + .../search/extensions/wiktionary/favicon.ico | Bin 0 -> 318 bytes .../search/extensions/wiktionary/manifest.json | 26 + .../search/extensions/wolnelektury-pl/favicon.png | Bin 0 -> 304 bytes .../extensions/wolnelektury-pl/manifest.json | 24 + .../extensions/yahoo-jp-auctions/favicon.ico | Bin 0 -> 2672 bytes .../extensions/yahoo-jp-auctions/manifest.json | 25 + .../search/extensions/yahoo-jp/favicon.ico | Bin 0 -> 5430 bytes .../search/extensions/yahoo-jp/manifest.json | 24 + .../extensions/yandex/_locales/az/messages.json | 38 + .../extensions/yandex/_locales/by/messages.json | 38 + .../extensions/yandex/_locales/en/messages.json | 38 + .../extensions/yandex/_locales/kk/messages.json | 38 + .../extensions/yandex/_locales/ru/messages.json | 38 + .../extensions/yandex/_locales/tr/messages.json | 38 + .../extensions/yandex/_locales/ua/messages.json | 23 + .../search/extensions/yandex/manifest.json | 59 + .../search/extensions/yandex/yandex-en.ico | Bin 0 -> 1338 bytes .../search/extensions/yandex/yandex-ru.ico | Bin 0 -> 1368 bytes browser/components/search/jar.mn | 13 + browser/components/search/metrics.yaml | 313 +++++ browser/components/search/moz.build | 28 + browser/components/search/schema/Readme.txt | 7 + .../search/schema/search-telemetry-schema.json | 341 +++++ .../search/schema/search-telemetry-ui-schema.json | 20 + browser/components/search/test/browser/426329.xml | 11 + .../components/search/test/browser/483086-1.xml | 10 + .../components/search/test/browser/483086-2.xml | 10 + browser/components/search/test/browser/browser.ini | 176 +++ .../search/test/browser/browser_426329.js | 335 +++++ .../search/test/browser/browser_483086.js | 56 + .../test/browser/browser_addKeywordSearch.js | 89 ++ .../test/browser/browser_contentContextMenu.js | 230 ++++ .../test/browser/browser_contentContextMenu.xhtml | 22 + .../search/test/browser/browser_contentSearchUI.js | 1158 +++++++++++++++++ .../browser/browser_contentSearchUI_default.js | 210 ++++ .../browser/browser_contextSearchTabPosition.js | 94 ++ .../search/test/browser/browser_contextmenu.js | 249 ++++ .../browser/browser_contextmenu_whereToOpenLink.js | 183 +++ .../test/browser/browser_defaultPrivate_nimbus.js | 155 +++ .../search/test/browser/browser_google_behavior.js | 215 ++++ .../test/browser/browser_hiddenOneOffs_cleanup.js | 117 ++ .../browser/browser_hiddenOneOffs_diacritics.js | 74 ++ .../search/test/browser/browser_ime_composition.js | 77 ++ .../test/browser/browser_oneOffContextMenu.js | 89 ++ .../browser_oneOffContextMenu_setDefault.js | 236 ++++ .../browser/browser_private_search_perwindowpb.js | 84 ++ .../test/browser/browser_rich_suggestions.js | 110 ++ .../test/browser/browser_searchEngine_behaviors.js | 223 ++++ .../test/browser/browser_search_annotation.js | 176 +++ .../test/browser/browser_search_discovery.js | 132 ++ ...an_serp_telemetry_enabled_by_nimbus_variable.js | 159 +++ .../test/browser/browser_search_nimbus_reload.js | 55 + .../browser_search_telemetry_abandonment.js | 243 ++++ .../browser/browser_search_telemetry_aboutHome.js | 135 ++ ...wser_search_telemetry_adImpression_component.js | 401 ++++++ ...owser_search_telemetry_categorization_timing.js | 107 ++ .../browser/browser_search_telemetry_content.js | 204 +++ .../browser_search_telemetry_engagement_cached.js | 199 +++ ...wser_search_telemetry_engagement_cached_serp.js | 239 ++++ .../browser_search_telemetry_engagement_content.js | 486 ++++++++ ...er_search_telemetry_engagement_multiple_tabs.js | 225 ++++ .../browser_search_telemetry_engagement_non_ad.js | 164 +++ ...browser_search_telemetry_engagement_redirect.js | 346 ++++++ .../browser_search_telemetry_engagement_target.js | 433 +++++++ .../browser/browser_search_telemetry_searchbar.js | 440 +++++++ .../browser/browser_search_telemetry_shopping.js | 149 +++ .../browser/browser_search_telemetry_sources.js | 497 ++++++++ .../browser_search_telemetry_sources_ads.js | 841 +++++++++++++ .../browser_search_telemetry_sources_in_content.js | 435 +++++++ .../browser_search_telemetry_sources_navigation.js | 549 ++++++++ .../test/browser/browser_searchbar_addEngine.js | 99 ++ .../test/browser/browser_searchbar_context.js | 246 ++++ .../test/browser/browser_searchbar_default.js | 221 ++++ .../search/test/browser/browser_searchbar_enter.js | 152 +++ .../browser_searchbar_keyboard_navigation.js | 644 ++++++++++ .../test/browser/browser_searchbar_openpopup.js | 794 ++++++++++++ .../test/browser/browser_searchbar_results.js | 60 + ...ser_searchbar_smallpanel_keyboard_navigation.js | 449 +++++++ .../test/browser/browser_searchbar_widths.js | 33 + .../test/browser/browser_tooManyEnginesOffered.js | 68 + .../test/browser/browser_trending_suggestions.js | 189 +++ .../components/search/test/browser/cacheable.html | 12 + .../search/test/browser/cacheable.html^headers^ | 1 + .../search/test/browser/contentSearchUI.html | 22 + .../search/test/browser/contentSearchUI.js | 13 + .../components/search/test/browser/discovery.html | 9 + .../search/test/browser/google_codes/browser.ini | 5 + browser/components/search/test/browser/head.js | 395 ++++++ .../components/search/test/browser/mozsearch.sjs | 11 + .../components/search/test/browser/opensearch.html | 10 + .../components/search/test/browser/redirect_ad.sjs | 10 + .../search/test/browser/redirect_final.sjs | 9 + .../search/test/browser/redirect_once.sjs | 9 + .../search/test/browser/redirect_thrice.sjs | 9 + .../search/test/browser/redirect_twice.sjs | 9 + .../browser/search-engines/basic/manifest.json | 20 + .../browser/search-engines/private/manifest.json | 20 + .../search/test/browser/searchSuggestionEngine.sjs | 55 + .../search/test/browser/searchTelemetry.html | 11 + .../search/test/browser/searchTelemetryAd.html | 13 + .../searchTelemetryAd_components_carousel.html | 116 ++ ...metryAd_components_carousel_below_the_fold.html | 83 ++ ...rchTelemetryAd_components_carousel_doubled.html | 182 +++ ...ponents_carousel_first_element_non_visible.html | 85 ++ ...archTelemetryAd_components_carousel_hidden.html | 87 ++ ...etryAd_components_carousel_outer_container.html | 83 ++ .../browser/searchTelemetryAd_components_text.html | 112 ++ .../searchTelemetryAd_components_visibility.html | 46 + .../browser/searchTelemetryAd_dataAttributes.html | 10 + .../searchTelemetryAd_dataAttributes_href.html | 10 + .../searchTelemetryAd_dataAttributes_none.html | 10 + .../searchTelemetryAd_nonAdsLink_redirect.html | 12 + ...chTelemetryAd_nonAdsLink_redirect.html^headers^ | 1 + ...lemetryAd_nonAdsLink_redirect_nonTopLoaded.html | 17 + ..._nonAdsLink_redirect_nonTopLoaded.html^headers^ | 4 + .../test/browser/searchTelemetryAd_searchbox.html | 38 + .../searchTelemetryAd_searchbox.html^headers^ | 1 + .../searchTelemetryAd_searchbox_with_content.html | 39 + ...elemetryAd_searchbox_with_content.html^headers^ | 1 + ...elemetryAd_searchbox_with_content_redirect.html | 12 + ...d_searchbox_with_content_redirect.html^headers^ | 1 + .../test/browser/searchTelemetryAd_shopping.html | 15 + browser/components/search/test/browser/serp.css | 164 +++ .../test/browser/slow_loading_page_with_ads.html | 14 + .../test/browser/slow_loading_page_with_ads.sjs | 21 + .../slow_loading_page_with_ads_on_load_event.html | 30 + .../test/browser/telemetrySearchSuggestions.sjs | 9 + .../test/browser/telemetrySearchSuggestions.xml | 6 + browser/components/search/test/browser/test.html | 8 + .../components/search/test/browser/testEngine.xml | 12 + .../search/test/browser/testEngine_diacritics.xml | 12 + .../search/test/browser/testEngine_dupe.xml | 12 + .../search/test/browser/testEngine_mozsearch.xml | 14 + .../search/test/browser/test_search.html | 1 + .../search/test/browser/tooManyEnginesOffered.html | 13 + .../test/browser/trendingSuggestionEngine.sjs | 51 + .../components/search/test/marionette/manifest.ini | 4 + .../test/marionette/test_engines_on_restart.py | 40 + .../test_search_telemetry_config_validation.js | 82 ++ .../search/test/unit/test_urlTelemetry.js | 310 +++++ .../search/test/unit/test_urlTelemetry_generic.js | 323 +++++ browser/components/search/test/unit/xpcshell.ini | 9 + 381 files changed, 27132 insertions(+) create mode 100644 browser/components/search/.eslintrc.js create mode 100644 browser/components/search/BrowserSearchTelemetry.sys.mjs create mode 100644 browser/components/search/SearchOneOffs.sys.mjs create mode 100644 browser/components/search/SearchSERPTelemetry.sys.mjs create mode 100644 browser/components/search/SearchUIUtils.sys.mjs create mode 100644 browser/components/search/content/autocomplete-popup.js create mode 100644 browser/components/search/content/contentSearchHandoffUI.js create mode 100644 browser/components/search/content/contentSearchUI.css create mode 100644 browser/components/search/content/contentSearchUI.js create mode 100644 browser/components/search/content/searchbar.js create mode 100644 browser/components/search/docs/Preferences.rst create mode 100644 browser/components/search/docs/application-search-engines.rst create mode 100644 browser/components/search/docs/index.rst create mode 100644 browser/components/search/docs/telemetry.rst create mode 100644 browser/components/search/extensions/1und1/favicon.ico create mode 100644 browser/components/search/extensions/1und1/manifest.json create mode 100644 browser/components/search/extensions/allegro-pl/favicon.ico create mode 100644 browser/components/search/extensions/allegro-pl/manifest.json create mode 100644 browser/components/search/extensions/amazon/_locales/au/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/ca/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/de/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/en-GB/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/france/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/in/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/it/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/jp/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/nl/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/spain/messages.json create mode 100644 browser/components/search/extensions/amazon/_locales/sweden/messages.json create mode 100644 browser/components/search/extensions/amazon/favicon.ico create mode 100644 browser/components/search/extensions/amazon/manifest.json create mode 100644 browser/components/search/extensions/amazondotcn/_locales/default/messages.json create mode 100644 browser/components/search/extensions/amazondotcn/_locales/mozillaonline/messages.json create mode 100644 browser/components/search/extensions/amazondotcn/favicon.ico create mode 100644 browser/components/search/extensions/amazondotcn/manifest.json create mode 100644 browser/components/search/extensions/amazondotcom/_locales/en/messages.json create mode 100644 browser/components/search/extensions/amazondotcom/_locales/us/messages.json create mode 100644 browser/components/search/extensions/amazondotcom/favicon.ico create mode 100644 browser/components/search/extensions/amazondotcom/manifest.json create mode 100644 browser/components/search/extensions/azerdict/favicon.ico create mode 100644 browser/components/search/extensions/azerdict/manifest.json create mode 100644 browser/components/search/extensions/baidu/favicon.ico create mode 100644 browser/components/search/extensions/baidu/manifest.json create mode 100644 browser/components/search/extensions/bing/favicon.ico create mode 100644 browser/components/search/extensions/bing/manifest.json create mode 100644 browser/components/search/extensions/bok-NO/favicon.png create mode 100644 browser/components/search/extensions/bok-NO/manifest.json create mode 100644 browser/components/search/extensions/ceneji/favicon.png create mode 100644 browser/components/search/extensions/ceneji/manifest.json create mode 100644 browser/components/search/extensions/coccoc/favicon.ico create mode 100644 browser/components/search/extensions/coccoc/manifest.json create mode 100644 browser/components/search/extensions/daum-kr/favicon.ico create mode 100644 browser/components/search/extensions/daum-kr/manifest.json create mode 100644 browser/components/search/extensions/ddg/favicon.ico create mode 100644 browser/components/search/extensions/ddg/manifest.json create mode 100644 browser/components/search/extensions/ebay/_locales/at/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/au/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/be/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/ca/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/ch/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/de/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/en/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/es/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/fr/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/ie/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/it/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/nl/messages.json create mode 100644 browser/components/search/extensions/ebay/_locales/uk/messages.json create mode 100644 browser/components/search/extensions/ebay/favicon.ico create mode 100644 browser/components/search/extensions/ebay/manifest.json create mode 100644 browser/components/search/extensions/ecosia/favicon.ico create mode 100644 browser/components/search/extensions/ecosia/manifest.json create mode 100644 browser/components/search/extensions/eudict/favicon.ico create mode 100644 browser/components/search/extensions/eudict/manifest.json create mode 100644 browser/components/search/extensions/faclair-beag/favicon.ico create mode 100644 browser/components/search/extensions/faclair-beag/manifest.json create mode 100644 browser/components/search/extensions/gmx/_locales/de/messages.json create mode 100644 browser/components/search/extensions/gmx/_locales/en-GB/messages.json create mode 100644 browser/components/search/extensions/gmx/_locales/es/messages.json create mode 100644 browser/components/search/extensions/gmx/_locales/fr/messages.json create mode 100644 browser/components/search/extensions/gmx/_locales/shopping/messages.json create mode 100644 browser/components/search/extensions/gmx/favicon.png create mode 100644 browser/components/search/extensions/gmx/manifest.json create mode 100644 browser/components/search/extensions/google/_locales/en/messages.json create mode 100644 browser/components/search/extensions/google/_locales/region-by/messages.json create mode 100644 browser/components/search/extensions/google/_locales/region-kz/messages.json create mode 100644 browser/components/search/extensions/google/_locales/region-ru/messages.json create mode 100644 browser/components/search/extensions/google/_locales/region-tr/messages.json create mode 100644 browser/components/search/extensions/google/favicon.ico create mode 100644 browser/components/search/extensions/google/manifest.json create mode 100644 browser/components/search/extensions/gulesider-NO/favicon.ico create mode 100644 browser/components/search/extensions/gulesider-NO/manifest.json create mode 100644 browser/components/search/extensions/leo_ende_de/favicon.png create mode 100644 browser/components/search/extensions/leo_ende_de/manifest.json create mode 100644 browser/components/search/extensions/longdo/favicon.ico create mode 100644 browser/components/search/extensions/longdo/manifest.json create mode 100644 browser/components/search/extensions/mailcom/favicon.ico create mode 100644 browser/components/search/extensions/mailcom/manifest.json create mode 100644 browser/components/search/extensions/mailru/_locales/default/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/mailru001/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-az/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-en-US/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-hy-AM/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-kk/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-ro/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-ru/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-tr/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-uk/messages.json create mode 100644 browser/components/search/extensions/mailru/_locales/okru-uz/messages.json create mode 100644 browser/components/search/extensions/mailru/favicon.ico create mode 100644 browser/components/search/extensions/mailru/manifest.json create mode 100644 browser/components/search/extensions/mapy-cz/favicon.ico create mode 100644 browser/components/search/extensions/mapy-cz/manifest.json create mode 100644 browser/components/search/extensions/mercadolibre/_locales/ar/messages.json create mode 100644 browser/components/search/extensions/mercadolibre/_locales/cl/messages.json create mode 100644 browser/components/search/extensions/mercadolibre/_locales/mx/messages.json create mode 100644 browser/components/search/extensions/mercadolibre/favicon.ico create mode 100644 browser/components/search/extensions/mercadolibre/manifest.json create mode 100644 browser/components/search/extensions/mercadolivre/favicon.ico create mode 100644 browser/components/search/extensions/mercadolivre/manifest.json create mode 100644 browser/components/search/extensions/naver-kr/favicon.ico create mode 100644 browser/components/search/extensions/naver-kr/manifest.json create mode 100644 browser/components/search/extensions/odpiralni/favicon.png create mode 100644 browser/components/search/extensions/odpiralni/manifest.json create mode 100644 browser/components/search/extensions/pazaruvaj/favicon.ico create mode 100644 browser/components/search/extensions/pazaruvaj/manifest.json create mode 100644 browser/components/search/extensions/priberam/favicon.png create mode 100644 browser/components/search/extensions/priberam/manifest.json create mode 100644 browser/components/search/extensions/prisjakt-sv-SE/favicon.ico create mode 100644 browser/components/search/extensions/prisjakt-sv-SE/manifest.json create mode 100644 browser/components/search/extensions/qwant/favicon.ico create mode 100644 browser/components/search/extensions/qwant/manifest.json create mode 100644 browser/components/search/extensions/qwantjr/favicon.ico create mode 100644 browser/components/search/extensions/qwantjr/manifest.json create mode 100644 browser/components/search/extensions/rakuten/favicon.ico create mode 100644 browser/components/search/extensions/rakuten/manifest.json create mode 100644 browser/components/search/extensions/readmoo/favicon.ico create mode 100644 browser/components/search/extensions/readmoo/manifest.json create mode 100644 browser/components/search/extensions/salidzinilv/favicon.ico create mode 100644 browser/components/search/extensions/salidzinilv/manifest.json create mode 100644 browser/components/search/extensions/seznam-cz/favicon.ico create mode 100644 browser/components/search/extensions/seznam-cz/manifest.json create mode 100644 browser/components/search/extensions/tyda-sv-SE/favicon.ico create mode 100644 browser/components/search/extensions/tyda-sv-SE/manifest.json create mode 100644 browser/components/search/extensions/vatera/favicon.ico create mode 100644 browser/components/search/extensions/vatera/manifest.json create mode 100644 browser/components/search/extensions/webde/favicon.ico create mode 100644 browser/components/search/extensions/webde/manifest.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/NN/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/NO/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/af/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/an/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ar/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ast/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/az/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/be-tarask/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/be/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/bg/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/bn/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/br/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/bs/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ca/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/cy/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/cz/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/da/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/de/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/dsb/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/el/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/en/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/eo/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/es/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/et/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/eu/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/fa/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/fi/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/fr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/fy-NL/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ga-IE/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/gd/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/gl/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/gn/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/gu/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/he/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/hi/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/hr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/hsb/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/hu/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/hy/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ia/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/id/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/is/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/it/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ja/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ka/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/kab/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/kk/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/km/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/kn/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/kr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/lij/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/lo/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/lt/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ltg/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/lv/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/mk/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/mr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ms/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/my/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ne/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/nl/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/oc/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/pa/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/pl/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/pt/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/rm/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ro/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ru/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/si/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/sk/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/sl/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/sq/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/sr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/sv-SE/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ta/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/te/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/th/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/tl/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/tr/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/uk/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/ur/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/uz/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/vi/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/wo/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/zh-CN/messages.json create mode 100644 browser/components/search/extensions/wikipedia/_locales/zh-TW/messages.json create mode 100644 browser/components/search/extensions/wikipedia/favicon.ico create mode 100644 browser/components/search/extensions/wikipedia/manifest.json create mode 100644 browser/components/search/extensions/wiktionary/_locales/oc/messages.json create mode 100644 browser/components/search/extensions/wiktionary/_locales/te/messages.json create mode 100644 browser/components/search/extensions/wiktionary/favicon.ico create mode 100644 browser/components/search/extensions/wiktionary/manifest.json create mode 100644 browser/components/search/extensions/wolnelektury-pl/favicon.png create mode 100644 browser/components/search/extensions/wolnelektury-pl/manifest.json create mode 100644 browser/components/search/extensions/yahoo-jp-auctions/favicon.ico create mode 100644 browser/components/search/extensions/yahoo-jp-auctions/manifest.json create mode 100644 browser/components/search/extensions/yahoo-jp/favicon.ico create mode 100644 browser/components/search/extensions/yahoo-jp/manifest.json create mode 100644 browser/components/search/extensions/yandex/_locales/az/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/by/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/en/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/kk/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/ru/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/tr/messages.json create mode 100644 browser/components/search/extensions/yandex/_locales/ua/messages.json create mode 100644 browser/components/search/extensions/yandex/manifest.json create mode 100644 browser/components/search/extensions/yandex/yandex-en.ico create mode 100644 browser/components/search/extensions/yandex/yandex-ru.ico create mode 100644 browser/components/search/jar.mn create mode 100644 browser/components/search/metrics.yaml create mode 100644 browser/components/search/moz.build create mode 100644 browser/components/search/schema/Readme.txt create mode 100644 browser/components/search/schema/search-telemetry-schema.json create mode 100644 browser/components/search/schema/search-telemetry-ui-schema.json create mode 100644 browser/components/search/test/browser/426329.xml create mode 100644 browser/components/search/test/browser/483086-1.xml create mode 100644 browser/components/search/test/browser/483086-2.xml create mode 100644 browser/components/search/test/browser/browser.ini create mode 100644 browser/components/search/test/browser/browser_426329.js create mode 100644 browser/components/search/test/browser/browser_483086.js create mode 100644 browser/components/search/test/browser/browser_addKeywordSearch.js create mode 100644 browser/components/search/test/browser/browser_contentContextMenu.js create mode 100644 browser/components/search/test/browser/browser_contentContextMenu.xhtml create mode 100644 browser/components/search/test/browser/browser_contentSearchUI.js create mode 100644 browser/components/search/test/browser/browser_contentSearchUI_default.js create mode 100644 browser/components/search/test/browser/browser_contextSearchTabPosition.js create mode 100644 browser/components/search/test/browser/browser_contextmenu.js create mode 100644 browser/components/search/test/browser/browser_contextmenu_whereToOpenLink.js create mode 100644 browser/components/search/test/browser/browser_defaultPrivate_nimbus.js create mode 100644 browser/components/search/test/browser/browser_google_behavior.js create mode 100644 browser/components/search/test/browser/browser_hiddenOneOffs_cleanup.js create mode 100644 browser/components/search/test/browser/browser_hiddenOneOffs_diacritics.js create mode 100644 browser/components/search/test/browser/browser_ime_composition.js create mode 100644 browser/components/search/test/browser/browser_oneOffContextMenu.js create mode 100644 browser/components/search/test/browser/browser_oneOffContextMenu_setDefault.js create mode 100644 browser/components/search/test/browser/browser_private_search_perwindowpb.js create mode 100644 browser/components/search/test/browser/browser_rich_suggestions.js create mode 100644 browser/components/search/test/browser/browser_searchEngine_behaviors.js create mode 100644 browser/components/search/test/browser/browser_search_annotation.js create mode 100644 browser/components/search/test/browser/browser_search_discovery.js create mode 100644 browser/components/search/test/browser/browser_search_glean_serp_telemetry_enabled_by_nimbus_variable.js create mode 100644 browser/components/search/test/browser/browser_search_nimbus_reload.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_abandonment.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_aboutHome.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_adImpression_component.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_categorization_timing.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_content.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_cached.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_cached_serp.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_content.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_multiple_tabs.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_non_ad.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_redirect.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_engagement_target.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_searchbar.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_shopping.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_sources.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_sources_ads.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_sources_in_content.js create mode 100644 browser/components/search/test/browser/browser_search_telemetry_sources_navigation.js create mode 100644 browser/components/search/test/browser/browser_searchbar_addEngine.js create mode 100644 browser/components/search/test/browser/browser_searchbar_context.js create mode 100644 browser/components/search/test/browser/browser_searchbar_default.js create mode 100644 browser/components/search/test/browser/browser_searchbar_enter.js create mode 100644 browser/components/search/test/browser/browser_searchbar_keyboard_navigation.js create mode 100644 browser/components/search/test/browser/browser_searchbar_openpopup.js create mode 100644 browser/components/search/test/browser/browser_searchbar_results.js create mode 100644 browser/components/search/test/browser/browser_searchbar_smallpanel_keyboard_navigation.js create mode 100644 browser/components/search/test/browser/browser_searchbar_widths.js create mode 100644 browser/components/search/test/browser/browser_tooManyEnginesOffered.js create mode 100644 browser/components/search/test/browser/browser_trending_suggestions.js create mode 100644 browser/components/search/test/browser/cacheable.html create mode 100644 browser/components/search/test/browser/cacheable.html^headers^ create mode 100644 browser/components/search/test/browser/contentSearchUI.html create mode 100644 browser/components/search/test/browser/contentSearchUI.js create mode 100644 browser/components/search/test/browser/discovery.html create mode 100644 browser/components/search/test/browser/google_codes/browser.ini create mode 100644 browser/components/search/test/browser/head.js create mode 100644 browser/components/search/test/browser/mozsearch.sjs create mode 100644 browser/components/search/test/browser/opensearch.html create mode 100644 browser/components/search/test/browser/redirect_ad.sjs create mode 100644 browser/components/search/test/browser/redirect_final.sjs create mode 100644 browser/components/search/test/browser/redirect_once.sjs create mode 100644 browser/components/search/test/browser/redirect_thrice.sjs create mode 100644 browser/components/search/test/browser/redirect_twice.sjs create mode 100644 browser/components/search/test/browser/search-engines/basic/manifest.json create mode 100644 browser/components/search/test/browser/search-engines/private/manifest.json create mode 100644 browser/components/search/test/browser/searchSuggestionEngine.sjs create mode 100644 browser/components/search/test/browser/searchTelemetry.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel_below_the_fold.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel_doubled.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel_first_element_non_visible.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel_hidden.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_carousel_outer_container.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_text.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_components_visibility.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_dataAttributes.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_dataAttributes_href.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_dataAttributes_none.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html^headers^ create mode 100644 browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html^headers^ create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox.html^headers^ create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html^headers^ create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html create mode 100644 browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html^headers^ create mode 100644 browser/components/search/test/browser/searchTelemetryAd_shopping.html create mode 100644 browser/components/search/test/browser/serp.css create mode 100644 browser/components/search/test/browser/slow_loading_page_with_ads.html create mode 100644 browser/components/search/test/browser/slow_loading_page_with_ads.sjs create mode 100644 browser/components/search/test/browser/slow_loading_page_with_ads_on_load_event.html create mode 100644 browser/components/search/test/browser/telemetrySearchSuggestions.sjs create mode 100644 browser/components/search/test/browser/telemetrySearchSuggestions.xml create mode 100644 browser/components/search/test/browser/test.html create mode 100644 browser/components/search/test/browser/testEngine.xml create mode 100644 browser/components/search/test/browser/testEngine_diacritics.xml create mode 100644 browser/components/search/test/browser/testEngine_dupe.xml create mode 100644 browser/components/search/test/browser/testEngine_mozsearch.xml create mode 100644 browser/components/search/test/browser/test_search.html create mode 100644 browser/components/search/test/browser/tooManyEnginesOffered.html create mode 100644 browser/components/search/test/browser/trendingSuggestionEngine.sjs create mode 100644 browser/components/search/test/marionette/manifest.ini create mode 100644 browser/components/search/test/marionette/test_engines_on_restart.py create mode 100644 browser/components/search/test/unit/test_search_telemetry_config_validation.js create mode 100644 browser/components/search/test/unit/test_urlTelemetry.js create mode 100644 browser/components/search/test/unit/test_urlTelemetry_generic.js create mode 100644 browser/components/search/test/unit/xpcshell.ini (limited to 'browser/components/search') diff --git a/browser/components/search/.eslintrc.js b/browser/components/search/.eslintrc.js new file mode 100644 index 0000000000..39079432e7 --- /dev/null +++ b/browser/components/search/.eslintrc.js @@ -0,0 +1,13 @@ +/* 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/. */ + +"use strict"; + +module.exports = { + extends: ["plugin:mozilla/require-jsdoc"], + + rules: { + "mozilla/var-only-at-top-level": "error", + }, +}; diff --git a/browser/components/search/BrowserSearchTelemetry.sys.mjs b/browser/components/search/BrowserSearchTelemetry.sys.mjs new file mode 100644 index 0000000000..15163e38c7 --- /dev/null +++ b/browser/components/search/BrowserSearchTelemetry.sys.mjs @@ -0,0 +1,293 @@ +/* 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/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + PartnerLinkAttribution: "resource:///modules/PartnerLinkAttribution.sys.mjs", + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.sys.mjs", + UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.sys.mjs", +}); + +// A map of known search origins. +// The keys of this map are used in the calling code to recordSearch, and in +// the SEARCH_COUNTS histogram. +// The values of this map are used in the names of scalars for the following +// scalar groups: +// browser.engagement.navigation.* +// browser.search.content.* +// browser.search.withads.* +// browser.search.adclicks.* +const KNOWN_SEARCH_SOURCES = new Map([ + ["abouthome", "about_home"], + ["contextmenu", "contextmenu"], + ["newtab", "about_newtab"], + ["searchbar", "searchbar"], + ["system", "system"], + ["urlbar", "urlbar"], + ["urlbar-handoff", "urlbar_handoff"], + ["urlbar-persisted", "urlbar_persisted"], + ["urlbar-searchmode", "urlbar_searchmode"], + ["webextension", "webextension"], +]); + +/** + * This class handles saving search telemetry related to the url bar, + * search bar and other areas as per the sources above. + */ +class BrowserSearchTelemetryHandler { + KNOWN_SEARCH_SOURCES = KNOWN_SEARCH_SOURCES; + + /** + * Determines if we should record a search for this browser instance. + * Private Browsing mode is normally skipped. + * + * @param {browser} browser + * The browser where the search was loaded. + * @returns {boolean} + * True if the search should be recorded, false otherwise. + */ + shouldRecordSearchCount(browser) { + return ( + !lazy.PrivateBrowsingUtils.isWindowPrivate(browser.ownerGlobal) || + !Services.prefs.getBoolPref("browser.engagement.search_counts.pbm", false) + ); + } + + /** + * Records the method by which the user selected a result from the urlbar or + * searchbar. + * + * @param {Event} event + * The event that triggered the selection. + * @param {string} source + * Either "urlbar" or "searchbar" depending on the source. + * @param {number} index + * The index that the user chose in the popup, or -1 if there wasn't a + * selection. + * @param {string} userSelectionBehavior + * How the user cycled through results before picking the current match. + * Could be one of "tab", "arrow" or "none". + */ + recordSearchSuggestionSelectionMethod( + event, + source, + index, + userSelectionBehavior = "none" + ) { + // If the contents of the histogram are changed then + // `UrlbarTestUtils.SELECTED_RESULT_METHODS` should also be updated. + if (source == "searchbar" && userSelectionBehavior != "none") { + throw new Error("Did not expect a selection behavior for the searchbar."); + } + + let histogram = Services.telemetry.getHistogramById( + source == "urlbar" + ? "FX_URLBAR_SELECTED_RESULT_METHOD" + : "FX_SEARCHBAR_SELECTED_RESULT_METHOD" + ); + // command events are from the one-off context menu. Treat them as clicks. + // Note that we don't care about MouseEvent subclasses here, since + // those are not clicks. + let isClick = + event && + (ChromeUtils.getClassName(event) == "MouseEvent" || + event.type == "command"); + let category; + if (isClick) { + category = "click"; + } else if (index >= 0) { + switch (userSelectionBehavior) { + case "tab": + category = "tabEnterSelection"; + break; + case "arrow": + category = "arrowEnterSelection"; + break; + case "rightClick": + // Selected by right mouse button. + category = "rightClickEnter"; + break; + default: + category = "enterSelection"; + } + } else { + category = "enter"; + } + histogram.add(category); + } + + /** + * Records entry into the Urlbar's search mode. + * + * Telemetry records only which search mode is entered and how it was entered. + * It does not record anything pertaining to searches made within search mode. + * + * @param {object} searchMode + * A search mode object. See UrlbarInput.setSearchMode documentation for + * details. + */ + recordSearchMode(searchMode) { + // Search mode preview is not search mode. Recording it would just create + // noise. + if (searchMode.isPreview) { + return; + } + + let scalarKey = lazy.UrlbarSearchUtils.getSearchModeScalarKey(searchMode); + Services.telemetry.keyedScalarAdd( + "urlbar.searchmode." + searchMode.entry, + scalarKey, + 1 + ); + } + + /** + * The main entry point for recording search related Telemetry. This includes + * search counts and engagement measurements. + * + * Telemetry records only search counts per engine and action origin, but + * nothing pertaining to the search contents themselves. + * + * @param {browser} browser + * The browser where the search originated. + * @param {nsISearchEngine} engine + * The engine handling the search. + * @param {string} source + * Where the search originated from. See KNOWN_SEARCH_SOURCES for allowed + * values. + * @param {object} [details] Options object. + * @param {boolean} [details.isOneOff=false] + * true if this event was generated by a one-off search. + * @param {boolean} [details.isSuggestion=false] + * true if this event was generated by a suggested search. + * @param {boolean} [details.isFormHistory=false] + * true if this event was generated by a form history result. + * @param {string} [details.alias=null] + * The search engine alias used in the search, if any. + * @param {string} [details.newtabSessionId=undefined] + * The newtab session that prompted this search, if any. + * @throws if source is not in the known sources list. + */ + recordSearch(browser, engine, source, details = {}) { + try { + if (!this.shouldRecordSearchCount(browser)) { + return; + } + if (!KNOWN_SEARCH_SOURCES.has(source)) { + console.error("Unknown source for search: ", source); + return; + } + + const countIdPrefix = `${engine.telemetryId}.`; + const countIdSource = countIdPrefix + source; + let histogram = Services.telemetry.getKeyedHistogramById("SEARCH_COUNTS"); + + if ( + details.alias && + engine.isAppProvided && + engine.aliases.includes(details.alias) + ) { + // This is a keyword search using an AppProvided engine. + // Record the source as "alias", not "urlbar". + histogram.add(countIdPrefix + "alias"); + } else { + histogram.add(countIdSource); + } + + // Dispatch the search signal to other handlers. + switch (source) { + case "urlbar": + case "searchbar": + case "urlbar-searchmode": + case "urlbar-persisted": + case "urlbar-handoff": + this._handleSearchAndUrlbar(browser, engine, source, details); + break; + case "abouthome": + case "newtab": + this._recordSearch(browser, engine, details.url, source, "enter"); + break; + default: + this._recordSearch(browser, engine, details.url, source); + break; + } + if (["urlbar-handoff", "abouthome", "newtab"].includes(source)) { + Glean.newtabSearch.issued.record({ + newtab_visit_id: details.newtabSessionId, + search_access_point: KNOWN_SEARCH_SOURCES.get(source), + telemetry_id: engine.telemetryId, + }); + lazy.SearchSERPTelemetry.recordBrowserNewtabSession( + browser, + details.newtabSessionId + ); + } + } catch (ex) { + // Catch any errors here, so that search actions are not broken if + // telemetry is broken for some reason. + console.error(ex); + } + } + + /** + * This function handles the "urlbar", "urlbar-oneoff", "searchbar" and + * "searchbar-oneoff" sources. + * + * @param {browser} browser + * The browser where the search originated. + * @param {nsISearchEngine} engine + * The engine handling the search. + * @param {string} source + * Where the search originated from. + * @param {object} details + * See {@link BrowserSearchTelemetryHandler.recordSearch} + */ + _handleSearchAndUrlbar(browser, engine, source, details) { + const isOneOff = !!details.isOneOff; + let action = "enter"; + if (isOneOff) { + action = "oneoff"; + } else if (details.isFormHistory) { + action = "formhistory"; + } else if (details.isSuggestion) { + action = "suggestion"; + } else if (details.alias) { + action = "alias"; + } + + this._recordSearch(browser, engine, details.url, source, action); + } + + _recordSearch(browser, engine, url, source, action = null) { + if (url) { + lazy.PartnerLinkAttribution.makeSearchEngineRequest(engine, url).catch( + console.error + ); + } + + let scalarSource = KNOWN_SEARCH_SOURCES.get(source); + + lazy.SearchSERPTelemetry.recordBrowserSource(browser, scalarSource); + + let scalarKey = action ? "search_" + action : "search"; + Services.telemetry.keyedScalarAdd( + "browser.engagement.navigation." + scalarSource, + scalarKey, + 1 + ); + Services.telemetry.recordEvent( + "navigation", + "search", + scalarSource, + action, + { + engine: engine.telemetryId, + } + ); + } +} + +export var BrowserSearchTelemetry = new BrowserSearchTelemetryHandler(); diff --git a/browser/components/search/SearchOneOffs.sys.mjs b/browser/components/search/SearchOneOffs.sys.mjs new file mode 100644 index 0000000000..ddab74f94a --- /dev/null +++ b/browser/components/search/SearchOneOffs.sys.mjs @@ -0,0 +1,1130 @@ +/* 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/. */ + +const lazy = {}; + +ChromeUtils.defineESModuleGetters(lazy, { + PrivateBrowsingUtils: "resource://gre/modules/PrivateBrowsingUtils.sys.mjs", + SearchUIUtils: "resource:///modules/SearchUIUtils.sys.mjs", +}); + +const EMPTY_ADD_ENGINES = []; + +/** + * Defines the search one-off button elements. These are displayed at the bottom + * of the address bar and search bar. The address bar buttons are a subclass in + * browser/components/urlbar/UrlbarSearchOneOffs.jsm. If you are adding a new + * subclass, see "Methods for subclasses to override" below. + */ +export class SearchOneOffs { + constructor(container) { + this.container = container; + this.window = container.ownerGlobal; + this.document = container.ownerDocument; + + this.container.appendChild( + this.window.MozXULElement.parseXULToFragment( + ` + + + + + + + +
non_ad_carousel
+ + + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_carousel_below_the_fold.html b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_below_the_fold.html new file mode 100644 index 0000000000..737e1e654b --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_below_the_fold.html @@ -0,0 +1,83 @@ + + + + + + + + +
+
ad_carousel
+ +
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_carousel_doubled.html b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_doubled.html new file mode 100644 index 0000000000..f7b7f948d9 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_doubled.html @@ -0,0 +1,182 @@ + + + + + + + +
+ +
ad_carousel
+ +
ad_carousel
+ + +
non_ad_carousel
+ +
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_carousel_first_element_non_visible.html b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_first_element_non_visible.html new file mode 100644 index 0000000000..b5a44b325e --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_first_element_non_visible.html @@ -0,0 +1,85 @@ + + + + + + + +
+ +
ad_carousel
+ +
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_carousel_hidden.html b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_hidden.html new file mode 100644 index 0000000000..cccd714326 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_hidden.html @@ -0,0 +1,87 @@ + + + + + + + +
+
ad_carousel with display: none;
+ + +
ad_carousel with no width;
+ + +
ad_carousel with no height;
+ + +
ad_carousel that is far above the page
+ +
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_carousel_outer_container.html b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_outer_container.html new file mode 100644 index 0000000000..759bd9f0d9 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_carousel_outer_container.html @@ -0,0 +1,83 @@ + + + + + + + +
+ +
ad_carousel
+ +
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_text.html b/browser/components/search/test/browser/searchTelemetryAd_components_text.html new file mode 100644 index 0000000000..bc1219bfa9 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_text.html @@ -0,0 +1,112 @@ + + + + + + + +
+ +
+
ad_sidebar
+
+ +
Mock ad image
+
+ +

Buy Example Now

+
+

Lorem ipsum dolor sit amet, consectetuer adipiscing elit.

+ Buy Now +
+
+
+ + + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_components_visibility.html b/browser/components/search/test/browser/searchTelemetryAd_components_visibility.html new file mode 100644 index 0000000000..475ada3a3c --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_components_visibility.html @@ -0,0 +1,46 @@ + + + + + + + +
+
+
+
ad_link
+ +
+ Ad Link +
+
+
+
ad_link
+ Ad Link +
+ +
+
ad_link
+
+ Ad Link +
+
+
+
ad_link
+ Ad Link +
+ +
+
ad_link
+
+ Ad Link +
+
+
+
ad_link
+ Ad Link +
+
+
+ + diff --git a/browser/components/search/test/browser/searchTelemetryAd_dataAttributes.html b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes.html new file mode 100644 index 0000000000..7bc1b2745e --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes.html @@ -0,0 +1,10 @@ + + + + + + + + Ad link + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_href.html b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_href.html new file mode 100644 index 0000000000..319485cfae --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_href.html @@ -0,0 +1,10 @@ + + + + + + + + Ad link + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_none.html b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_none.html new file mode 100644 index 0000000000..a119cf71be --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_dataAttributes_none.html @@ -0,0 +1,10 @@ + + + + + + + + Non-Ad Link + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html new file mode 100644 index 0000000000..d987356d7e --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html @@ -0,0 +1,12 @@ + + + + + + + Page will do a redirect + + + + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html^headers^ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html^headers^ new file mode 100644 index 0000000000..94cde2a288 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect.html^headers^ @@ -0,0 +1 @@ +Cache-Control: no-cache, must-revalidate diff --git a/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html new file mode 100644 index 0000000000..1c5c31cb38 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html @@ -0,0 +1,17 @@ + + + + + + + Page will do a redirect without doing it in a top load + + + + + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html^headers^ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html^headers^ new file mode 100644 index 0000000000..419697b050 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_nonAdsLink_redirect_nonTopLoaded.html^headers^ @@ -0,0 +1,4 @@ +Cache-Control: no-cache, must-revalidate +Pragma: no-cache +Expires: Fri, 01 Jan 1990 00:00:00 GMT +Content-Type: text/html; charset=ISO-8859-1 diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox.html b/browser/components/search/test/browser/searchTelemetryAd_searchbox.html new file mode 100644 index 0000000000..ca38c13218 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox.html @@ -0,0 +1,38 @@ + + + + + + + +
+
+ +
+
    +
  • test
  • +
+
+
+
+
+
+
non_ads_link
+ +

Example of a non ad

+
+
+
+
+ + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox.html^headers^ b/browser/components/search/test/browser/searchTelemetryAd_searchbox.html^headers^ new file mode 100644 index 0000000000..62847d0585 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox.html^headers^ @@ -0,0 +1 @@ +Cache-Control: private, max-age=0 diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html new file mode 100644 index 0000000000..e381135561 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html @@ -0,0 +1,39 @@ + + + + + + + +
+
+ +
+
+ +
+ Test's + Test 2 +
+
+ +
+ + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html^headers^ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html^headers^ new file mode 100644 index 0000000000..94cde2a288 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content.html^headers^ @@ -0,0 +1 @@ +Cache-Control: no-cache, must-revalidate diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html new file mode 100644 index 0000000000..901dd54a55 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html @@ -0,0 +1,12 @@ + + + + + + + Page will do a redirect + + + + + diff --git a/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html^headers^ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html^headers^ new file mode 100644 index 0000000000..94cde2a288 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_searchbox_with_content_redirect.html^headers^ @@ -0,0 +1 @@ +Cache-Control: no-cache, must-revalidate diff --git a/browser/components/search/test/browser/searchTelemetryAd_shopping.html b/browser/components/search/test/browser/searchTelemetryAd_shopping.html new file mode 100644 index 0000000000..faa6c057a4 --- /dev/null +++ b/browser/components/search/test/browser/searchTelemetryAd_shopping.html @@ -0,0 +1,15 @@ + + + + + + + Document + + + + + diff --git a/browser/components/search/test/browser/serp.css b/browser/components/search/test/browser/serp.css new file mode 100644 index 0000000000..5b3865da44 --- /dev/null +++ b/browser/components/search/test/browser/serp.css @@ -0,0 +1,164 @@ +:root { + --margin-left: 80px; + --subtle: whitesmoke; + --carousel-card-width: 180px; +} + +body { + margin: 0; + padding: 0 0 80px 0; +} + +a:link { + text-decoration: none; +} + +a:visited { + color: blue; +} + +h5[test-label] { + margin-top: 30px; + margin-bottom: 4px; +} + +nav { + border-bottom: 1px solid #ececec; + padding-bottom: 20px; + margin-bottom: 20px; +} + +#searchform { + padding-top: 20px; + margin-bottom: 20px; +} + +nav>div, +#searchform, +.moz-carousel, +.factrow { + display: flex; + align-items: center; +} + +nav>div, +#searchform { + gap: 40px; +} + +nav>div, +#searchform, +#searchresults, +#top { + margin-left: var(--margin-left); +} + +#searchbox { + font-size: 14px; + padding: 10px 20px; + width: 300px; + border-radius: 20px; + border: 2px solid var(--subtle); + height: 20px; +} + +.card-container { + white-space: nowrap; + overflow-x: auto; + overflow-y: hidden; +} + +.card-container>.card { + height: 160px; + border-radius: 3px; + border: 1px solid var(--subtle); + display: inline-block; + box-sizing: border-box; + padding: 10px; +} + +.card-container>.card:not(:last-child) { + margin-right: 10px; +} + +.card-container>.card>a { + display: block; + margin-bottom: 2px; +} + +#searchresults { + width: 900px; + display: grid; + grid-template-columns: 600px 300px; +} + +.moz-carousel, +.factrow { + gap: 10px; +} + +.moz-carousel { + overflow: hidden; +} + +.moz-carousel[narrow], +.moz-carousel-container { + width: calc(var(--carousel-card-width) * 3 + (3 * 10px)); + overflow-x: auto; +} + +.moz-carousel[extra] { + width: calc(var(--carousel-card-width) * 4 + (3 * 10px)); +} + +.moz-carousel>.moz-inner { + border: 1px solid var(--subtle); + border-radius: 10px; + padding: 10px; +} + +.moz-carousel>.moz-carousel-card { + flex: 1 0 var(--carousel-card-width); + border: 1px solid var(--subtle); + font-size: 14px; +} + +.moz-carousel-card .moz-carousel-image { + width: 100%; + height: 120px; + background-color: var(--subtle); + display: flex; + align-items: center; + justify-content: center; +} + +.moz-carousel-card-inner-content { + padding: 10px 20px 20px 20px; +} + +.multi-col { + display: grid; + padding: 10px 20px 20px 20px; + grid-template-columns: 1fr 1fr; + gap: 10px; +} + +.mock-image { + height: 100px; + background-color: var(--subtle); + display: flex; + align-items: center; + justify-content: center; +} + +/* Some SERPs hide anchors using CSS */ +.hidden { + display: none; +} + +/* Typography */ +h2 { + line-height: 100%; + margin-bottom: 10px; + margin-top: 10px; +} diff --git a/browser/components/search/test/browser/slow_loading_page_with_ads.html b/browser/components/search/test/browser/slow_loading_page_with_ads.html new file mode 100644 index 0000000000..35ac9878ec --- /dev/null +++ b/browser/components/search/test/browser/slow_loading_page_with_ads.html @@ -0,0 +1,14 @@ + + + + + + + Ad link + Second Ad link + + + + + diff --git a/browser/components/search/test/browser/slow_loading_page_with_ads.sjs b/browser/components/search/test/browser/slow_loading_page_with_ads.sjs new file mode 100644 index 0000000000..7a6382d1cb --- /dev/null +++ b/browser/components/search/test/browser/slow_loading_page_with_ads.sjs @@ -0,0 +1,21 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function handleRequest(request, response) { + const DELAY_MS = 2000; + response.processAsync(); + + response.setHeader("Cache-Control", "no-cache", false); + response.setHeader("Content-Type", "image/png", false); + response.write("Start loading image"); + + let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); + timer.init( + () => { + response.write("Finish loading image"); + response.finish(); + }, + DELAY_MS, + Ci.nsITimer.TYPE_ONE_SHOT + ); +} diff --git a/browser/components/search/test/browser/slow_loading_page_with_ads_on_load_event.html b/browser/components/search/test/browser/slow_loading_page_with_ads_on_load_event.html new file mode 100644 index 0000000000..307b24d4fe --- /dev/null +++ b/browser/components/search/test/browser/slow_loading_page_with_ads_on_load_event.html @@ -0,0 +1,30 @@ + + + + + + + + + + diff --git a/browser/components/search/test/browser/telemetrySearchSuggestions.sjs b/browser/components/search/test/browser/telemetrySearchSuggestions.sjs new file mode 100644 index 0000000000..1978b4f665 --- /dev/null +++ b/browser/components/search/test/browser/telemetrySearchSuggestions.sjs @@ -0,0 +1,9 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +function handleRequest(req, resp) { + let suffixes = ["foo", "bar"]; + let data = [req.queryString, suffixes.map(s => req.queryString + s)]; + resp.setHeader("Content-Type", "application/json", false); + resp.write(JSON.stringify(data)); +} diff --git a/browser/components/search/test/browser/telemetrySearchSuggestions.xml b/browser/components/search/test/browser/telemetrySearchSuggestions.xml new file mode 100644 index 0000000000..057fc70bf5 --- /dev/null +++ b/browser/components/search/test/browser/telemetrySearchSuggestions.xml @@ -0,0 +1,6 @@ + + +browser_UsageTelemetry usageTelemetrySearchSuggestions.xml + + + diff --git a/browser/components/search/test/browser/test.html b/browser/components/search/test/browser/test.html new file mode 100644 index 0000000000..a39bece4ff --- /dev/null +++ b/browser/components/search/test/browser/test.html @@ -0,0 +1,8 @@ + + + + + Bug 426329 + + + diff --git a/browser/components/search/test/browser/testEngine.xml b/browser/components/search/test/browser/testEngine.xml new file mode 100644 index 0000000000..9c25993232 --- /dev/null +++ b/browser/components/search/test/browser/testEngine.xml @@ -0,0 +1,12 @@ + + Foo + Foo Search + utf-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC + + + + http://mochi.test:8888/browser/browser/components/search/test/browser/ + fooalias + diff --git a/browser/components/search/test/browser/testEngine_diacritics.xml b/browser/components/search/test/browser/testEngine_diacritics.xml new file mode 100644 index 0000000000..340893348d --- /dev/null +++ b/browser/components/search/test/browser/testEngine_diacritics.xml @@ -0,0 +1,12 @@ + + Foo ♡ + Engine whose ShortName contains non-BMP Unicode characters + utf-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC + + + + http://mochi.test:8888/browser/browser/components/search/test/browser/ + diacriticalias + diff --git a/browser/components/search/test/browser/testEngine_dupe.xml b/browser/components/search/test/browser/testEngine_dupe.xml new file mode 100644 index 0000000000..86c4cfadaf --- /dev/null +++ b/browser/components/search/test/browser/testEngine_dupe.xml @@ -0,0 +1,12 @@ + + FooDupe + Second Engine Search + utf-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC + + + + http://mochi.test:8888/browser/browser/components/search/test/browser/ + secondalias + diff --git a/browser/components/search/test/browser/testEngine_mozsearch.xml b/browser/components/search/test/browser/testEngine_mozsearch.xml new file mode 100644 index 0000000000..2f285feb4c --- /dev/null +++ b/browser/components/search/test/browser/testEngine_mozsearch.xml @@ -0,0 +1,14 @@ + + Foo + Foo Search + utf-8 + data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC + + + + + + + + http://mochi.test:8888/browser/browser/components/search/test/browser/ + diff --git a/browser/components/search/test/browser/test_search.html b/browser/components/search/test/browser/test_search.html new file mode 100644 index 0000000000..010d1fdc82 --- /dev/null +++ b/browser/components/search/test/browser/test_search.html @@ -0,0 +1 @@ +test%20search diff --git a/browser/components/search/test/browser/tooManyEnginesOffered.html b/browser/components/search/test/browser/tooManyEnginesOffered.html new file mode 100644 index 0000000000..64e48d05e9 --- /dev/null +++ b/browser/components/search/test/browser/tooManyEnginesOffered.html @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/browser/components/search/test/browser/trendingSuggestionEngine.sjs b/browser/components/search/test/browser/trendingSuggestionEngine.sjs new file mode 100644 index 0000000000..c568cc223b --- /dev/null +++ b/browser/components/search/test/browser/trendingSuggestionEngine.sjs @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +Cu.importGlobalProperties(["TextEncoder"]); + +let gTimer; + +function handleRequest(req, resp) { + // Parse the query params. If the params aren't in the form "foo=bar", then + // treat the entire query string as a search string. + let params = req.queryString.split("&").reduce((memo, pair) => { + let [key, val] = pair.split("="); + if (!val) { + // This part isn't in the form "foo=bar". Treat it as the search string + // (the "query"). + val = key; + key = "query"; + } + memo[decode(key)] = decode(val); + return memo; + }, {}); + + writeResponse(params, resp); +} + +function writeResponse(params, resp) { + // Echoes back 15 results, query0, query1, query2 etc. + let suffixes = [...Array(15).keys()]; + let query = params.query || ""; + let data = [query, suffixes.map(s => query + s)]; + if (params?.richsuggestions) { + data.push([]); + data.push({ + "google:suggestdetail": suffixes.map(s => ({ + a: "Extended title", + dc: "#FFFFFF", + i: "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==", + t: "Title", + })), + }); + } + resp.setHeader("Content-Type", "application/json", false); + + let json = JSON.stringify(data); + let utf8 = String.fromCharCode(...new TextEncoder().encode(json)); + resp.write(utf8); +} + +function decode(str) { + return decodeURIComponent(str.replace(/\+/g, encodeURIComponent(" "))); +} diff --git a/browser/components/search/test/marionette/manifest.ini b/browser/components/search/test/marionette/manifest.ini new file mode 100644 index 0000000000..3ca0ae0eb5 --- /dev/null +++ b/browser/components/search/test/marionette/manifest.ini @@ -0,0 +1,4 @@ +[DEFAULT] +run-if = buildapp == 'browser' + +[test_engines_on_restart.py] diff --git a/browser/components/search/test/marionette/test_engines_on_restart.py b/browser/components/search/test/marionette/test_engines_on_restart.py new file mode 100644 index 0000000000..d7a0634e75 --- /dev/null +++ b/browser/components/search/test/marionette/test_engines_on_restart.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +# 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/. + +import textwrap + +from marionette_harness.marionette_test import MarionetteTestCase + + +class TestEnginesOnRestart(MarionetteTestCase): + def setUp(self): + super(TestEnginesOnRestart, self).setUp() + self.marionette.enforce_gecko_prefs( + { + "browser.search.log": True, + } + ) + + def get_default_search_engine(self): + """Retrieve the identifier of the default search engine.""" + + script = """\ + let [resolve] = arguments; + let searchService = Components.classes[ + "@mozilla.org/browser/search-service;1"] + .getService(Components.interfaces.nsISearchService); + return searchService.init().then(function () { + resolve(searchService.defaultEngine.identifier); + }); + """ + + with self.marionette.using_context(self.marionette.CONTEXT_CHROME): + return self.marionette.execute_async_script(textwrap.dedent(script)) + + def test_engines(self): + self.assertTrue(self.get_default_search_engine().startswith("google")) + self.marionette.set_pref("intl.locale.requested", "kk_KZ") + self.marionette.restart(clean=False, in_app=True) + self.assertTrue(self.get_default_search_engine().startswith("google")) diff --git a/browser/components/search/test/unit/test_search_telemetry_config_validation.js b/browser/components/search/test/unit/test_search_telemetry_config_validation.js new file mode 100644 index 0000000000..1c243cfc82 --- /dev/null +++ b/browser/components/search/test/unit/test_search_telemetry_config_validation.js @@ -0,0 +1,82 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +ChromeUtils.defineESModuleGetters(this, { + AppConstants: "resource://gre/modules/AppConstants.sys.mjs", + RemoteSettings: "resource://services-settings/remote-settings.sys.mjs", + TELEMETRY_SETTINGS_KEY: "resource:///modules/SearchSERPTelemetry.sys.mjs", + JsonSchema: "resource://gre/modules/JsonSchema.sys.mjs", +}); + +/** + * Checks to see if a value is an object or not. + * + * @param {*} value + * The value to check. + * @returns {boolean} + */ +function isObject(value) { + return value != null && typeof value == "object" && !Array.isArray(value); +} + +/** + * This function modifies the schema to prevent allowing additional properties + * on objects. This is used to enforce that the schema contains everything that + * we deliver via the search configuration. + * + * These checks are not enabled in-product, as we want to allow older versions + * to keep working if we add new properties for whatever reason. + * + * @param {object} section + * The section to check to see if an additionalProperties flag should be added. + */ +function disallowAdditionalProperties(section) { + // It is generally acceptable for new properties to be added to the + // configuration as older builds will ignore them. + // + // As a result, we only check for new properties on nightly builds, and this + // avoids us having to uplift schema changes. This also helps preserve the + // schemas as documentation of "what was supported in this version". + if (!AppConstants.NIGHTLY_BUILD) { + info("Skipping additional properties validation."); + return; + } + + if (section.type == "object") { + section.additionalProperties = false; + } + for (let value of Object.values(section)) { + if (isObject(value)) { + disallowAdditionalProperties(value); + } + } +} + +add_task(async function test_search_config_validates_to_schema() { + let schema = await IOUtils.readJSON( + PathUtils.join(do_get_cwd().path, "search-telemetry-schema.json") + ); + disallowAdditionalProperties(schema); + + let data = await RemoteSettings(TELEMETRY_SETTINGS_KEY).get(); + + let validator = new JsonSchema.Validator(schema); + + for (let entry of data) { + // Records in Remote Settings contain additional properties independent of + // the schema. Hence, we don't want to validate their presence. + delete entry.schema; + delete entry.id; + delete entry.last_modified; + delete entry.filter_expression; + + let result = validator.validate(entry); + let message = `Should validate ${entry.telemetryId}`; + if (!result.valid) { + message += `:\n${JSON.stringify(result.errors, null, 2)}`; + } + Assert.ok(result.valid, message); + } +}); diff --git a/browser/components/search/test/unit/test_urlTelemetry.js b/browser/components/search/test/unit/test_urlTelemetry.js new file mode 100644 index 0000000000..bd46f39e5b --- /dev/null +++ b/browser/components/search/test/unit/test_urlTelemetry.js @@ -0,0 +1,310 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +ChromeUtils.defineESModuleGetters(this, { + BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.sys.mjs", + SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.sys.mjs", + SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs", + TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs", + sinon: "resource://testing-common/Sinon.sys.mjs", +}); + +XPCOMUtils.defineLazyModuleGetters(this, { + NetUtil: "resource://gre/modules/NetUtil.jsm", +}); + +const TESTS = [ + { + title: "Google search access point", + trackingUrl: + "https://www.google.com/search?q=test&ie=utf-8&oe=utf-8&client=firefox-b-1-ab", + expectedSearchCountEntry: "google:tagged:firefox-b-1-ab", + expectedAdKey: "google:tagged", + adUrls: [ + "https://www.googleadservices.com/aclk=foobar", + "https://www.googleadservices.com/pagead/aclk=foobar", + "https://www.google.com/aclk=foobar", + "https://www.google.com/pagead/aclk=foobar", + ], + nonAdUrls: [ + "https://www.googleadservices.com/?aclk=foobar", + "https://www.googleadservices.com/bar", + "https://www.google.com/image", + ], + }, + { + title: "Google search access point follow-on", + trackingUrl: + "https://www.google.com/search?client=firefox-b-1-ab&ei=EI_VALUE&q=test2&oq=test2&gs_l=GS_L_VALUE", + expectedSearchCountEntry: "google:tagged-follow-on:firefox-b-1-ab", + }, + { + title: "Google organic", + trackingUrl: + "https://www.google.com/search?client=firefox-b-d-invalid&source=hp&ei=EI_VALUE&q=test&oq=test&gs_l=GS_L_VALUE", + expectedSearchCountEntry: "google:organic:other", + expectedAdKey: "google:organic", + adUrls: ["https://www.googleadservices.com/aclk=foobar"], + nonAdUrls: ["https://www.googleadservices.com/?aclk=foobar"], + }, + { + title: "Google organic no code", + trackingUrl: + "https://www.google.com/search?source=hp&ei=EI_VALUE&q=test&oq=test&gs_l=GS_L_VALUE", + expectedSearchCountEntry: "google:organic:none", + expectedAdKey: "google:organic", + adUrls: ["https://www.googleadservices.com/aclk=foobar"], + nonAdUrls: ["https://www.googleadservices.com/?aclk=foobar"], + }, + { + title: "Google organic UK", + trackingUrl: + "https://www.google.co.uk/search?source=hp&ei=EI_VALUE&q=test&oq=test&gs_l=GS_L_VALUE", + expectedSearchCountEntry: "google:organic:none", + }, + { + title: "Bing search access point", + trackingUrl: "https://www.bing.com/search?q=test&pc=MOZI&form=MOZLBR", + expectedSearchCountEntry: "bing:tagged:MOZI", + expectedAdKey: "bing:tagged", + adUrls: [ + "https://www.bing.com/aclick?ld=foo", + "https://www.bing.com/aclk?ld=foo", + ], + nonAdUrls: [ + "https://www.bing.com/fd/ls/ls.gif?IG=foo", + "https://www.bing.com/fd/ls/l?IG=bar", + "https://www.bing.com/aclook?", + "https://www.bing.com/fd/ls/GLinkPingPost.aspx?IG=baz&url=%2Fvideos%2Fsearch%3Fq%3Dfoo", + "https://www.bing.com/fd/ls/GLinkPingPost.aspx?IG=bar&url=https%3A%2F%2Fwww.bing.com%2Faclick", + "https://www.bing.com/fd/ls/GLinkPingPost.aspx?IG=bar&url=https%3A%2F%2Fwww.bing.com%2Faclk", + ], + }, + { + setUp() { + Services.cookies.removeAll(); + Services.cookies.add( + "www.bing.com", + "/", + "SRCHS", + "PC=MOZI", + false, + false, + false, + Date.now() + 1000 * 60 * 60, + {}, + Ci.nsICookie.SAMESITE_NONE, + Ci.nsICookie.SCHEME_HTTPS + ); + }, + tearDown() { + Services.cookies.removeAll(); + }, + title: "Bing search access point follow-on", + trackingUrl: + "https://www.bing.com/search?q=test&qs=n&form=QBRE&sp=-1&pq=&sc=0-0&sk=&cvid=CVID_VALUE", + expectedSearchCountEntry: "bing:tagged-follow-on:MOZI", + }, + { + title: "Bing organic", + trackingUrl: "https://www.bing.com/search?q=test&pc=MOZIfoo&form=MOZLBR", + expectedSearchCountEntry: "bing:organic:other", + expectedAdKey: "bing:organic", + adUrls: ["https://www.bing.com/aclick?ld=foo"], + nonAdUrls: ["https://www.bing.com/fd/ls/ls.gif?IG=foo"], + }, + { + title: "Bing organic no code", + trackingUrl: + "https://www.bing.com/search?q=test&qs=n&form=QBLH&sp=-1&pq=&sc=0-0&sk=&cvid=CVID_VALUE", + expectedSearchCountEntry: "bing:organic:none", + expectedAdKey: "bing:organic", + adUrls: ["https://www.bing.com/aclick?ld=foo"], + nonAdUrls: ["https://www.bing.com/fd/ls/ls.gif?IG=foo"], + }, + { + title: "DuckDuckGo search access point", + trackingUrl: "https://duckduckgo.com/?q=test&t=ffab", + expectedSearchCountEntry: "duckduckgo:tagged:ffab", + expectedAdKey: "duckduckgo:tagged", + adUrls: [ + "https://duckduckgo.com/y.js?ad_provider=foo", + "https://duckduckgo.com/y.js?f=bar&ad_provider=foo", + "https://www.amazon.co.uk/foo?tag=duckduckgo-ffab-uk-32-xk", + ], + nonAdUrls: [ + "https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images", + "https://duckduckgo.com/y.js?ifu=foo", + "https://improving.duckduckgo.com/t/bar", + ], + }, + { + title: "DuckDuckGo organic", + trackingUrl: "https://duckduckgo.com/?q=test&t=other&ia=news", + expectedSearchCountEntry: "duckduckgo:organic:other", + expectedAdKey: "duckduckgo:organic", + adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"], + nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"], + }, + { + title: "DuckDuckGo expected organic code", + trackingUrl: "https://duckduckgo.com/?q=test&t=h_&ia=news", + expectedSearchCountEntry: "duckduckgo:organic:none", + expectedAdKey: "duckduckgo:organic", + adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"], + nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"], + }, + { + title: "DuckDuckGo expected organic code 2", + trackingUrl: "https://duckduckgo.com/?q=test&t=hz&ia=news", + expectedSearchCountEntry: "duckduckgo:organic:none", + expectedAdKey: "duckduckgo:organic", + adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"], + nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"], + }, + { + title: "DuckDuckGo organic no code", + trackingUrl: "https://duckduckgo.com/?q=test&ia=news", + expectedSearchCountEntry: "duckduckgo:organic:none", + expectedAdKey: "duckduckgo:organic", + adUrls: ["https://duckduckgo.com/y.js?ad_provider=foo"], + nonAdUrls: ["https://duckduckgo.com/?q=foo&t=ffab&ia=images&iax=images"], + }, + { + title: "Baidu search access point", + trackingUrl: "https://www.baidu.com/baidu?wd=test&tn=monline_7_dg&ie=utf-8", + expectedSearchCountEntry: "baidu:tagged:monline_7_dg", + expectedAdKey: "baidu:tagged", + adUrls: ["https://www.baidu.com/baidu.php?url=encoded"], + nonAdUrls: ["https://www.baidu.com/link?url=encoded"], + }, + { + title: "Baidu search access point follow-on", + trackingUrl: + "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&tn=monline_7_dg&wd=test2&oq=test&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn&rsv_enter=1&rsv_sug3=2&rsv_sug2=0&inputT=227&rsv_sug4=397", + expectedSearchCountEntry: "baidu:tagged-follow-on:monline_7_dg", + }, + { + title: "Baidu organic", + trackingUrl: + "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&tn=baidu&bar=&wd=test&rn=&oq&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn", + expectedSearchCountEntry: "baidu:organic:other", + }, + { + title: "Baidu organic no code", + trackingUrl: + "https://www.baidu.com/s?ie=utf-8&f=8&rsv_bp=1&rsv_idx=1&ch=&bar=&wd=test&rn=&oq&rsv_pq=RSV_PQ_VALUE&rsv_t=RSV_T_VALUE&rqlang=cn", + expectedSearchCountEntry: "baidu:organic:none", + }, + { + title: "Ecosia search access point", + trackingUrl: "https://www.ecosia.org/search?tt=mzl&q=foo", + expectedSearchCountEntry: "ecosia:tagged:mzl", + expectedAdKey: "ecosia:tagged", + adUrls: ["https://www.bing.com/aclick?ld=foo"], + nonAdUrls: [], + }, + { + title: "Ecosia organic", + trackingUrl: "https://www.ecosia.org/search?method=index&q=foo", + expectedSearchCountEntry: "ecosia:organic:none", + expectedAdKey: "ecosia:organic", + adUrls: ["https://www.bing.com/aclick?ld=foo"], + nonAdUrls: [], + }, +]; + +/** + * This function is primarily for testing the Ad URL regexps that are triggered + * when a URL is clicked on. These regexps are also used for the `with_ads` + * probe. However, we test the ad_clicks route as that is easier to hit. + * + * @param {string} serpUrl + * The url to simulate where the page the click came from. + * @param {string} adUrl + * The ad url to simulate being clicked. + * @param {string} [expectedAdKey] + * The expected key to be logged for the scalar. Omit if no scalar should be + * logged. + */ +async function testAdUrlClicked(serpUrl, adUrl, expectedAdKey) { + info(`Testing Ad URL: ${adUrl}`); + let channel = NetUtil.newChannel({ + uri: NetUtil.newURI(adUrl), + triggeringPrincipal: Services.scriptSecurityManager.createContentPrincipal( + NetUtil.newURI(serpUrl), + {} + ), + loadUsingSystemPrincipal: true, + }); + SearchSERPTelemetry._contentHandler.observeActivity( + channel, + Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION, + Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE + ); + // Since the content handler takes a moment to allow the channel information + // to settle down, wait the same amount of time here. + await new Promise(resolve => Services.tm.dispatchToMainThread(resolve)); + + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); + if (!expectedAdKey) { + Assert.ok( + !("browser.search.adclicks.unknown" in scalars), + "Should not have recorded an ad click" + ); + } else { + TelemetryTestUtils.assertKeyedScalar( + scalars, + "browser.search.adclicks.unknown", + expectedAdKey, + 1 + ); + } +} + +do_get_profile(); + +add_task(async function setup() { + Services.prefs.setBoolPref(SearchUtils.BROWSER_SEARCH_PREF + "log", true); + await SearchSERPTelemetry.init(); + sinon.stub(BrowserSearchTelemetry, "shouldRecordSearchCount").returns(true); +}); + +add_task(async function test_parsing_search_urls() { + for (const test of TESTS) { + info(`Running ${test.title}`); + if (test.setUp) { + test.setUp(); + } + SearchSERPTelemetry.updateTrackingStatus( + { + getTabBrowser: () => {}, + }, + test.trackingUrl + ); + let scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); + TelemetryTestUtils.assertKeyedScalar( + scalars, + "browser.search.content.unknown", + test.expectedSearchCountEntry, + 1 + ); + + if ("adUrls" in test) { + for (const adUrl of test.adUrls) { + await testAdUrlClicked(test.trackingUrl, adUrl, test.expectedAdKey); + } + for (const nonAdUrls of test.nonAdUrls) { + await testAdUrlClicked(test.trackingUrl, nonAdUrls); + } + } + + if (test.tearDown) { + test.tearDown(); + } + } +}); diff --git a/browser/components/search/test/unit/test_urlTelemetry_generic.js b/browser/components/search/test/unit/test_urlTelemetry_generic.js new file mode 100644 index 0000000000..610dd56e3a --- /dev/null +++ b/browser/components/search/test/unit/test_urlTelemetry_generic.js @@ -0,0 +1,323 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { XPCOMUtils } = ChromeUtils.importESModule( + "resource://gre/modules/XPCOMUtils.sys.mjs" +); + +ChromeUtils.defineESModuleGetters(this, { + BrowserSearchTelemetry: "resource:///modules/BrowserSearchTelemetry.sys.mjs", + SearchSERPTelemetry: "resource:///modules/SearchSERPTelemetry.sys.mjs", + SearchSERPTelemetryUtils: "resource:///modules/SearchSERPTelemetry.sys.mjs", + SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs", + TelemetryTestUtils: "resource://testing-common/TelemetryTestUtils.sys.mjs", + sinon: "resource://testing-common/Sinon.sys.mjs", +}); + +XPCOMUtils.defineLazyModuleGetters(this, { + NetUtil: "resource://gre/modules/NetUtil.jsm", +}); + +const TEST_PROVIDER_INFO = [ + { + telemetryId: "example", + searchPageRegexp: /^https:\/\/www\.example\.com\/search/, + queryParamName: "q", + codeParamName: "abc", + taggedCodes: ["ff", "tb"], + expectedOrganicCodes: ["baz"], + organicCodes: ["foo"], + followOnParamNames: ["a"], + extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/], + shoppingTab: { + regexp: "&site=shop", + }, + components: [ + { + type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK, + default: true, + }, + ], + }, + { + telemetryId: "example2", + searchPageRegexp: /^https:\/\/www\.example2\.com\/search/, + queryParamName: "q", + codeParamName: "abc", + taggedCodes: ["ff", "tb"], + expectedOrganicCodes: ["baz"], + organicCodes: ["foo"], + followOnParamNames: ["a"], + extraAdServersRegexps: [/^https:\/\/www\.example\.com\/ad2/], + components: [ + { + type: SearchSERPTelemetryUtils.COMPONENTS.AD_LINK, + default: true, + }, + ], + }, +]; + +const TESTS = [ + { + title: "Tagged search", + trackingUrl: "https://www.example.com/search?q=test&abc=ff", + expectedSearchCountEntry: "example:tagged:ff", + expectedAdKey: "example:tagged", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "true", + partner_code: "ff", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Tagged search with shopping", + trackingUrl: "https://www.example.com/search?q=test&abc=ff&site=shop", + expectedSearchCountEntry: "example:tagged:ff", + expectedAdKey: "example:tagged", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "true", + partner_code: "ff", + is_shopping_page: "true", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Tagged follow-on", + trackingUrl: "https://www.example.com/search?q=test&abc=tb&a=next", + expectedSearchCountEntry: "example:tagged-follow-on:tb", + expectedAdKey: "example:tagged-follow-on", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "true", + partner_code: "tb", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Organic search matched code", + trackingUrl: "https://www.example.com/search?q=test&abc=foo", + expectedSearchCountEntry: "example:organic:foo", + expectedAdKey: "example:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "false", + partner_code: "foo", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Organic search non-matched code", + trackingUrl: "https://www.example.com/search?q=test&abc=ff123", + expectedSearchCountEntry: "example:organic:other", + expectedAdKey: "example:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "false", + partner_code: "other", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Organic search non-matched code 2", + trackingUrl: "https://www.example.com/search?q=test&abc=foo123", + expectedSearchCountEntry: "example:organic:other", + expectedAdKey: "example:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "false", + partner_code: "other", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Organic search expected organic matched code", + trackingUrl: "https://www.example.com/search?q=test&abc=baz", + expectedSearchCountEntry: "example:organic:none", + expectedAdKey: "example:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "false", + partner_code: "", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Organic search no codes", + trackingUrl: "https://www.example.com/search?q=test", + expectedSearchCountEntry: "example:organic:none", + expectedAdKey: "example:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example", + tagged: "false", + partner_code: "", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, + { + title: "Different engines using the same adUrl", + trackingUrl: "https://www.example2.com/search?q=test", + expectedSearchCountEntry: "example2:organic:none", + expectedAdKey: "example2:organic", + adUrls: ["https://www.example.com/ad2"], + nonAdUrls: ["https://www.example.com/ad3"], + impression: { + provider: "example2", + tagged: "false", + partner_code: "", + is_shopping_page: "false", + shopping_tab_displayed: "false", + source: "unknown", + }, + }, +]; + +/** + * This function is primarily for testing the Ad URL regexps that are triggered + * when a URL is clicked on. These regexps are also used for the `withads` + * probe. However, we test the adclicks route as that is easier to hit. + * + * @param {string} serpUrl + * The url to simulate where the page the click came from. + * @param {string} adUrl + * The ad url to simulate being clicked. + * @param {string} [expectedAdKey] + * The expected key to be logged for the scalar. Omit if no scalar should be + * logged. + */ +async function testAdUrlClicked(serpUrl, adUrl, expectedAdKey) { + info(`Testing Ad URL: ${adUrl}`); + let channel = NetUtil.newChannel({ + uri: NetUtil.newURI(adUrl), + triggeringPrincipal: Services.scriptSecurityManager.createContentPrincipal( + NetUtil.newURI(serpUrl), + {} + ), + loadUsingSystemPrincipal: true, + }); + SearchSERPTelemetry._contentHandler.observeActivity( + channel, + Ci.nsIHttpActivityObserver.ACTIVITY_TYPE_HTTP_TRANSACTION, + Ci.nsIHttpActivityObserver.ACTIVITY_SUBTYPE_TRANSACTION_CLOSE + ); + // Since the content handler takes a moment to allow the channel information + // to settle down, wait the same amount of time here. + await new Promise(resolve => Services.tm.dispatchToMainThread(resolve)); + + const scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); + if (!expectedAdKey) { + Assert.ok( + !("browser.search.adclicks.unknown" in scalars), + "Should not have recorded an ad click" + ); + } else { + TelemetryTestUtils.assertKeyedScalar( + scalars, + "browser.search.adclicks.unknown", + expectedAdKey, + 1 + ); + } +} + +do_get_profile(); + +add_task(async function setup() { + Services.prefs.setBoolPref(SearchUtils.BROWSER_SEARCH_PREF + "log", true); + Services.prefs.setBoolPref( + SearchUtils.BROWSER_SEARCH_PREF + "serpEventTelemetry.enabled", + true + ); + Services.fog.initializeFOG(); + await SearchSERPTelemetry.init(); + SearchSERPTelemetry.overrideSearchTelemetryForTests(TEST_PROVIDER_INFO); + sinon.stub(BrowserSearchTelemetry, "shouldRecordSearchCount").returns(true); +}); + +add_task(async function test_parsing_search_urls() { + for (const test of TESTS) { + info(`Running ${test.title}`); + if (test.setUp) { + test.setUp(); + } + let browser = { + getTabBrowser: () => {}, + }; + SearchSERPTelemetry.updateTrackingStatus(browser, test.trackingUrl); + SearchSERPTelemetry.reportPageImpression( + { + url: test.trackingUrl, + shoppingTabDisplayed: false, + }, + browser + ); + let scalars = TelemetryTestUtils.getProcessScalars("parent", true, true); + TelemetryTestUtils.assertKeyedScalar( + scalars, + "browser.search.content.unknown", + test.expectedSearchCountEntry, + 1 + ); + + if ("adUrls" in test) { + for (const adUrl of test.adUrls) { + await testAdUrlClicked(test.trackingUrl, adUrl, test.expectedAdKey); + } + for (const nonAdUrls of test.nonAdUrls) { + await testAdUrlClicked(test.trackingUrl, nonAdUrls); + } + } + + let recordedEvents = Glean.serp.impression.testGetValue(); + + Assert.equal( + recordedEvents.length, + 1, + "should only see one impression event" + ); + + // To allow deep equality. + test.impression.impression_id = recordedEvents[0].extra.impression_id; + Assert.deepEqual(recordedEvents[0].extra, test.impression); + + if (test.tearDown) { + test.tearDown(); + } + + // We need to clear Glean events so they don't accumulate for each iteration. + Services.fog.testResetFOG(); + } +}); diff --git a/browser/components/search/test/unit/xpcshell.ini b/browser/components/search/test/unit/xpcshell.ini new file mode 100644 index 0000000000..7feeb6d38c --- /dev/null +++ b/browser/components/search/test/unit/xpcshell.ini @@ -0,0 +1,9 @@ +[DEFAULT] +skip-if = toolkit == 'android' # bug 1730213 +firefox-appdir = browser + +[test_search_telemetry_config_validation.js] +support-files = + ../../schema/search-telemetry-schema.json +[test_urlTelemetry.js] +[test_urlTelemetry_generic.js] -- cgit v1.2.3