Bug 1866777 - Disable test_race_cache_with_network.js on windows opt for frequent...
[gecko.git] / testing / specialpowers / content / AppTestDelegateParent.sys.mjs
blobb271dea3df9aacf47627f7762ad2efef33c0d690
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 /**
6  * This module provides the bridge between the "AppTestDelegate" helper in
7  * mochitests and the supporting implementations in AppUiTestDelegate.sys.mjs.
8  *
9  * "AppTestDelegate" is documented in AppTestDelegate.sys.mjs and enables
10  * mochitests to invoke common functionality whose implementation is different
11  * (e.g. in browser/ and mobile/ instead of toolkit/).
12  * Tests can use this common interface after importing AppTestDelegate.sys.mjs:
13  *
14  *     // head.js, in the scope of a plain mochitest:
15  *     var { AppTestDelegate } = SpecialPowers.ChromeUtils.importESModule(
16  *       "resource://specialpowers/AppTestDelegate.sys.mjs"
17  *     );
18  *
19  *     // test usage example: open and close a tab.
20  *     let tab = await AppTestDelegate.openNewForegroundTab(window, url);
21  *     await AppTestDelegate.removeTab(window, tab);
22  *
23  * ## Overview of files supporting "AppTestDelegate":
24  *
25  * MOZ_BUILD_APP-specific AppUiTestDelegate.sys.mjs implementations:
26  * - browser/components/extensions/test/AppUiTestDelegate.jsm
27  * - mobile/android/modules/test/AppUiTestDelegate.jsm
28  * - mail/components/extensions/test/AppUiTestDelegate.sys.mjs (in comm-central)
29  *
30  * Glue between AppUiTestDelegate.sys.mjs in parent and test code in child:
31  * - testing/specialpowers/content/AppTestDelegateParent.sys.mjs (this file)
32  * - testing/specialpowers/content/AppTestDelegateChild.sys.mjs
33  * - testing/specialpowers/content/AppTestDelegate.sys.mjs
34  *
35  * Setup for usage by test code in child (i.e. plain mochitests):
36  * - Import AppTestDelegate.sys.mjs (e.g. in head.js or the test)
37  *
38  * Note: some browser-chrome tests import AppUiTestDelegate.sys.mjs directly,
39  * but that is not part of this API contract. They merely reuse code.
40  *
41  * ## How to add new AppTestDelegate methods
42  *
43  * - Add the method to AppTestDelegate.sys.mjs
44  * - Add a message forwarder in AppTestDelegateChild.sys.mjs
45  * - Add a message handler in AppTestDelegateParent.sys.mjs
46  * - Add an implementation in AppUiTestDelegate.sys.mjs for each MOZ_BUILD_APP,
47  *   by defining the method on the exported AppUiTestDelegate object.
48  *   All AppUiTestDelegate implementations must be kept in sync to have the
49  *   same interface!
50  *
51  * You should use the same method name across all of these files for ease of
52  * lookup and maintainability.
53  */
55 const lazy = {};
57 ChromeUtils.defineESModuleGetters(lazy, {
58   // Each app needs to implement this - see above comment.
59   AppUiTestDelegate: "resource://testing-common/AppUiTestDelegate.sys.mjs",
60 });
62 export class AppTestDelegateParent extends JSWindowActorParent {
63   constructor() {
64     super();
65     this._tabs = new Map();
66   }
68   get browser() {
69     return this.browsingContext.top.embedderElement;
70   }
72   get window() {
73     return this.browser.ownerGlobal;
74   }
76   async receiveMessage(message) {
77     const { extensionId, url, waitForLoad, tabId } = message.data;
78     switch (message.name) {
79       case "DOMContentLoaded":
80       case "load": {
81         return this.browser?.dispatchEvent(
82           new CustomEvent(`AppTestDelegate:${message.name}`, {
83             detail: {
84               browsingContext: this.browsingContext,
85               ...message.data,
86             },
87           })
88         );
89       }
90       case "clickPageAction":
91         return lazy.AppUiTestDelegate.clickPageAction(this.window, extensionId);
92       case "clickBrowserAction":
93         return lazy.AppUiTestDelegate.clickBrowserAction(
94           this.window,
95           extensionId
96         );
97       case "closePageAction":
98         return lazy.AppUiTestDelegate.closePageAction(this.window, extensionId);
99       case "closeBrowserAction":
100         return lazy.AppUiTestDelegate.closeBrowserAction(
101           this.window,
102           extensionId
103         );
104       case "awaitExtensionPanel":
105         // The desktop delegate returns a <browser>, but that cannot be sent
106         // over IPC, so just ignore it. The promise resolves when the panel and
107         // its content is fully loaded.
108         await lazy.AppUiTestDelegate.awaitExtensionPanel(
109           this.window,
110           extensionId
111         );
112         return null;
113       case "openNewForegroundTab": {
114         // We cannot send the tab object across process so let's store it with
115         // a unique ID here.
116         const uuid = Services.uuid.generateUUID().toString();
117         const tab = await lazy.AppUiTestDelegate.openNewForegroundTab(
118           this.window,
119           url,
120           waitForLoad
121         );
122         this._tabs.set(uuid, tab);
123         return uuid;
124       }
125       case "removeTab": {
126         const tab = this._tabs.get(tabId);
127         this._tabs.delete(tabId);
128         return lazy.AppUiTestDelegate.removeTab(tab);
129       }
131       default:
132         throw new Error(`Unknown Test API: ${message.name}.`);
133     }
134   }