Source code
Revision control
Copy as Markdown
Other Tools
/* 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
"use strict";
/* globals Services */
const { E10SUtils } = ChromeUtils.importESModule(
"resource://gre/modules/E10SUtils.sys.mjs"
);
const { Preferences } = ChromeUtils.importESModule(
"resource://gre/modules/Preferences.sys.mjs"
);
// eslint-disable-next-line mozilla/reject-importGlobalProperties
Cu.importGlobalProperties(["PathUtils"]);
this.test = class extends ExtensionAPI {
onStartup() {
ChromeUtils.registerWindowActor("TestSupport", {
child: {
esModuleURI:
},
allFrames: true,
});
ChromeUtils.registerProcessActor("TestSupportProcess", {
child: {
esModuleURI:
},
});
}
onShutdown(isAppShutdown) {
if (isAppShutdown) {
return;
}
ChromeUtils.unregisterWindowActor("TestSupport");
ChromeUtils.unregisterProcessActor("TestSupportProcess");
}
getAPI(context) {
/**
* Helper function for getting window or process actors.
*
* @param tabId - id of the tab; required
* @param actorName - a string; the name of the actor
* Default: "TestSupport" which is our test framework actor
* (you can still pass the second parameter when getting the TestSupport actor, for readability)
*
* @returns actor
*/
function getActorForTab(tabId, actorName = "TestSupport") {
const tab = context.extension.tabManager.get(tabId);
const { browsingContext } = tab.browser;
return browsingContext.currentWindowGlobal.getActor(actorName);
}
return {
test: {
/* Set prefs and returns set of saved prefs */
async setPrefs(oldPrefs, newPrefs) {
// Save old prefs
Object.assign(
oldPrefs,
...Object.keys(newPrefs)
.filter(key => !(key in oldPrefs))
.map(key => ({ [key]: Preferences.get(key, null) }))
);
// Set new prefs
Preferences.set(newPrefs);
return oldPrefs;
},
/* Restore prefs to old value. */
async restorePrefs(oldPrefs) {
for (const [name, value] of Object.entries(oldPrefs)) {
if (value === null) {
Preferences.reset(name);
} else {
Preferences.set(name, value);
}
}
},
/* Get pref values. */
async getPrefs(prefs) {
return Preferences.get(prefs);
},
/* Gets link color for a given selector. */
async getLinkColor(tabId, selector) {
return getActorForTab(tabId, "TestSupport").sendQuery(
"GetLinkColor",
{ selector }
);
},
async getRequestedLocales() {
return Services.locale.requestedLocales;
},
async getPidForTab(tabId) {
const tab = context.extension.tabManager.get(tabId);
const pids = E10SUtils.getBrowserPids(tab.browser);
return pids[0];
},
async waitForContentTransformsReceived(tabId) {
return getActorForTab(tabId).sendQuery(
"WaitForContentTransformsReceived"
);
},
async getAllBrowserPids() {
const pids = [];
const processes = ChromeUtils.getAllDOMProcesses();
for (const process of processes) {
if (process.remoteType && process.remoteType.startsWith("web")) {
pids.push(process.osPid);
}
}
return pids;
},
async killContentProcess(pid) {
const procs = ChromeUtils.getAllDOMProcesses();
for (const proc of procs) {
if (pid === proc.osPid) {
proc
.getActor("TestSupportProcess")
.sendAsyncMessage("KillContentProcess");
}
}
},
async addHistogram(id, value) {
return Services.telemetry.getHistogramById(id).add(value);
},
removeAllCertOverrides() {
const overrideService = Cc[
"@mozilla.org/security/certoverride;1"
].getService(Ci.nsICertOverrideService);
overrideService.clearAllOverrides();
},
async setScalar(id, value) {
return Services.telemetry.scalarSet(id, value);
},
async setResolutionAndScaleTo(tabId, resolution) {
return getActorForTab(tabId, "TestSupport").sendQuery(
"SetResolutionAndScaleTo",
{
resolution,
}
);
},
async getActive(tabId) {
const tab = context.extension.tabManager.get(tabId);
return tab.browser.docShellIsActive;
},
async getProfilePath() {
return PathUtils.profileDir;
},
async flushApzRepaints(tabId) {
// TODO: Note that `waitUntilApzStable` in apz_test_utils.js does
// flush APZ repaints in the parent process (i.e. calling
// nsIDOMWindowUtils.flushApzRepaints for the parent process) before
// flushApzRepaints is called for the target content document, if we
// still meet intermittent failures, we might want to do it here as
// well.
await getActorForTab(tabId, "TestSupport").sendQuery(
"FlushApzRepaints"
);
},
async zoomToFocusedInput(tabId) {
await getActorForTab(tabId, "TestSupport").sendQuery(
"ZoomToFocusedInput"
);
},
async promiseAllPaintsDone(tabId) {
await getActorForTab(tabId, "TestSupport").sendQuery(
"PromiseAllPaintsDone"
);
},
async usingGpuProcess() {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
Ci.nsIGfxInfo
);
return gfxInfo.usingGPUProcess;
},
async killGpuProcess() {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
Ci.nsIGfxInfo
);
return gfxInfo.killGPUProcessForTests();
},
async crashGpuProcess() {
const gfxInfo = Cc["@mozilla.org/gfx/info;1"].getService(
Ci.nsIGfxInfo
);
return gfxInfo.crashGPUProcessForTests();
},
async clearHSTSState() {
const sss = Cc["@mozilla.org/ssservice;1"].getService(
Ci.nsISiteSecurityService
);
return sss.clearAll();
},
async isSessionHistoryInParentRunning() {
return Services.appinfo.sessionHistoryInParent;
},
async isFissionRunning() {
return Services.appinfo.fissionAutostart;
},
async triggerCookieBannerDetected(tabId) {
const actor = getActorForTab(tabId, "CookieBanner");
return actor.receiveMessage({
name: "CookieBanner::DetectedBanner",
});
},
async triggerCookieBannerHandled(tabId) {
const actor = getActorForTab(tabId, "CookieBanner");
return actor.receiveMessage({
name: "CookieBanner::HandledBanner",
});
},
async triggerTranslationsOffer(tabId) {
const browser = context.extension.tabManager.get(tabId).browser;
const { CustomEvent } = browser.ownerGlobal;
return browser.dispatchEvent(
new CustomEvent("TranslationsParent:OfferTranslation", {
bubbles: true,
})
);
},
async triggerLanguageStateChange(tabId, languageState) {
const browser = context.extension.tabManager.get(tabId).browser;
const { CustomEvent } = browser.ownerGlobal;
return browser.dispatchEvent(
new CustomEvent("TranslationsParent:LanguageState", {
bubbles: true,
detail: languageState,
})
);
},
},
};
}
};