summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search/tests/SearchTestUtils.jsm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-28 14:29:10 +0000
commit2aa4a82499d4becd2284cdb482213d541b8804dd (patch)
treeb80bf8bf13c3766139fbacc530efd0dd9d54394c /toolkit/components/search/tests/SearchTestUtils.jsm
parentInitial commit. (diff)
downloadfirefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz
firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'toolkit/components/search/tests/SearchTestUtils.jsm')
-rw-r--r--toolkit/components/search/tests/SearchTestUtils.jsm352
1 files changed, 352 insertions, 0 deletions
diff --git a/toolkit/components/search/tests/SearchTestUtils.jsm b/toolkit/components/search/tests/SearchTestUtils.jsm
new file mode 100644
index 0000000000..68b1afecb3
--- /dev/null
+++ b/toolkit/components/search/tests/SearchTestUtils.jsm
@@ -0,0 +1,352 @@
+"use strict";
+
+const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
+
+const { XPCOMUtils } = ChromeUtils.import(
+ "resource://gre/modules/XPCOMUtils.jsm"
+);
+
+const { MockRegistrar } = ChromeUtils.import(
+ "resource://testing-common/MockRegistrar.jsm"
+);
+
+XPCOMUtils.defineLazyModuleGetters(this, {
+ AddonManager: "resource://gre/modules/AddonManager.jsm",
+ AddonTestUtils: "resource://testing-common/AddonTestUtils.jsm",
+ ExtensionTestUtils: "resource://testing-common/ExtensionXPCShellUtils.jsm",
+ RemoteSettings: "resource://services-settings/remote-settings.js",
+ SearchUtils: "resource://gre/modules/SearchUtils.jsm",
+ Services: "resource://gre/modules/Services.jsm",
+ sinon: "resource://testing-common/Sinon.jsm",
+});
+
+Cu.importGlobalProperties(["fetch"]);
+
+var EXPORTED_SYMBOLS = ["SearchTestUtils"];
+
+var gTestScope;
+
+var SearchTestUtils = Object.freeze({
+ init(testScope) {
+ gTestScope = testScope;
+ // This handles xpcshell-tests.
+ if (!("ExtensionTestUtils" in gTestScope)) {
+ gTestScope.ExtensionTestUtils = ExtensionTestUtils;
+ }
+ },
+
+ /**
+ * Adds an OpenSearch based engine to the search service. It will remove
+ * the engine at the end of the test.
+ *
+ * @param {string} url The URL of the engine to add.
+ * @param {Function} registerCleanupFunction Pass the registerCleanupFunction
+ * from the test's scope.
+ * @returns {Promise} Returns a promise that is resolved with the new engine
+ * or rejected if it fails.
+ */
+ async promiseNewSearchEngine(url) {
+ let engine = await Services.search.addOpenSearchEngine(url, "");
+ gTestScope.registerCleanupFunction(async () =>
+ Services.search.removeEngine(engine)
+ );
+ return engine;
+ },
+
+ /**
+ * Returns a promise that is resolved when an observer notification from the
+ * search service fires with the specified data.
+ *
+ * @param {*} expectedData
+ * The value the observer notification sends that causes us to resolve
+ * the promise.
+ * @param {string} topic
+ * The notification topic to observe. Defaults to 'browser-search-service'.
+ * @returns {Promise}
+ * Returns a promise that is resolved with the subject of the
+ * topic once the topic with the data has been observed.
+ */
+ promiseSearchNotification(expectedData, topic = "browser-search-service") {
+ return new Promise(resolve => {
+ Services.obs.addObserver(function observer(aSubject, aTopic, aData) {
+ if (aData != expectedData) {
+ return;
+ }
+
+ Services.obs.removeObserver(observer, topic);
+ // Let the stack unwind.
+ Services.tm.dispatchToMainThread(() => resolve(aSubject));
+ }, topic);
+ });
+ },
+
+ /**
+ * Load engines from test data located in particular folders.
+ *
+ * @param {string} [folder]
+ * The folder name to use.
+ * @param {string} [subFolder]
+ * The subfolder to use, if any.
+ * @param {array} [config]
+ * An array which contains the configuration to set.
+ * @returns {object}
+ * An object that is a sinon stub for the configuration getter.
+ */
+ async useTestEngines(folder = "data", subFolder = null, config = null) {
+ let url = `resource://test/${folder}/`;
+ if (subFolder) {
+ url += `${subFolder}/`;
+ }
+ let resProt = Services.io
+ .getProtocolHandler("resource")
+ .QueryInterface(Ci.nsIResProtocolHandler);
+ resProt.setSubstitution("search-extensions", Services.io.newURI(url));
+
+ const settings = await RemoteSettings(SearchUtils.SETTINGS_KEY);
+ if (config) {
+ return sinon.stub(settings, "get").returns(config);
+ }
+
+ let response = await fetch(`resource://search-extensions/engines.json`);
+ let json = await response.json();
+ return sinon.stub(settings, "get").returns(json.data);
+ },
+
+ async useMochitestEngines(testDir) {
+ // Replace the path we load search engines from with
+ // the path to our test data.
+ let resProt = Services.io
+ .getProtocolHandler("resource")
+ .QueryInterface(Ci.nsIResProtocolHandler);
+ let originalSubstitution = resProt.getSubstitution("search-extensions");
+ resProt.setSubstitution(
+ "search-extensions",
+ Services.io.newURI("file://" + testDir.path)
+ );
+ gTestScope.registerCleanupFunction(() => {
+ resProt.setSubstitution("search-extensions", originalSubstitution);
+ });
+ },
+
+ /**
+ * Convert a list of engine configurations into engine objects.
+ *
+ * @param {Array} engineConfigurations
+ **/
+ async searchConfigToEngines(engineConfigurations) {
+ let engines = [];
+ for (let config of engineConfigurations) {
+ let engine = await Services.search.wrappedJSObject.makeEngineFromConfig(
+ config
+ );
+ engines.push(engine);
+ }
+ return engines;
+ },
+
+ /**
+ * Provides various setup for xpcshell-tests installing WebExtensions. Should
+ * be called from the global scope of the test.
+ *
+ * @param {object} scope
+ * The global scope of the test being run.
+ * @param {*} usePrivilegedSignatures
+ * How to sign created addons.
+ */
+ initXPCShellAddonManager(scope, usePrivilegedSignatures = false) {
+ let scopes = AddonManager.SCOPE_PROFILE | AddonManager.SCOPE_APPLICATION;
+ Services.prefs.setIntPref("extensions.enabledScopes", scopes);
+ Services.prefs.setBoolPref(
+ "extensions.webextensions.background-delayed-startup",
+ false
+ );
+ gTestScope.ExtensionTestUtils.init(scope);
+ AddonTestUtils.usePrivilegedSignatures = usePrivilegedSignatures;
+ AddonTestUtils.overrideCertDB();
+ },
+
+ /**
+ * Add a search engine as a WebExtension.
+ *
+ * Note: If you are in xpcshell-tests, then you should call
+ * `initXPCShellAddonManager` before calling this.
+ *
+ * @param {object} [options]
+ * @see createEngineManifest
+ */
+ async installSearchExtension(options = {}) {
+ options.id = (options.id ?? "example") + "@tests.mozilla.org";
+ let extensionInfo = {
+ useAddonManager: "permanent",
+ manifest: this.createEngineManifest(options),
+ };
+
+ let extension = gTestScope.ExtensionTestUtils.loadExtension(extensionInfo);
+ await extension.startup();
+ await AddonTestUtils.waitForSearchProviderStartup(extension);
+ return extension;
+ },
+
+ /**
+ * Install a search engine as a system extension to simulate
+ * Normandy updates. For xpcshell-tests only.
+ *
+ * Note: If you are in xpcshell-tests, then you should call
+ * `initXPCShellAddonManager` before calling this.
+ *
+ * @param {object} [options]
+ * @see createEngineManifest
+ */
+ async installSystemSearchExtension(options = {}) {
+ options.id = (options.id ?? "example") + "@search.mozilla.org";
+ let xpi = await AddonTestUtils.createTempWebExtensionFile({
+ manifest: this.createEngineManifest(options),
+ background() {
+ // eslint-disable-next-line no-undef
+ browser.test.sendMessage("started");
+ },
+ });
+ let wrapper = gTestScope.ExtensionTestUtils.expectExtension(options.id);
+
+ const install = await AddonManager.getInstallForURL(`file://${xpi.path}`, {
+ useSystemLocation: true,
+ });
+
+ install.install();
+
+ await wrapper.awaitStartup();
+ await wrapper.awaitMessage("started");
+
+ return wrapper;
+ },
+
+ /**
+ * Create a search engine extension manifest.
+ *
+ * @param {object} [options]
+ * @param {string} [options.id]
+ * The id to use for the WebExtension.
+ * @param {string} [options.name]
+ * The display name to use for the WebExtension.
+ * @param {string} [options.version]
+ * The version to use for the WebExtension.
+ * @param {string} [options.keyword]
+ * The keyword to use for the WebExtension.
+ * @param {string} [options.encoding]
+ * The encoding to use for the WebExtension.
+ * @param {string} [options.search_url]
+ * The search URL to use for the WebExtension.
+ * @param {string} [options.search_url_get_params]
+ * The search URL parameters to use for the WebExtension.
+ * @param {string} [options.suggest_url]
+ * The suggestion URL to use for the WebExtension.
+ * @param {string} [options.suggest_url]
+ * The suggestion URL parameters to use for the WebExtension.
+ * @returns {object}
+ * The generated manifest.
+ */
+ createEngineManifest(options = {}) {
+ options.id = options.id ?? "example@tests.mozilla.org";
+ options.name = options.name ?? "Example";
+ options.version = options.version ?? "1.0";
+ let manifest = {
+ version: options.version,
+ applications: {
+ gecko: {
+ id: options.id,
+ },
+ },
+ chrome_settings_overrides: {
+ search_provider: {
+ name: options.name,
+ search_url: options.search_url ?? "https://example.com/",
+ search_url_get_params:
+ options.search_url_get_params ?? "?q={searchTerms}",
+ },
+ },
+ };
+ if (options.encoding) {
+ manifest.chrome_settings_overrides.search_provider.encoding =
+ options.encoding;
+ }
+ if (options.keyword) {
+ manifest.chrome_settings_overrides.search_provider.keyword =
+ options.keyword;
+ }
+ if (options.suggest_url) {
+ manifest.chrome_settings_overrides.search_provider.suggest_url =
+ options.suggest_url;
+ }
+ if (options.suggest_url) {
+ manifest.chrome_settings_overrides.search_provider.suggest_url_get_params =
+ options.suggest_url_get_params;
+ }
+ return manifest;
+ },
+
+ /**
+ * A mock idleService that allows us to simulate RemoteSettings
+ * configuration updates.
+ */
+ idleService: {
+ _observers: new Set(),
+
+ _reset() {
+ this._observers.clear();
+ },
+
+ _fireObservers(state) {
+ for (let observer of this._observers.values()) {
+ observer.observe(observer, state, null);
+ }
+ },
+
+ QueryInterface: ChromeUtils.generateQI(["nsIUserIdleService"]),
+ idleTime: 19999,
+
+ addIdleObserver(observer, time) {
+ this._observers.add(observer);
+ },
+
+ removeIdleObserver(observer, time) {
+ this._observers.delete(observer);
+ },
+ },
+
+ /**
+ * Register the mock idleSerice.
+ *
+ * @param {Fun} registerCleanupFunction
+ */
+ useMockIdleService() {
+ let fakeIdleService = MockRegistrar.register(
+ "@mozilla.org/widget/useridleservice;1",
+ SearchTestUtils.idleService
+ );
+ gTestScope.registerCleanupFunction(() => {
+ MockRegistrar.unregister(fakeIdleService);
+ });
+ },
+
+ /**
+ * Simulates an update to the RemoteSettings configuration.
+ *
+ * @param {object} [config]
+ * The new configuration.
+ */
+ async updateRemoteSettingsConfig(config) {
+ if (!config) {
+ let settings = RemoteSettings(SearchUtils.SETTINGS_KEY);
+ config = await settings.get();
+ }
+ const reloadObserved = SearchTestUtils.promiseSearchNotification(
+ "engines-reloaded"
+ );
+ await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", {
+ data: { current: config },
+ });
+
+ this.idleService._fireObservers("idle");
+ await reloadObserved;
+ },
+});