summaryrefslogtreecommitdiffstats
path: root/dom/base/test/test_postMessages.html
diff options
context:
space:
mode:
Diffstat (limited to 'dom/base/test/test_postMessages.html')
-rw-r--r--dom/base/test/test_postMessages.html654
1 files changed, 654 insertions, 0 deletions
diff --git a/dom/base/test/test_postMessages.html b/dom/base/test/test_postMessages.html
new file mode 100644
index 000000000..13a284270
--- /dev/null
+++ b/dom/base/test/test_postMessages.html
@@ -0,0 +1,654 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+ <title>Test for postMessages cloning/transferring objects</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+
+<body>
+<input id="fileList" type="file"></input>
+<script type="application/javascript;version=1.7">
+
+function setup_tests() {
+ SpecialPowers.pushPrefEnv({"set": [["dom.input.dirpicker", true],
+ ["javascript.options.wasm", true]]}, next);
+}
+
+function getType(a) {
+ if (a === null || a === undefined)
+ return 'null';
+
+ if (Array.isArray(a))
+ return 'array';
+
+ if (typeof a == 'object')
+ return 'object';
+
+ if (SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported() &&
+ a instanceof WebAssembly.Module)
+ return "wasm";
+
+ return 'primitive';
+}
+
+function compare(a, b) {
+ is (getType(a), getType(b), 'Type matches');
+
+ var type = getType(a);
+ if (type == 'array') {
+ is (a.length, b.length, 'Array.length matches');
+ for (var i = 0; i < a.length; ++i) {
+ compare(a[i], b[i]);
+ }
+
+ return;
+ }
+
+ if (type == 'object') {
+ ok (a !== b, 'They should not match');
+
+ var aProps = [];
+ for (var p in a) aProps.push(p);
+
+ var bProps = [];
+ for (var p in b) bProps.push(p);
+
+ is (aProps.length, bProps.length, 'Props match');
+ is (aProps.sort().toSource(), bProps.sort().toSource(), 'Props match - using toSource()');
+
+ for (var p in a) {
+ compare(a[p], b[p]);
+ }
+
+ return;
+ }
+
+ if (type == 'wasm') {
+ var wasmA = new WebAssembly.Instance(a);
+ ok(wasmA instanceof WebAssembly.Instance, "got an instance");
+
+ var wasmB = new WebAssembly.Instance(b);
+ ok(wasmB instanceof WebAssembly.Instance, "got an instance");
+
+ ok(wasmA.exports.foo() === wasmB.exports.foo(), "Same result!");
+ ok(wasmB.exports.foo() === 42, "We want 42");
+ }
+
+ if (type != 'null') {
+ is (a.toSource(), b.toSource(), 'Matching using toSource()');
+ }
+}
+
+var clonableObjects = [
+ { target: 'all', data: 'hello world' },
+ { target: 'all', data: 123 },
+ { target: 'all', data: null },
+ { target: 'all', data: true },
+ { target: 'all', data: new Date() },
+ { target: 'all', data: [ 1, 'test', true, new Date() ] },
+ { target: 'all', data: { a: true, b: null, c: new Date(), d: [ true, false, {} ] } },
+ { target: 'all', data: new Blob([123], { type: 'plain/text' }) },
+ { target: 'all', data: new ImageData(2, 2) },
+];
+
+function create_fileList() {
+ var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
+ var script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ var fileList = document.getElementById('fileList');
+ SpecialPowers.wrap(fileList).mozSetFileArray([message.file]);
+
+ // Just a simple test
+ var domFile = fileList.files[0];
+ is(domFile.name, "prefs.js", "fileName should be prefs.js");
+
+ clonableObjects.push({ target: 'all', data: fileList.files });
+ script.destroy();
+ next();
+ }
+
+ script.addMessageListener("file.opened", onOpened);
+ script.sendAsyncMessage("file.open");
+}
+
+function create_directory() {
+ if (navigator.userAgent.toLowerCase().indexOf('Android') != -1) {
+ next();
+ return;
+ }
+
+ var url = SimpleTest.getTestFileURL("script_postmessages_fileList.js");
+ var script = SpecialPowers.loadChromeScript(url);
+
+ function onOpened(message) {
+ var fileList = document.getElementById('fileList');
+ SpecialPowers.wrap(fileList).mozSetDirectory(message.dir);
+
+ fileList.getFilesAndDirectories().then(function(list) {
+ // Just a simple test
+ is(list.length, 1, "This list has 1 element");
+ ok(list[0] instanceof Directory, "We have a directory.");
+
+ clonableObjects.push({ target: 'all', data: list[0] });
+ script.destroy();
+ next();
+ });
+ }
+
+ script.addMessageListener("dir.opened", onOpened);
+ script.sendAsyncMessage("dir.open");
+}
+
+function create_wasmModule() {
+ info("Checking if we can play with WebAssembly...");
+
+ if (!SpecialPowers.Cu.getJSTestingFunctions().wasmIsSupported()) {
+ next();
+ return;
+ }
+
+ ok(WebAssembly, "WebAssembly object should exist");
+ ok(WebAssembly.compile, "WebAssembly.compile function should exist");
+
+ const wasmTextToBinary = SpecialPowers.unwrap(SpecialPowers.Cu.getJSTestingFunctions().wasmTextToBinary);
+ const fooModuleCode = wasmTextToBinary(`(module
+ (func $foo (result i32) (i32.const 42))
+ (export "foo" $foo)
+ )`, 'new-format');
+
+ WebAssembly.compile(fooModuleCode).then((m) => {
+ ok(m instanceof WebAssembly.Module, "The WasmModule has been compiled.");
+ clonableObjects.push({ target: 'sameProcess', data: m });
+ next();
+ }, () => {
+ ok(false, "The compilation of the wasmModule failed.");
+ });
+}
+
+function runTests(obj) {
+ ok(('clonableObjectsEveryWhere' in obj) &&
+ ('clonableObjectsSameProcess' in obj) &&
+ ('transferableObjects' in obj) &&
+ (obj.clonableObjectsEveryWhere || obj.clonableObjectsSameProcess || obj.transferableObjects), "We must run some test!");
+
+ // cloning tests - everyWhere
+ new Promise(function(resolve, reject) {
+ if (!obj.clonableObjectsEveryWhere) {
+ resolve();
+ return;
+ }
+
+ var clonableObjectsId = 0;
+ function runClonableTest() {
+ if (clonableObjectsId >= clonableObjects.length) {
+ resolve();
+ return;
+ }
+
+ var object = clonableObjects[clonableObjectsId++];
+
+ if (object.target != 'all') {
+ runClonableTest();
+ return;
+ }
+
+ obj.send(object.data, []).then(function(received) {
+ compare(received.data, object.data);
+ runClonableTest();
+ });
+ }
+
+ runClonableTest();
+ })
+
+ // clonable same process
+ .then(function() {
+ return new Promise(function(resolve, reject) {
+ if (!obj.clonableObjectsSameProcess) {
+ resolve();
+ return;
+ }
+
+ var clonableObjectsId = 0;
+ function runClonableTest() {
+ if (clonableObjectsId >= clonableObjects.length) {
+ resolve();
+ return;
+ }
+
+ var object = clonableObjects[clonableObjectsId++];
+
+ if (object.target != 'sameProcess') {
+ runClonableTest();
+ return;
+ }
+
+ obj.send(object.data, []).then(function(received) {
+ compare(received.data, object.data);
+ runClonableTest();
+ });
+ }
+
+ runClonableTest();
+ });
+ })
+
+ // transfering tests
+ .then(function() {
+ if (!obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function(r, rr) {
+ var mc = new MessageChannel();
+ obj.send(42, [mc.port1]).then(function(received) {
+ ok(received.ports.length, 1, "MessagePort has been transferred");
+ mc.port2.postMessage("hello world");
+ received.ports[0].onmessage = function(e) {
+ ok(e.data, "hello world", "Ports are connected!");
+ r();
+ }
+ });
+ });
+ })
+
+ // no dup transfering
+ .then(function() {
+ if (!obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function(r, rr) {
+ var mc = new MessageChannel();
+ obj.send(42, [mc.port1, mc.port1]).then(function(received) {
+ ok(false, "Duplicate ports should throw!");
+ }, function() {
+ ok(true, "Duplicate ports should throw!");
+ })
+ .then(r);
+ });
+ })
+
+ // non transfering tests
+ .then(function() {
+ if (obj.transferableObjects) {
+ return;
+ }
+
+ // MessagePort
+ return new Promise(function(r, rr) {
+ var mc = new MessageChannel();
+ obj.send(42, [mc.port1]).then(function(received) {
+ ok(false, "This object should not support port transferring");
+ }, function() {
+ ok(true, "This object should not support port transferring");
+ })
+ .then(r);
+ });
+ })
+
+ // done.
+ .then(function() {
+ obj.finished();
+ });
+}
+
+// PostMessage to the same window.
+function test_windowToWindow() {
+ info("Testing window to window");
+ var resolve;
+
+ onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+
+ try {
+ postMessage(what, '*', ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+}
+
+// PostMessage to iframe
+function test_windowToIframe() {
+ info("Testing window to iframe");
+ test_windowToIframeURL('iframe_postMessages.html');
+}
+
+// PostMessage to cross-origin iframe
+function test_windowToCrossOriginIframe() {
+ info("Testing window to cross-origin iframe");
+ test_windowToIframeURL('http://example.com/tests/dom/base/test/iframe_postMessages.html');
+}
+
+// iframe helper class
+function test_windowToIframeURL(url) {
+ var resolve;
+
+ onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ var ifr = document.createElement('iframe');
+ ifr.src = url;
+ ifr.onload = function() {
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ ifr.contentWindow.postMessage(what, '*', ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished: function() {
+ document.body.removeChild(ifr);
+ onmessage = null;
+ next();
+ }
+ });
+ }
+ document.body.appendChild(ifr);
+}
+
+// PostMessage for Workers
+function test_workers() {
+ info("Testing Workers");
+
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('workers');
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: true,
+ transferableObjects: true,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ w.postMessage(what, ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+ }
+}
+
+// PostMessage for BroadcastChannel
+function test_broadcastChannel() {
+ info("Testing broadcastChannel");
+
+ var bc1 = new BroadcastChannel('postMessagesTest');
+ var bc2 = new BroadcastChannel('postMessagesTest');
+
+ var resolve;
+
+ bc2.onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: [] });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: false,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ if (ports.length) {
+ rr();
+ return;
+ }
+
+ resolve = r;
+ bc1.postMessage(what);
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+}
+
+// PostMessage for BroadcastChannel in workers
+function test_broadcastChannel_inWorkers() {
+ info("Testing broadcastChannel in Workers");
+
+ var bc = new BroadcastChannel('postMessagesTest_inWorkers');
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('broadcastChannel');
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: false,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ if (ports.length) {
+ rr();
+ return;
+ }
+
+ resolve = r;
+ bc.postMessage(what);
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+ }
+}
+
+// PostMessage for MessagePort
+function test_messagePort() {
+ info("Testing messagePort");
+
+ var mc = new MessageChannel();
+ var resolve;
+
+ mc.port2.onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: true,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ mc.port1.postMessage(what, ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+}
+
+// PostMessage for MessagePort in Workers
+function test_messagePort_inWorkers() {
+ info("Testing messagePort in workers");
+
+ var mc = new MessageChannel();
+ var resolve;
+
+ var w = new Worker('worker_postMessages.js');
+ w.postMessage('messagePort', [ mc.port2 ]);
+ w.onmessage = function(e) {
+ is(e.data, 'ok', "Worker ready!");
+
+ w.onmessage = function(e) {
+ if (!resolve) {
+ ok(false, "Unexpected message!");
+ return;
+ }
+
+ let tmp = resolve;
+ resolve = null;
+ tmp({ data: e.data, ports: e.ports });
+ }
+
+ runTests({
+ clonableObjectsEveryWhere: true,
+ clonableObjectsSameProcess: false,
+ transferableObjects: true,
+ send: function(what, ports) {
+ return new Promise(function(r, rr) {
+ resolve = r;
+ try {
+ mc.port1.postMessage(what, ports);
+ } catch(e) {
+ resolve = null;
+ rr();
+ }
+ });
+ },
+
+ finished: function() {
+ onmessage = null;
+ next();
+ }
+ });
+ }
+}
+
+var tests = [
+ setup_tests,
+
+ create_fileList,
+ create_directory,
+ create_wasmModule,
+
+ test_windowToWindow,
+ test_windowToIframe,
+ test_windowToCrossOriginIframe,
+
+ test_workers,
+
+ test_broadcastChannel,
+ test_broadcastChannel_inWorkers,
+
+ test_messagePort,
+ test_messagePort_inWorkers,
+];
+
+function next() {
+ if (!tests.length) {
+ SimpleTest.finish();
+ return;
+ }
+
+ var test = tests.shift();
+ test();
+}
+
+SimpleTest.waitForExplicitFinish();
+next();
+</script>
+</body>
+</html>