"use strict"; const { ExtensionProcessScript } = ChromeUtils.importESModule( "resource://gre/modules/ExtensionProcessScript.sys.mjs" ); let experimentAPIs = { userinputtest: { schema: "schema.json", parent: { scopes: ["addon_parent"], script: "parent.js", paths: [["userinputtest"]], }, child: { scopes: ["addon_child"], script: "child.js", paths: [["userinputtest", "child"]], }, }, }; let experimentFiles = { "schema.json": JSON.stringify([ { namespace: "userinputtest", functions: [ { name: "test", type: "function", async: true, requireUserInput: true, parameters: [], }, { name: "child", type: "function", async: true, requireUserInput: true, parameters: [], }, ], }, ]), /* globals ExtensionAPI */ "parent.js": () => { this.userinputtest = class extends ExtensionAPI { getAPI() { return { userinputtest: { test() {}, }, }; } }; }, "child.js": () => { this.userinputtest = class extends ExtensionAPI { getAPI() { return { userinputtest: { child() {}, }, }; } }; }, }; // Set the "handlingUserInput" flag for the given extension's background page. // Returns an RAIIHelper that should be destruct()ed eventually. function setHandlingUserInput(extension) { let extensionChild = ExtensionProcessScript.getExtensionChild(extension.id); let bgwin = null; for (let view of extensionChild.views) { if (view.viewType == "background") { bgwin = view.contentWindow; break; } } notEqual(bgwin, null, "Found background window for the test extension"); let winutils = bgwin.windowUtils; return winutils.setHandlingUserInput(true); } // Test that the schema requireUserInput flag works correctly for // proxied api implementations. add_task(async function test_proxy() { let extension = ExtensionTestUtils.loadExtension({ isPrivileged: true, background() { browser.test.onMessage.addListener(async () => { try { await browser.userinputtest.test(); browser.test.sendMessage("result", null); } catch (err) { browser.test.sendMessage("result", err.message); } }); }, manifest: { permissions: ["experiments.userinputtest"], experiment_apis: experimentAPIs, }, files: experimentFiles, }); await extension.startup(); extension.sendMessage("test"); let result = await extension.awaitMessage("result"); ok( /test may only be called from a user input handler/.test(result), `function failed when not called from a user input handler: ${result}` ); let handle = setHandlingUserInput(extension); extension.sendMessage("test"); result = await extension.awaitMessage("result"); equal( result, null, "function succeeded when called from a user input handler" ); handle.destruct(); await extension.unload(); }); // Test that the schema requireUserInput flag works correctly for // non-proxied api implementations. add_task(async function test_local() { let extension = ExtensionTestUtils.loadExtension({ isPrivileged: true, background() { browser.test.onMessage.addListener(async () => { try { await browser.userinputtest.child(); browser.test.sendMessage("result", null); } catch (err) { browser.test.sendMessage("result", err.message); } }); }, manifest: { experiment_apis: experimentAPIs, }, files: experimentFiles, }); await extension.startup(); extension.sendMessage("test"); let result = await extension.awaitMessage("result"); ok( /child may only be called from a user input handler/.test(result), `function failed when not called from a user input handler: ${result}` ); let handle = setHandlingUserInput(extension); extension.sendMessage("test"); result = await extension.awaitMessage("result"); equal( result, null, "function succeeded when called from a user input handler" ); handle.destruct(); await extension.unload(); });