diff options
Diffstat (limited to '')
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser.ini | 11 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_getActor.js | 47 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_getActor_filter.js | 80 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_observer_notification.js | 41 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_registerProcessActor.js | 16 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_sendAsyncMessage.js | 51 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_sendQuery.js | 99 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/browser_uri_combination.js | 81 | ||||
-rw-r--r-- | dom/ipc/tests/JSProcessActor/head.js | 79 |
9 files changed, 505 insertions, 0 deletions
diff --git a/dom/ipc/tests/JSProcessActor/browser.ini b/dom/ipc/tests/JSProcessActor/browser.ini new file mode 100644 index 0000000000..021b8d84d9 --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser.ini @@ -0,0 +1,11 @@ +[DEFAULT] +support-files = + head.js + +[browser_getActor.js] +[browser_getActor_filter.js] +[browser_observer_notification.js] +[browser_registerProcessActor.js] +[browser_sendAsyncMessage.js] +[browser_sendQuery.js] +[browser_uri_combination.js]
\ No newline at end of file diff --git a/dom/ipc/tests/JSProcessActor/browser_getActor.js b/dom/ipc/tests/JSProcessActor/browser_getActor.js new file mode 100644 index 0000000000..e111f1a274 --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_getActor.js @@ -0,0 +1,47 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +declTest("getActor on both sides", { + async test(browser) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + ok(parent, "WindowGlobalParent should have value."); + let actorParent = parent.getActor("TestProcessActor"); + is( + actorParent.show(), + "TestProcessActorParent", + "actor `show` should have value." + ); + is( + actorParent.manager, + parent, + "manager should match WindowGlobalParent.domProcess" + ); + + ok( + actorParent.sawActorCreated, + "Checking that we can observe parent creation" + ); + + await SpecialPowers.spawn(browser, [], async function () { + let child = ChromeUtils.domProcessChild; + ok(child, "WindowGlobalChild should have value."); + let actorChild = child.getActor("TestProcessActor"); + is( + actorChild.show(), + "TestProcessActorChild", + "actor show should have vaule." + ); + is( + actorChild.manager, + child, + "manager should match ChromeUtils.domProcessChild." + ); + + ok( + actorChild.sawActorCreated, + "Checking that we can observe child creation" + ); + }); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_getActor_filter.js b/dom/ipc/tests/JSProcessActor/browser_getActor_filter.js new file mode 100644 index 0000000000..f79340fd89 --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_getActor_filter.js @@ -0,0 +1,80 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +declTest("getActor with remoteType match", { + remoteTypes: ["web"], + + async test(browser) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + ok( + parent.getActor("TestProcessActor"), + "JSProcessActorParent should have value." + ); + + await SpecialPowers.spawn(browser, [], async function () { + let child = ChromeUtils.domProcessChild; + ok(child, "DOMProcessChild should have value."); + ok( + child.getActor("TestProcessActor"), + "JSProcessActorChild should have value." + ); + }); + }, +}); + +declTest("getActor with remoteType mismatch", { + remoteTypes: ["privilegedabout"], + url: TEST_URL, + + async test(browser) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + Assert.throws( + () => parent.getActor("TestProcessActor"), + /NotSupportedError/, + "Should throw if its remoteTypes don't match." + ); + + await SpecialPowers.spawn(browser, [], async function () { + let child = ChromeUtils.domProcessChild; + ok(child, "DOMProcessChild should have value."); + Assert.throws( + () => child.getActor("TestProcessActor"), + /NotSupportedError/, + "Should throw if its remoteTypes don't match." + ); + }); + }, +}); + +declTest("getActor without includeParent", { + includeParent: false, + + async test(_browser, win) { + let parent = win.docShell.browsingContext.currentWindowGlobal.domProcess; + SimpleTest.doesThrow( + () => parent.getActor("TestProcessActor"), + "Should throw if includeParent is false." + ); + + let child = ChromeUtils.domProcessChild; + SimpleTest.doesThrow( + () => child.getActor("TestProcessActor"), + "Should throw if includeParent is false." + ); + }, +}); + +declTest("getActor with includeParent", { + includeParent: true, + + async test(_browser, win) { + let parent = win.docShell.browsingContext.currentWindowGlobal.domProcess; + let actorParent = parent.getActor("TestProcessActor"); + ok(actorParent, "JSProcessActorParent should have value."); + + let child = ChromeUtils.domProcessChild; + let actorChild = child.getActor("TestProcessActor"); + ok(actorChild, "JSProcessActorChild should have value."); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_observer_notification.js b/dom/ipc/tests/JSProcessActor/browser_observer_notification.js new file mode 100644 index 0000000000..28dfa16481 --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_observer_notification.js @@ -0,0 +1,41 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +/* eslint-disable no-unused-vars */ +declTest("test observer triggering actor creation", { + async test(browser) { + await SpecialPowers.spawn(browser, [], async function () { + const TOPIC = "test-js-content-actor-child-observer"; + Services.obs.notifyObservers(content.window, TOPIC, "dataString"); + + let child = ChromeUtils.domProcessChild; + let actorChild = child.getActor("TestProcessActor"); + ok(actorChild, "JSProcessActorChild should have value."); + ok( + actorChild.lastObserved, + "JSProcessActorChild lastObserved should have value." + ); + let { subject, topic, data } = actorChild.lastObserved; + is(topic, TOPIC, "Topic matches"); + is(data, "dataString", "Data matches"); + }); + }, +}); + +declTest("test observers with null data", { + async test(browser) { + await SpecialPowers.spawn(browser, [], async function () { + const TOPIC = "test-js-content-actor-child-observer"; + Services.obs.notifyObservers(content.window, TOPIC); + + let child = ChromeUtils.domProcessChild; + let actorChild = child.getActor("TestProcessActor"); + ok(actorChild, "JSProcessActorChild should have value."); + let { subject, topic, data } = actorChild.lastObserved; + + is(topic, TOPIC, "Topic matches"); + is(data, null, "Data matches"); + }); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_registerProcessActor.js b/dom/ipc/tests/JSProcessActor/browser_registerProcessActor.js new file mode 100644 index 0000000000..1fa4e1c17c --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_registerProcessActor.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +declTest("double register", { + async test(_browser, _window, fileExt) { + SimpleTest.doesThrow( + () => + ChromeUtils.registerContentActor( + "TestProcessActor", + processActorOptions[fileExt] + ), + "Should throw if register has duplicate name." + ); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_sendAsyncMessage.js b/dom/ipc/tests/JSProcessActor/browser_sendAsyncMessage.js new file mode 100644 index 0000000000..02ad64ee8b --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_sendAsyncMessage.js @@ -0,0 +1,51 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +declTest("asyncMessage testing", { + async test(browser) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + let actorParent = parent.getActor("TestProcessActor"); + ok(actorParent, "JSProcessActorParent should have value."); + + await ContentTask.spawn(browser, {}, async function () { + let child = ChromeUtils.domProcessChild; + let actorChild = child.getActor("TestProcessActor"); + ok(actorChild, "JSProcessActorChild should have value."); + + let promise = new Promise(resolve => { + actorChild.sendAsyncMessage("init", {}); + actorChild.done = data => resolve(data); + }).then(data => { + ok(data.initial, "Initial should be true."); + ok(data.toParent, "ToParent should be true."); + ok(data.toChild, "ToChild should be true."); + }); + + await promise; + }); + }, +}); + +declTest("asyncMessage without both sides", { + async test(browser) { + // If we don't create a parent actor, make sure the parent actor + // gets created by having sent the message. + await ContentTask.spawn(browser, {}, async function () { + let child = ChromeUtils.domProcessChild; + let actorChild = child.getActor("TestProcessActor"); + ok(actorChild, "JSProcessActorChild should have value."); + + let promise = new Promise(resolve => { + actorChild.sendAsyncMessage("init", {}); + actorChild.done = data => resolve(data); + }).then(data => { + ok(data.initial, "Initial should be true."); + ok(data.toParent, "ToParent should be true."); + ok(data.toChild, "ToChild should be true."); + }); + + await promise; + }); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_sendQuery.js b/dom/ipc/tests/JSProcessActor/browser_sendQuery.js new file mode 100644 index 0000000000..5a9767bf3a --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_sendQuery.js @@ -0,0 +1,99 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const ERROR_LINE_NUMBERS = { + jsm: 31, + "sys.mjs": 28, +}; +const EXCEPTION_LINE_NUMBERS = { + jsm: ERROR_LINE_NUMBERS.jsm + 3, + "sys.mjs": ERROR_LINE_NUMBERS["sys.mjs"] + 3, +}; +const ERROR_COLUMN_NUMBERS = { + jsm: 31, + "sys.mjs": 31, +}; +const EXCEPTION_COLUMN_NUMBERS = { + jsm: 22, + "sys.mjs": 22, +}; + +function maybeAsyncStack(offset, column) { + if ( + Services.prefs.getBoolPref( + "javascript.options.asyncstack_capture_debuggee_only" + ) + ) { + return ""; + } + + let stack = Error().stack.replace(/^.*?\n/, ""); + return ( + "JSActor query*" + + stack.replace( + /^([^\n]+?):(\d+):\d+/, + (m0, m1, m2) => `${m1}:${+m2 + offset}:${column}` + ) + ); +} + +declTest("sendQuery Error", { + async test(browser, _window, fileExt) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + let actorParent = parent.getActor("TestProcessActor"); + + let asyncStack = maybeAsyncStack(2, 8); + let error = await actorParent + .sendQuery("error", { message: "foo" }) + .catch(e => e); + + is(error.message, "foo", "Error should have the correct message"); + is(error.name, "SyntaxError", "Error should have the correct name"); + is( + error.stack, + `receiveMessage@resource://testing-common/TestProcessActorChild.${fileExt}:${ERROR_LINE_NUMBERS[fileExt]}:${ERROR_COLUMN_NUMBERS[fileExt]}\n` + + asyncStack, + "Error should have the correct stack" + ); + }, +}); + +declTest("sendQuery Exception", { + async test(browser, _window, fileExt) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + let actorParent = parent.getActor("TestProcessActor"); + + let asyncStack = maybeAsyncStack(2, 8); + let error = await actorParent + .sendQuery("exception", { + message: "foo", + result: Cr.NS_ERROR_INVALID_ARG, + }) + .catch(e => e); + + is(error.message, "foo", "Error should have the correct message"); + is( + error.result, + Cr.NS_ERROR_INVALID_ARG, + "Error should have the correct result code" + ); + is( + error.stack, + `receiveMessage@resource://testing-common/TestProcessActorChild.${fileExt}:${EXCEPTION_LINE_NUMBERS[fileExt]}:${EXCEPTION_COLUMN_NUMBERS[fileExt]}\n` + + asyncStack, + "Error should have the correct stack" + ); + }, +}); + +declTest("sendQuery testing", { + async test(browser) { + let parent = browser.browsingContext.currentWindowGlobal.domProcess; + let actorParent = parent.getActor("TestProcessActor"); + ok(actorParent, "JSWindowActorParent should have value."); + + let { result } = await actorParent.sendQuery("asyncAdd", { a: 10, b: 20 }); + is(result, 30); + }, +}); diff --git a/dom/ipc/tests/JSProcessActor/browser_uri_combination.js b/dom/ipc/tests/JSProcessActor/browser_uri_combination.js new file mode 100644 index 0000000000..33394cf54a --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/browser_uri_combination.js @@ -0,0 +1,81 @@ +add_task(function specify_both() { + // Specifying both should throw. + + SimpleTest.doesThrow(() => { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + moduleURI: "resource://testing-common/TestProcessActorParent.jsm", + }, + child: { + moduleURI: "resource://testing-common/TestProcessActorChild.jsm", + esModuleURI: "resource://testing-common/TestProcessActorChild.sys.mjs", + }, + }); + }, "Should throw if both moduleURI and esModuleURI are specified."); + + SimpleTest.doesThrow(() => { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + esModuleURI: "resource://testing-common/TestProcessActorParent.sys.mjs", + }, + child: { + moduleURI: "resource://testing-common/TestProcessActorChild.jsm", + esModuleURI: "resource://testing-common/TestProcessActorChild.sys.mjs", + }, + }); + }, "Should throw if both moduleURI and esModuleURI are specified."); + + SimpleTest.doesThrow(() => { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + moduleURI: "resource://testing-common/TestProcessActorParent.jsm", + esModuleURI: "resource://testing-common/TestProcessActorParent.sys.mjs", + }, + child: { + moduleURI: "resource://testing-common/TestProcessActorChild.jsm", + }, + }); + }, "Should throw if both moduleURI and esModuleURI are specified."); + + SimpleTest.doesThrow(() => { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + moduleURI: "resource://testing-common/TestProcessActorParent.jsm", + esModuleURI: "resource://testing-common/TestProcessActorParent.sys.mjs", + }, + child: { + esModuleURI: "resource://testing-common/TestProcessActorChild.sys.mjs", + }, + }); + }, "Should throw if both moduleURI and esModuleURI are specified."); +}); + +add_task(function specify_mixed() { + // Mixing JSM and ESM should work. + + try { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + moduleURI: "resource://testing-common/TestProcessActorParent.jsm", + }, + child: { + esModuleURI: "resource://testing-common/TestProcessActorChild.sys.mjs", + }, + }); + } finally { + ChromeUtils.unregisterProcessActor("TestProcessActor"); + } + + try { + ChromeUtils.registerProcessActor("TestProcessActor", { + parent: { + esModuleURI: "resource://testing-common/TestProcessActorParent.sys.mjs", + }, + child: { + moduleURI: "resource://testing-common/TestProcessActorChild.jsm", + }, + }); + } finally { + ChromeUtils.unregisterProcessActor("TestProcessActor"); + } +}); diff --git a/dom/ipc/tests/JSProcessActor/head.js b/dom/ipc/tests/JSProcessActor/head.js new file mode 100644 index 0000000000..e19e9d5ff4 --- /dev/null +++ b/dom/ipc/tests/JSProcessActor/head.js @@ -0,0 +1,79 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +/** + * Provide infrastructure for JSProcessActor tests. + */ + +const URL = "about:blank"; +const TEST_URL = "http://test2.example.org/"; +let processActorOptions = { + jsm: { + parent: { + moduleURI: "resource://testing-common/TestProcessActorParent.jsm", + }, + child: { + moduleURI: "resource://testing-common/TestProcessActorChild.jsm", + observers: ["test-js-content-actor-child-observer"], + }, + }, + "sys.mjs": { + parent: { + esModuleURI: "resource://testing-common/TestProcessActorParent.sys.mjs", + }, + child: { + esModuleURI: "resource://testing-common/TestProcessActorChild.sys.mjs", + observers: ["test-js-content-actor-child-observer"], + }, + }, +}; + +function promiseNotification(aNotification) { + let notificationResolve; + let notificationObserver = function observer() { + notificationResolve(); + Services.obs.removeObserver(notificationObserver, aNotification); + }; + return new Promise(resolve => { + notificationResolve = resolve; + Services.obs.addObserver(notificationObserver, aNotification); + }); +} + +function declTest(name, cfg) { + declTestWithOptions(name, cfg, "jsm"); + declTestWithOptions(name, cfg, "sys.mjs"); +} + +function declTestWithOptions(name, cfg, fileExt) { + let { url = "about:blank", includeParent = false, remoteTypes, test } = cfg; + + // Build the actor options object which will be used to register & unregister + // our process actor. + let actorOptions = { + parent: Object.assign({}, processActorOptions[fileExt].parent), + child: Object.assign({}, processActorOptions[fileExt].child), + }; + actorOptions.includeParent = includeParent; + if (remoteTypes !== undefined) { + actorOptions.remoteTypes = remoteTypes; + } + + // Add a new task for the actor test declared here. + add_task(async function () { + info("Entering test: " + name); + + // Register our actor, and load a new tab with the provided URL + ChromeUtils.registerProcessActor("TestProcessActor", actorOptions); + try { + await BrowserTestUtils.withNewTab(url, async browser => { + info("browser ready"); + await Promise.resolve(test(browser, window, fileExt)); + }); + } finally { + // Unregister the actor after the test is complete. + ChromeUtils.unregisterProcessActor("TestProcessActor"); + info("Exiting test: " + name); + } + }); +} |