diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /remote/shared/messagehandler/test/browser/resources | |
parent | Initial commit. (diff) | |
download | firefox-upstream.tar.xz firefox-upstream.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'remote/shared/messagehandler/test/browser/resources')
13 files changed, 626 insertions, 0 deletions
diff --git a/remote/shared/messagehandler/test/browser/resources/modules/ModuleRegistry.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/ModuleRegistry.sys.mjs new file mode 100644 index 0000000000..e5d9c38719 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/ModuleRegistry.sys.mjs @@ -0,0 +1,30 @@ +/* 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/. */ + +/** + * Retrieve the WebDriver BiDi module class matching the provided module name + * and folder. + * + * @param {String} moduleName + * The name of the module to get the class for. + * @param {String} moduleFolder + * A valid folder name for modules. + * @return {Class=} + * The class corresponding to the module name and folder, null if no match + * was found. + * @throws {Error} + * If the provided module folder is unexpected. + **/ +export const getModuleClass = function(moduleName, moduleFolder) { + const root = `chrome://mochitests/content/browser/remote/shared/messagehandler/test/`; + const path = `${root}browser/resources/modules/${moduleFolder}/${moduleName}.sys.mjs`; + try { + return ChromeUtils.importESModule(path)[moduleName]; + } catch (e) { + if (e.result == Cr.NS_ERROR_FILE_NOT_FOUND) { + return null; + } + throw e; + } +}; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/root/command.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/root/command.sys.mjs new file mode 100644 index 0000000000..a67428ddfa --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/root/command.sys.mjs @@ -0,0 +1,80 @@ +/* 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 { ContextDescriptorType } from "chrome://remote/content/shared/messagehandler/MessageHandler.sys.mjs"; +import { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; +import { WindowGlobalMessageHandler } from "chrome://remote/content/shared/messagehandler/WindowGlobalMessageHandler.sys.mjs"; + +class CommandModule extends Module { + destroy() {} + + async #getSessionDataUpdateFromAllContexts() { + const updates = await this.messageHandler.handleCommand({ + moduleName: "command", + commandName: "_getSessionDataUpdate", + destination: { + contextDescriptor: { + type: ContextDescriptorType.All, + }, + type: WindowGlobalMessageHandler.type, + }, + }); + + // Filter out null values, which indicate that no new session data was + // received by the windowglobal module since the last getSessionDataUpdate + // command. + return updates.filter(update => update != null); + } + + /** + * Commands + */ + + async testAddSessionData(params) { + await this.messageHandler.addSessionData({ + moduleName: "command", + category: "testCategory", + contextDescriptor: { + type: ContextDescriptorType.All, + }, + values: params.values, + }); + + return this.#getSessionDataUpdateFromAllContexts(); + } + + async testRemoveSessionData(params) { + await this.messageHandler.removeSessionData({ + moduleName: "command", + category: "testCategory", + contextDescriptor: { + type: ContextDescriptorType.All, + }, + values: params.values, + }); + + return this.#getSessionDataUpdateFromAllContexts(); + } + + async testUpdateSessionData(params) { + await this.messageHandler.updateSessionData(params); + return this.#getSessionDataUpdateFromAllContexts(); + } + + testRootModule() { + return "root-value"; + } + + testMissingIntermediaryMethod(params, destination) { + // Spawn a new internal command, but with a commandName which doesn't match + // any method. + return this.messageHandler.handleCommand({ + moduleName: "command", + commandName: "missingMethod", + destination, + }); + } +} + +export const command = CommandModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/root/event.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/root/event.sys.mjs new file mode 100644 index 0000000000..e49437e80d --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/root/event.sys.mjs @@ -0,0 +1,21 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class EventModule extends Module { + destroy() {} + + /** + * Commands + */ + + testEmitRootEvent() { + this.emitEvent("event-from-root", { + text: "event from root", + }); + } +} + +export const event = EventModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/root/invalid.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/root/invalid.sys.mjs new file mode 100644 index 0000000000..3b74769d06 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/root/invalid.sys.mjs @@ -0,0 +1,4 @@ +// This module is meant to check error reporting when importing a module fails +// due to an actual issue (syntax error etc...). + +SyntaxError(; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.sys.mjs new file mode 100644 index 0000000000..0931a7ee8e --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/root/rootOnly.sys.mjs @@ -0,0 +1,70 @@ +/* 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 { ContextDescriptorType } from "chrome://remote/content/shared/messagehandler/MessageHandler.sys.mjs"; +import { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class RootOnlyModule extends Module { + #sessionDataReceived; + #subscribedEvents; + + constructor(messageHandler) { + super(messageHandler); + + this.#sessionDataReceived = []; + this.#subscribedEvents = new Set(); + } + + destroy() {} + + /** + * Commands + */ + + getSessionDataReceived() { + return this.#sessionDataReceived; + } + + testCommand(params = {}) { + return params; + } + + _applySessionData(params) { + const added = []; + const removed = []; + + const filteredSessionData = params.sessionData.filter(item => + this.messageHandler.matchesContext(item.contextDescriptor) + ); + for (const event of this.#subscribedEvents.values()) { + const hasSessionItem = filteredSessionData.some( + item => item.value === event + ); + // If there are no session items for this context, we should unsubscribe from the event. + if (!hasSessionItem) { + this.#subscribedEvents.delete(event); + removed.push(event); + } + } + + // Subscribe to all events, which have an item in SessionData + for (const { value } of filteredSessionData) { + if (!this.#subscribedEvents.has(value)) { + this.#subscribedEvents.add(value); + added.push(value); + } + } + + this.#sessionDataReceived.push({ + category: params.category, + added, + removed, + contextDescriptor: { + type: ContextDescriptorType.All, + }, + }); + } +} + +export const rootOnly = RootOnlyModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/command.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/command.sys.mjs new file mode 100644 index 0000000000..f9a2e5d4eb --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/command.sys.mjs @@ -0,0 +1,28 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class CommandModule extends Module { + destroy() {} + + /** + * Commands + */ + + testInterceptModule() { + return "intercepted-value"; + } + + async testInterceptAndForwardModule(params, destination) { + const windowGlobalValue = await this.messageHandler.handleCommand({ + moduleName: "command", + commandName: "testForwardToWindowGlobal", + destination, + }); + return "intercepted-and-forward+" + windowGlobalValue; + } +} + +export const command = CommandModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/event.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/event.sys.mjs new file mode 100644 index 0000000000..2969e0a3e8 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal-in-root/event.sys.mjs @@ -0,0 +1,31 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class EventModule extends Module { + destroy() {} + + interceptEvent(name, payload) { + if (name === "event.testEventWithInterception") { + return { + ...payload, + additionalInformation: "information added through interception", + }; + } + return payload; + } + + /** + * Commands + */ + + testEmitWindowGlobalInRootEvent(params, destination) { + this.emitEvent("event-from-window-global-in-root", { + text: `windowglobal-in-root event for ${destination.id}`, + }); + } +} + +export const event = EventModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/command.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/command.sys.mjs new file mode 100644 index 0000000000..23655a464a --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/command.sys.mjs @@ -0,0 +1,114 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class CommandModule extends Module { + constructor(messageHandler) { + super(messageHandler); + this._lastSessionDataUpdate = {}; + this._subscribedEvents = new Set(); + this._testCategorySessionData = []; + + this._createdByMessageHandlerConstructor = this._isCreatedByMessageHandlerConstructor(); + } + destroy() {} + + /** + * Commands + */ + + _applySessionData(params) { + if (params.category === "testCategory") { + const added = []; + const removed = []; + + const filteredSessionData = params.sessionData.filter(item => + this.messageHandler.matchesContext(item.contextDescriptor) + ); + for (const event of this._subscribedEvents.values()) { + const hasSessionItem = filteredSessionData.some( + item => item.value === event + ); + // If there are no session items for this context, we should unsubscribe from the event. + if (!hasSessionItem) { + this._subscribedEvents.delete(event); + removed.push(event); + } + } + + // Subscribe to all events, which have an item in SessionData + for (const { value } of filteredSessionData) { + if (!this._subscribedEvents.has(value)) { + this._subscribedEvents.add(value); + added.push(value); + } + } + + this._testCategorySessionData = this._testCategorySessionData + .concat(added) + .filter(value => !removed.includes(value)); + + this._lastSessionDataUpdate = { + addedData: added.join(", "), + removedData: removed.join(", "), + sessionData: this._testCategorySessionData.join(", "), + contextId: this.messageHandler.contextId, + }; + } + + if (params.category === "browser_session_data_browser_element") { + this.emitEvent("received-session-data", { + contextId: this.messageHandler.contextId, + }); + } + + return {}; + } + + _getSessionDataUpdate(params) { + const lastUpdate = this._lastSessionDataUpdate; + + // Each "lastUpdate" should only be returned once, so that the caller can + // assert when a SessionData update had no impact. + this._lastSessionDataUpdate = null; + + return lastUpdate; + } + + testWindowGlobalModule() { + return "windowglobal-value"; + } + + testSetValue(params) { + const { value } = params; + + this._testValue = value; + } + + testGetValue() { + return this._testValue; + } + + testForwardToWindowGlobal() { + return "forward-to-windowglobal-value"; + } + + testIsCreatedByMessageHandlerConstructor() { + return this._createdByMessageHandlerConstructor; + } + + _isCreatedByMessageHandlerConstructor() { + let caller = Components.stack.caller; + while (caller) { + if (caller.name === this.messageHandler.constructor.name) { + return true; + } + caller = caller.caller; + } + return false; + } +} + +export const command = CommandModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/commandwindowglobalonly.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/commandwindowglobalonly.sys.mjs new file mode 100644 index 0000000000..1e4e6c1574 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/commandwindowglobalonly.sys.mjs @@ -0,0 +1,41 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class CommandWindowGlobalOnlyModule extends Module { + destroy() {} + + /** + * Commands + */ + + testOnlyInWindowGlobal() { + return "only-in-windowglobal"; + } + + testBroadcast() { + return `broadcast-${this.messageHandler.contextId}`; + } + + testBroadcastWithParameter(params) { + return `broadcast-${this.messageHandler.contextId}-${params.value}`; + } + + testError() { + throw new Error("error-from-module"); + } + + testMissingIntermediaryMethod(params, destination) { + // Spawn a new internal command, but with a commandName which doesn't match + // any method. + return this.messageHandler.handleCommand({ + moduleName: "commandwindowglobalonly", + commandName: "missingMethod", + destination, + }); + } +} + +export const commandwindowglobalonly = CommandWindowGlobalOnlyModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/event.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/event.sys.mjs new file mode 100644 index 0000000000..5bb50cb83d --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/event.sys.mjs @@ -0,0 +1,26 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class EventModule extends Module { + destroy() {} + + /** + * Commands + */ + + testEmitEvent() { + // Emit a payload including the contextId to check which context emitted + // a specific event. + const text = `event from ${this.messageHandler.contextId}`; + this.emitEvent("event-from-window-global", { text }); + } + + testEmitEventWithInterception() { + this.emitEvent("event.testEventWithInterception", {}); + } +} + +export const event = EventModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventemitter.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventemitter.sys.mjs new file mode 100644 index 0000000000..c86954c5e0 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventemitter.sys.mjs @@ -0,0 +1,81 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class EventEmitterModule extends Module { + #isSubscribed; + #subscribedEvents; + + constructor(messageHandler) { + super(messageHandler); + this.#isSubscribed = false; + this.#subscribedEvents = new Set(); + } + + destroy() {} + + /** + * Commands + */ + + emitTestEvent() { + if (this.#isSubscribed) { + const text = `event from ${this.messageHandler.contextId}`; + this.emitEvent("eventemitter.testEvent", { text }); + } + + // Emit another event consistently for monitoring during the test. + this.emitEvent("eventemitter.monitoringEvent", {}); + } + + isSubscribed() { + return this.#isSubscribed; + } + + _applySessionData(params) { + const { category } = params; + if (category === "event") { + const filteredSessionData = params.sessionData.filter(item => + this.messageHandler.matchesContext(item.contextDescriptor) + ); + for (const event of this.#subscribedEvents.values()) { + const hasSessionItem = filteredSessionData.some( + item => item.value === event + ); + // If there are no session items for this context, we should unsubscribe from the event. + if (!hasSessionItem) { + this.#unsubscribeEvent(event); + } + } + + // Subscribe to all events, which have an item in SessionData + for (const { value } of filteredSessionData) { + this.#subscribeEvent(value); + } + } + } + + #subscribeEvent(event) { + if (event === "eventemitter.testEvent") { + if (this.#isSubscribed) { + throw new Error("Already subscribed to eventemitter.testEvent"); + } + this.#isSubscribed = true; + this.#subscribedEvents.add(event); + } + } + + #unsubscribeEvent(event) { + if (event === "eventemitter.testEvent") { + if (!this.#isSubscribed) { + throw new Error("Not subscribed to eventemitter.testEvent"); + } + this.#isSubscribed = false; + this.#subscribedEvents.delete(event); + } + } +} + +export const eventemitter = EventEmitterModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventnointercept.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventnointercept.sys.mjs new file mode 100644 index 0000000000..48bbfbf951 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/eventnointercept.sys.mjs @@ -0,0 +1,16 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +class EventNoInterceptModule extends Module { + destroy() {} + + testEvent() { + const text = `event no interception`; + this.emitEvent("eventnointercept.testEvent", { text }); + } +} + +export const eventnointercept = EventNoInterceptModule; diff --git a/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs new file mode 100644 index 0000000000..f7b2279018 --- /dev/null +++ b/remote/shared/messagehandler/test/browser/resources/modules/windowglobal/retry.sys.mjs @@ -0,0 +1,84 @@ +/* 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 { Module } from "chrome://remote/content/shared/messagehandler/Module.sys.mjs"; + +// Store counters in the JSM scope to persist them across reloads. +let callsToBlockedOneTime = 0; +let callsToBlockedTenTimes = 0; +let callsToBlockedElevenTimes = 0; + +// This module provides various commands which all hang for various reasons. +// The test is supposed to trigger the command and then destroy the +// JSWindowActor pair by any mean (eg a navigation) in order to trigger an +// AbortError and a retry. +class RetryModule extends Module { + destroy() {} + + /** + * Commands + */ + + // Resolves only if called while on the example.net domain. + async blockedOnNetDomain(params) { + // Note: we do not store a call counter here, because this is used for a + // cross-group navigation test, and the JSM will be loaded in different + // processes. + const uri = this.messageHandler.window.document.baseURI; + if (!uri.includes("example.net")) { + await new Promise(r => {}); + } + + return { ...params }; + } + + // Resolves only if called more than once. + async blockedOneTime(params) { + callsToBlockedOneTime++; + if (callsToBlockedOneTime < 2) { + await new Promise(r => {}); + } + + // Return: + // - params sent to the command to check that retries have correct params + // - the call counter + return { ...params, callsToCommand: callsToBlockedOneTime }; + } + + // Resolves only if called more than ten times (which is exactly the maximum + // of retry attempts). + async blockedTenTimes(params) { + callsToBlockedTenTimes++; + if (callsToBlockedTenTimes < 11) { + await new Promise(r => {}); + } + + // Return: + // - params sent to the command to check that retries have correct params + // - the call counter + return { ...params, callsToCommand: callsToBlockedTenTimes }; + } + + // Resolves only if called more than eleven times (which is greater than the + // maximum of retry attempts). + async blockedElevenTimes(params) { + callsToBlockedElevenTimes++; + if (callsToBlockedElevenTimes < 12) { + await new Promise(r => {}); + } + + // Return: + // - params sent to the command to check that retries have correct params + // - the call counter + return { ...params, callsToCommand: callsToBlockedElevenTimes }; + } + + cleanup() { + callsToBlockedOneTime = 0; + callsToBlockedTenTimes = 0; + callsToBlockedElevenTimes = 0; + } +} + +export const retry = RetryModule; |