summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webmessaging
diff options
context:
space:
mode:
Diffstat (limited to 'testing/web-platform/tests/webmessaging')
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_Blob.any.js33
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_DataCloneErr.any.js14
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port.any.js31
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port_error.any.js14
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_event_properties.any.js24
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_ports_readonly_array.any.js28
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_target_source.any.js23
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js32
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_entangled.any.js36
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_incoming_messages.any.js32
-rw-r--r--testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_outgoing_messages.any.js35
-rw-r--r--testing/web-platform/tests/webmessaging/META.yml6
-rw-r--r--testing/web-platform/tests/webmessaging/MessageEvent-trusted.any.js32
-rw-r--r--testing/web-platform/tests/webmessaging/MessageEvent-trusted.window.js9
-rw-r--r--testing/web-platform/tests/webmessaging/MessageEvent.any.js22
-rw-r--r--testing/web-platform/tests/webmessaging/MessageEvent_onmessage_postMessage_infinite_loop.html31
-rw-r--r--testing/web-platform/tests/webmessaging/MessageEvent_properties.htm32
-rw-r--r--testing/web-platform/tests/webmessaging/MessagePort_initial_disabled.any.js10
-rw-r--r--testing/web-platform/tests/webmessaging/MessagePort_onmessage_start.any.js10
-rw-r--r--testing/web-platform/tests/webmessaging/README.md2
-rw-r--r--testing/web-platform/tests/webmessaging/Transferred_objects_unusable.sub.htm60
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/basics.any.js128
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/blobs.html82
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/cross-origin.html38
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/cross-partition.https.tentative.html356
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/detached-iframe.html174
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/interface.any.js65
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/opaque-origin.html193
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/ordering.html116
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/origin.window.js10
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/cross-origin.html15
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/ordering.html78
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/origin.html8
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/sandboxed.html10
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/service-worker.js15
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/resources/worker.js37
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/sandbox.html16
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/service-worker.https.html47
-rw-r--r--testing/web-platform/tests/webmessaging/broadcastchannel/workers.html375
-rw-r--r--testing/web-platform/tests/webmessaging/event.data.sub.htm44
-rw-r--r--testing/web-platform/tests/webmessaging/event.origin.sub.htm66
-rw-r--r--testing/web-platform/tests/webmessaging/event.ports.sub.htm49
-rw-r--r--testing/web-platform/tests/webmessaging/event.source.htm51
-rw-r--r--testing/web-platform/tests/webmessaging/event.source.xorigin.sub.htm51
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/basics.any.js12
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/close.any.js62
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/cross-document.html22
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/detached-iframe.window.js46
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/dictionary-transferrable.any.js13
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/implied-start.any.js14
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/no-start.any.js9
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-1.html8
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-2.html10
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/user-activation.tentative.any.js21
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/worker-post-after-close.any.js28
-rw-r--r--testing/web-platform/tests/webmessaging/message-channels/worker.any.js17
-rw-r--r--testing/web-platform/tests/webmessaging/messageerror.html44
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-current.sub.html45
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-incumbent.sub.html34
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/messageport-current.html39
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/messageport-incumbent.html35
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/support/current-document-domain.sub.html10
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/support/current.html5
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/support/incumbent-document-domain.sub.html14
-rw-r--r--testing/web-platform/tests/webmessaging/multi-globals/support/incumbent.html13
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_ArrayBuffer.sub.htm44
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_CryptoKey_insecure.sub.html20
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_Date.sub.htm40
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_Document.htm36
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_Function.htm36
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_MessagePorts_sorigin.htm76
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xorigin.sub.htm76
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xsite.sub.window.js66
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_arrays.sub.htm39
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_asterisk_xorigin.sub.htm52
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_cross_domain_image_transfer_2d.sub.htm34
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_crosssite.sub.htm29
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_dup_transfer_objects.htm38
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_invalid_targetOrigin.htm38
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_objects.sub.htm40
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_origin_mismatch.sub.htm51
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_origin_mismatch_xorigin.sub.htm51
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_solidus_sorigin.htm43
-rw-r--r--testing/web-platform/tests/webmessaging/postMessage_solidus_xorigin.sub.htm48
-rw-r--r--testing/web-platform/tests/webmessaging/resources/post-cryptokey-to-opener.html6
-rw-r--r--testing/web-platform/tests/webmessaging/resources/transfer-arraybuffer-to-parent.html5
-rw-r--r--testing/web-platform/tests/webmessaging/support/ChildWindowPostMessage.htm58
-rw-r--r--testing/web-platform/tests/webmessaging/support/MessageEvent-trusted-worker.js4
-rw-r--r--testing/web-platform/tests/webmessaging/support/compare.js39
-rw-r--r--testing/web-platform/tests/webmessaging/support/cross-domain-image-receive.htm25
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/broken-origin.html12
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/host-specific-origin.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/message-channel-transferable.html15
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/no-target-origin.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/null-transfer.html10
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/one-arg.html13
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/slash-origin.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/undefined-transferable.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-options/unknown-parameter.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/001.html12
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/002.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/003.html12
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/004.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/005.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/006.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/007.html14
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/010.html113
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/011.html29
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/012.html16
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/013.html17
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/014.html17
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/015.html15
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/016.html23
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/017.html18
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/018.html18
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/019.html20
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/020.html32
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/021.html32
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/023.html11
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/024.html15
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/025.html13
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/026.html13
-rw-r--r--testing/web-platform/tests/webmessaging/with-ports/027.html26
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/001.html12
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/002.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/003.html12
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/004.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/005.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/006.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/007.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/009.html12
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/010.html112
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/011.html29
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/012.html16
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/013.html17
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/014.html17
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/015.html15
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/016.html23
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/017.html18
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/018.html17
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/019-1.html1
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/019.html20
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/020-1.html5
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/020.html32
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/021.html32
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/023.html29
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/024.html14
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/025-1.js15
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/025.html13
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/026.html17
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/027.html19
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/028.html19
-rw-r--r--testing/web-platform/tests/webmessaging/without-ports/029.html20
-rw-r--r--testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.js3
-rw-r--r--testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.tentative.html19
155 files changed, 5305 insertions, 0 deletions
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_Blob.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_Blob.any.js
new file mode 100644
index 0000000000..fce814f588
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_Blob.any.js
@@ -0,0 +1,33 @@
+// META: title=postMessage() with a Blob
+// META: script=/common/gc.js
+
+ var TARGET = null;
+ var SOURCE = null;
+ var description = "Messages can contain Blobs.";
+
+ var t = async_test("Test Description: " + description);
+
+ var channel = new MessageChannel();
+ SOURCE = channel.port1;
+ TARGET = channel.port2;
+ TARGET.start();
+ TARGET.addEventListener("message", t.step_func(TestMessageEvent), true);
+
+ (function() {
+ SOURCE.postMessage({blob: new Blob(['foo', 'bar'])});
+ })();
+ garbageCollect();
+
+ function TestMessageEvent(evt)
+ {
+ assert_true('blob' in evt.data);
+ assert_true(evt.data.blob instanceof Blob);
+ assert_equals(evt.data.blob.size, 6);
+ const reader = new FileReader();
+ reader.onerror = t.unreached_func('Reading blob failed');
+ reader.onload = t.step_func(() => {
+ assert_equals(reader.result, 'foobar');
+ t.done();
+ });
+ reader.readAsText(evt.data.blob);
+ }
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_DataCloneErr.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_DataCloneErr.any.js
new file mode 100644
index 0000000000..048820fa6b
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_DataCloneErr.any.js
@@ -0,0 +1,14 @@
+// META: title=postMessage() with a host object raises DataCloneError
+
+ var description = "Throw a DataCloneError when a host object (e.g. a DOM node) is used with postMessage.";
+
+ test(function()
+ {
+ var channel = new MessageChannel();
+ channel.port1.start();
+
+ assert_throws_dom("DATA_CLONE_ERR", function()
+ {
+ channel.port1.postMessage(globalThis);
+ });
+ }, description);
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port.any.js
new file mode 100644
index 0000000000..3dcb902b77
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port.any.js
@@ -0,0 +1,31 @@
+// META: title=postMessage(): clone a port
+
+ var OriginalPort = null;
+ var ClonedPort = null;
+ var description = "Test Description: When the user agent is to clone a port original port, with "
+ + "the clone being owned by owner, it must return a new MessagePort object";
+
+ var t = async_test("Test Description: " + description);
+
+ var ChannelA = new MessageChannel();
+ var ChannelB = new MessageChannel();
+ OriginalPort = ChannelB.port2;
+
+ ChannelA.port2.onmessage = t.step_func(function(evt)
+ {
+ if(evt.data == "ports")
+ {
+ ClonedPort = evt.ports[0];
+
+ assert_not_equals(ClonedPort, OriginalPort, "new cloned port object should not equal to the original port!");
+
+ ClonedPort.onmessage = function(e)
+ {
+ test(function(){ assert_equals(e.data, "ping"); }, "Data sent through remote port is received by the new cloned port");
+ t.done();
+ }
+ }
+ });
+
+ ChannelA.port1.postMessage("ports", [OriginalPort]);
+ ChannelB.port1.postMessage("ping");
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port_error.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port_error.any.js
new file mode 100644
index 0000000000..cbee47270c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_clone_port_error.any.js
@@ -0,0 +1,14 @@
+// META: title=postMessage() DataCloneError: cloning source port
+
+ var description = "Test Description: Throw a DataCloneError if transfer array in postMessage contains source port.";
+
+ test(function()
+ {
+ var channel = new MessageChannel();
+ channel.port1.start();
+
+ assert_throws_dom("DATA_CLONE_ERR", function()
+ {
+ channel.port1.postMessage("ports", [channel.port1]);
+ });
+ }, description);
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_event_properties.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_event_properties.any.js
new file mode 100644
index 0000000000..0fd8c7e90a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_event_properties.any.js
@@ -0,0 +1,24 @@
+// META: title=postMessage(): MessageEvent properties
+
+ var TargetPort = null;
+ var description = "The postMessage() method - Create an event that uses the MessageEvent interface, "
+ + "with the name message, which does not bubble and is not cancelable.";
+
+ var t = async_test("Test Description: " + description);
+
+ var channel = new MessageChannel();
+
+ TargetPort = channel.port2;
+ TargetPort.start();
+ TargetPort.addEventListener("message", t.step_func(TestMessageEvent), true);
+
+ channel.port1.postMessage("ping");
+
+ function TestMessageEvent(evt)
+ {
+ ExpectedResult = [true, "message", false, false];
+ ActualResult = [(evt instanceof MessageEvent), evt.type, evt.bubbles, evt.cancelable];
+
+ assert_array_equals(ActualResult, ExpectedResult);
+ t.done();
+ }
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_ports_readonly_array.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_ports_readonly_array.any.js
new file mode 100644
index 0000000000..032a54e710
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_ports_readonly_array.any.js
@@ -0,0 +1,28 @@
+// META: title=postMessage(): read-only ports array
+
+ "use strict";
+
+ var TargetPort = null;
+ var description = "The postMessage() method - Make new ports into a read only array.";
+
+ var t = async_test("Test Description: " + description);
+
+ var channel = new MessageChannel();
+
+ TargetPort = channel.port2;
+ TargetPort.start();
+ TargetPort.addEventListener("message", t.step_func(TestMessageEvent), true);
+
+ var channel2 = new MessageChannel();
+
+ channel.port1.postMessage("ports", [channel2.port1]);
+
+ function TestMessageEvent(evt)
+ {
+ var channel3 = new MessageChannel();
+ assert_throws_js(TypeError, () => {
+ evt.ports.push(channel3.port1);
+ }, "ports is a frozen object");
+ assert_equals(evt.ports.length, 1, "ports is a read only array with length == 1.");
+ t.done();
+ }
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_target_source.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_target_source.any.js
new file mode 100644
index 0000000000..6b7fc7f20d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_target_source.any.js
@@ -0,0 +1,23 @@
+// META: title=postMessage(): target port and source port
+
+ var TARGET = null;
+ var SOURCE = null;
+ var description = "The postMessage() method - Let target port be the port with which source "
+ + "port is entangled, if any.";
+
+ var t = async_test("Test Description: " + description);
+
+ var channel = new MessageChannel();
+ SOURCE = channel.port1;
+ TARGET = channel.port2;
+ TARGET.start();
+ TARGET.addEventListener("message", t.step_func(TestMessageEvent), true);
+
+ SOURCE.postMessage("ping");
+
+ function TestMessageEvent(evt)
+ {
+ assert_equals(evt.target, TARGET);
+ assert_not_equals(evt.target, SOURCE);
+ t.done();
+ }
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js
new file mode 100644
index 0000000000..23237ae155
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js
@@ -0,0 +1,32 @@
+// META: script=/common/get-host-info.sub.js
+
+async_test(function(t) {
+ var channel1 = new MessageChannel();
+ var host = get_host_info();
+ let iframe = document.createElement('iframe');
+ iframe.src = host.HTTP_NOTSAMESITE_ORIGIN + "/webmessaging/support/ChildWindowPostMessage.htm";
+ document.body.appendChild(iframe);
+ var TARGET = document.querySelector("iframe").contentWindow;
+ iframe.onload = t.step_func(function() {
+ // Enable the port.
+ channel1.port1.onmessage = t.step_func(function (evt) {
+ assert_equals(Number(evt.data), 0);
+
+ // Send a message, expecting it to be received in the iframe.
+ channel1.port2.postMessage(1)
+
+ // Transfer the port.
+ TARGET.postMessage("ports", "*", [channel1.port1]);
+ });
+
+ // Send a message, expecting it to be received here.
+ channel1.port2.postMessage(0)
+
+ channel1.port2.onmessage = t.step_func(function (evt) {
+ assert_equals(Number(evt.data), 1);
+ t.done();
+ });
+ });
+}, `Tasks enqueued on the port-message-queue of an enabled port,
+ are transferred along with the port, when the transfer happens in the same task
+ during which postMessage is called`);
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_entangled.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_entangled.any.js
new file mode 100644
index 0000000000..2226b27844
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_entangled.any.js
@@ -0,0 +1,36 @@
+async_test(function(t) {
+ var channel1 = new MessageChannel();
+ var channel2 = new MessageChannel();
+
+ // One, send a message.
+ channel1.port1.postMessage(1);
+
+ // Two, transfer both ports.
+ channel2.port1.postMessage("transfer", [channel1.port1]);
+ channel2.port1.postMessage("transfer", [channel1.port2]);
+
+ var transfer_counter = 0;
+ var sender;
+ channel2.port2.onmessage = t.step_func(function (evt) {
+ if (transfer_counter == 0) {
+ sender = evt.ports[0];
+ transfer_counter = 1;
+ } else {
+ sender.postMessage(2);
+ var counter = 0;
+ evt.ports[0].onmessage = t.step_func(function (evt) {
+ if (counter == 0) {
+ assert_equals(evt.data, 1);
+ counter = 1;
+ } else if (counter == 1) {
+ assert_equals(evt.data, 2);
+ counter = 2;
+ } else {
+ assert_equals(evt.data, 3);
+ t.done();
+ }
+ });
+ sender.postMessage(3);
+ }
+ });
+}, "An entangled port transferred to the same origin receives messages in order");
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_incoming_messages.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_incoming_messages.any.js
new file mode 100644
index 0000000000..fe2e96220d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_incoming_messages.any.js
@@ -0,0 +1,32 @@
+async_test(function(t) {
+ var channel1 = new MessageChannel();
+ var channel2 = new MessageChannel();
+ var channel3 = new MessageChannel();
+ channel2.port2.onmessage = t.step_func(function (evt) {
+ channel3.port1.onmessage = t.step_func(function (evt) {
+ var counter = 0;
+ evt.ports[0].onmessage = t.step_func(function (evt) {
+ if (counter == 0) {
+ assert_equals(evt.data, "First");
+ counter = 1;
+ } else if (counter == 1) {
+ assert_equals(evt.data, "Second");
+ counter = 2;
+ } else if (counter == 2) {
+ assert_equals(evt.data, "Third");
+ counter = 3;
+ } else if (counter == 3) {
+ assert_equals(evt.data, "Fourth");
+ t.done();
+ }
+ });
+ channel1.port2.postMessage("Fourth");
+ });
+ channel1.port2.postMessage("Second");
+ channel1.port2.postMessage("Third");
+ channel3.port2.postMessage("2", evt.ports);
+ });
+ channel1.port2.postMessage("First");
+ channel2.port1.postMessage("1", [channel1.port1]);
+}, `When transferring a non-enabled port mutiple times,
+ incoming messages sent at various transfer steps are received in order upon enablement.`);
diff --git a/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_outgoing_messages.any.js b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_outgoing_messages.any.js
new file mode 100644
index 0000000000..aa80b7589c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Channel_postMessage_with_transfer_outgoing_messages.any.js
@@ -0,0 +1,35 @@
+
+async_test(function(t) {
+ var channel1 = new MessageChannel();
+ var channel2 = new MessageChannel();
+ var channel3 = new MessageChannel();
+ channel2.port2.onmessage = t.step_func(function (evt) {
+ evt.ports[0].postMessage("Second");
+ evt.ports[0].postMessage("Third");
+ channel3.port1.onmessage = t.step_func(function (evt) {
+ evt.ports[0].postMessage("Fourth");
+ });
+ channel3.port2.postMessage("2", evt.ports);
+ });
+ channel1.port1.postMessage("First");
+ channel2.port1.postMessage("1", [channel1.port1]);
+ var counter = 0;
+ channel1.port2.onmessage = t.step_func(function (evt) {
+ if (counter == 0) {
+ assert_equals(evt.data, "First");
+ counter = 1;
+ } else if (counter == 1) {
+ assert_equals(evt.data, "Second");
+ counter = 2;
+ }
+ else if (counter == 2) {
+ assert_equals(evt.data, "Third");
+ counter = 3;
+ }
+ else if (counter == 3) {
+ assert_equals(evt.data, "Fourth");
+ t.done();
+ }
+ });
+}, `When transferring a port,
+ outgoing messages sent at each transfer step are received in order by the entangled port.`);
diff --git a/testing/web-platform/tests/webmessaging/META.yml b/testing/web-platform/tests/webmessaging/META.yml
new file mode 100644
index 0000000000..95d5071171
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/META.yml
@@ -0,0 +1,6 @@
+spec: https://html.spec.whatwg.org/multipage/web-messaging.html
+suggested_reviewers:
+ - zqzhang
+ - jdm
+ - mkruisselbrink
+ - annevk
diff --git a/testing/web-platform/tests/webmessaging/MessageEvent-trusted.any.js b/testing/web-platform/tests/webmessaging/MessageEvent-trusted.any.js
new file mode 100644
index 0000000000..84187eb571
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessageEvent-trusted.any.js
@@ -0,0 +1,32 @@
+// META: title=MessagePort message events are trusted
+
+// See also:
+// - https://github.com/whatwg/html/issues/1602
+// - https://github.com/whatwg/html/pull/1935
+
+"use strict";
+
+async_test(t => {
+ assert_true("MessageChannel" in self, "The browser must support MessageChannel");
+
+ const channel = new MessageChannel();
+
+ channel.port2.onmessage = t.step_func_done(e => {
+ assert_equals(e.isTrusted, true);
+ });
+
+ channel.port1.postMessage("ping");
+}, "With a MessageChannel and its MessagePorts");
+
+async_test(t => {
+ assert_true("BroadcastChannel" in self, "The browser must support BroadcastChannel");
+
+ const channel = new BroadcastChannel("channel name");
+
+ channel.onmessage = t.step_func_done(e => {
+ assert_equals(e.isTrusted, true);
+ });
+
+ new Worker("support/MessageEvent-trusted-worker.js");
+}, "With a BroadcastChannel");
+
diff --git a/testing/web-platform/tests/webmessaging/MessageEvent-trusted.window.js b/testing/web-platform/tests/webmessaging/MessageEvent-trusted.window.js
new file mode 100644
index 0000000000..11cf48beed
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessageEvent-trusted.window.js
@@ -0,0 +1,9 @@
+// META: title=MessagePort message events are trusted with window
+
+async_test(t => {
+ window.onmessage = t.step_func_done(e => {
+ assert_equals(e.isTrusted, true);
+ });
+
+ window.postMessage("ping", "*");
+}, "With window");
diff --git a/testing/web-platform/tests/webmessaging/MessageEvent.any.js b/testing/web-platform/tests/webmessaging/MessageEvent.any.js
new file mode 100644
index 0000000000..0fb2636911
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessageEvent.any.js
@@ -0,0 +1,22 @@
+// META: title=MessageEvent
+
+var prefixes = ['moz', 'ms', 'o', 'webkit'];
+prefixes.forEach(function(prefix) {
+ var name = prefix + "InitMessageEvent";
+
+ test(function() {
+ assert_false(name in MessageEvent.prototype);
+ }, name + " on the prototype");
+
+ test(function() {
+ var event = new MessageEvent("message");
+ assert_false(name in event);
+ }, name + " on the instance");
+});
+
+test(function() {
+ var event = new MessageEvent("message");
+ assert_throws_js(TypeError, function() {
+ event.initMessageEvent();
+ }, "Not enough arguments to initMessageEvent");
+}, "initMessageEvent with no arguments");
diff --git a/testing/web-platform/tests/webmessaging/MessageEvent_onmessage_postMessage_infinite_loop.html b/testing/web-platform/tests/webmessaging/MessageEvent_onmessage_postMessage_infinite_loop.html
new file mode 100644
index 0000000000..179bc0cc4a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessageEvent_onmessage_postMessage_infinite_loop.html
@@ -0,0 +1,31 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>MessageEvent: onmessage infinite loop</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<script>
+'use strict';
+
+// The test passes if the onmessage / postMessage loop does not prevent the
+// step_timeout task from ever being run. In particular there should be no
+// infinite loop or stack overflow.
+async_test(function(t) {
+ var channel = new MessageChannel();
+ var count = 0;
+ channel.port1.addEventListener("message", t.step_func(function() {
+ count++;
+ assert_less_than(count, 1000, "There were many message events without " +
+ "t.step_timeout ever being called.");
+ }));
+ channel.port1.addEventListener("message", t.step_func(function() {
+ channel.port2.postMessage(0);
+ }));
+ channel.port1.start();
+ channel.port2.postMessage(0);
+
+ t.step_timeout(function() { t.done(); }, 0);
+}, "onmessage calling source postMessage");
+</script>
diff --git a/testing/web-platform/tests/webmessaging/MessageEvent_properties.htm b/testing/web-platform/tests/webmessaging/MessageEvent_properties.htm
new file mode 100644
index 0000000000..389add98d1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessageEvent_properties.htm
@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> MessageEvent interface and properties </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="do_test()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+async_test(function() {
+ window.do_test = this.step_func(function() {
+ document.querySelector("iframe").contentWindow.postMessage("foo", "*");
+ })
+
+ window.addEventListener("message", this.step_func_done(function(e) {
+ e.preventDefault();
+ assert_true(e instanceof MessageEvent, "Should be MessageEvent");
+ assert_equals(e.type, "message");
+ assert_false(e.bubbles, "bubbles");
+ assert_false(e.cancelable, "cancelable");
+ assert_false(e.defaultPrevented, "defaultPrevented");
+ }), false);
+});
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/MessagePort_initial_disabled.any.js b/testing/web-platform/tests/webmessaging/MessagePort_initial_disabled.any.js
new file mode 100644
index 0000000000..b897858175
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessagePort_initial_disabled.any.js
@@ -0,0 +1,10 @@
+// META: title=MessageChannel: port message queue is initially disabled
+
+// TODO: duplicate of ./message-channels/no-start.any.js?
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port2.addEventListener("message", t.unreached_func(), true);
+ channel.port1.postMessage("ping");
+ setTimeout(t.step_func_done(), 100);
+});
diff --git a/testing/web-platform/tests/webmessaging/MessagePort_onmessage_start.any.js b/testing/web-platform/tests/webmessaging/MessagePort_onmessage_start.any.js
new file mode 100644
index 0000000000..7ba3a37210
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/MessagePort_onmessage_start.any.js
@@ -0,0 +1,10 @@
+// META: title=MessageChannel: port.onmessage enables message queue
+
+// TODO: duplicate of ./message-channels/implied-start.any.js?
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port2.onmessage = t.step_func_done();
+ channel.port1.postMessage("ping");
+ t.step_timeout(t.unreached_func(), 1000);
+});
diff --git a/testing/web-platform/tests/webmessaging/README.md b/testing/web-platform/tests/webmessaging/README.md
new file mode 100644
index 0000000000..0b81aa0658
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/README.md
@@ -0,0 +1,2 @@
+These are the cross-document messaging (`postMessage()`) tests for the
+[cross-document messaging chapter of the HTML Standard](https://html.spec.whatwg.org/multipage/comms.html#web-messaging).
diff --git a/testing/web-platform/tests/webmessaging/Transferred_objects_unusable.sub.htm b/testing/web-platform/tests/webmessaging/Transferred_objects_unusable.sub.htm
new file mode 100644
index 0000000000..55c3dbdba1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/Transferred_objects_unusable.sub.htm
@@ -0,0 +1,60 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Transferred objects are no longer usable on the sending side </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "Objects listed in transfer are transferred, not just cloned, meaning that they are " +
+ "no longer usable on the sending side.";
+
+ var t = async_test(description);
+
+ var DATA = {test: "e.ports[0].postMessage('TRANSFERRED')"};
+ var TARGET = document.querySelector("iframe");
+ var ExpectedResult = ["PING", "TRANSFERRED"];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_own_property(window, "MessageChannel", "window");
+
+ var channel = new MessageChannel();
+
+ channel.port2.onmessage = t.step_func(VerifyResult);
+
+ channel.port1.postMessage("PING");
+
+ TARGET.contentWindow.postMessage(DATA, "*", [channel.port1]);
+
+ channel.port1.postMessage("PONG");
+
+ }, "MessageChannel is supported.");
+ }
+
+ function VerifyResult(e)
+ {
+ ActualResult.push(e.data)
+
+ if (ActualResult.length >= ExpectedResult.length)
+ {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/basics.any.js b/testing/web-platform/tests/webmessaging/broadcastchannel/basics.any.js
new file mode 100644
index 0000000000..eec09d65a3
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/basics.any.js
@@ -0,0 +1,128 @@
+test(function() {
+ assert_throws_js(
+ TypeError,
+ () => BroadcastChannel(""),
+ "Calling BroadcastChannel constructor without 'new' must throw"
+ );
+}, "BroadcastChannel constructor called as normal function");
+
+async_test(t => {
+ let c1 = new BroadcastChannel('eventType');
+ let c2 = new BroadcastChannel('eventType');
+
+ c2.onmessage = t.step_func(e => {
+ assert_true(e instanceof MessageEvent);
+ assert_equals(e.target, c2);
+ assert_equals(e.type, 'message');
+ assert_equals(e.origin, location.origin, 'origin');
+ assert_equals(e.data, 'hello world');
+ assert_equals(e.source, null, 'source');
+ t.done();
+ });
+ c1.postMessage('hello world');
+ }, 'postMessage results in correct event');
+
+async_test(t => {
+ let c1 = new BroadcastChannel('order');
+ let c2 = new BroadcastChannel('order');
+ let c3 = new BroadcastChannel('order');
+
+ let events = [];
+ let doneCount = 0;
+ let handler = t.step_func(e => {
+ events.push(e);
+ if (e.data == 'done') {
+ doneCount++;
+ if (doneCount == 2) {
+ assert_equals(events.length, 6);
+ assert_equals(events[0].target, c2, 'target for event 0');
+ assert_equals(events[0].data, 'from c1');
+ assert_equals(events[1].target, c3, 'target for event 1');
+ assert_equals(events[1].data, 'from c1');
+ assert_equals(events[2].target, c1, 'target for event 2');
+ assert_equals(events[2].data, 'from c3');
+ assert_equals(events[3].target, c2, 'target for event 3');
+ assert_equals(events[3].data, 'from c3');
+ assert_equals(events[4].target, c1, 'target for event 4');
+ assert_equals(events[4].data, 'done');
+ assert_equals(events[5].target, c3, 'target for event 5');
+ assert_equals(events[5].data, 'done');
+ t.done();
+ }
+ }
+ });
+ c1.onmessage = handler;
+ c2.onmessage = handler;
+ c3.onmessage = handler;
+
+ c1.postMessage('from c1');
+ c3.postMessage('from c3');
+ c2.postMessage('done');
+ }, 'messages are delivered in port creation order');
+
+async_test(t => {
+ let c1 = new BroadcastChannel('closed');
+ let c2 = new BroadcastChannel('closed');
+ let c3 = new BroadcastChannel('closed');
+
+ c2.onmessage = t.unreached_func();
+ c2.close();
+ c3.onmessage = t.step_func(() => t.done());
+ c1.postMessage('test');
+ }, 'messages aren\'t delivered to a closed port');
+
+ async_test(t => {
+ let c1 = new BroadcastChannel('closed');
+ let c2 = new BroadcastChannel('closed');
+ let c3 = new BroadcastChannel('closed');
+
+ c2.onmessage = t.unreached_func();
+ c3.onmessage = t.step_func(() => t.done());
+ c1.postMessage('test');
+ c2.close();
+}, 'messages aren\'t delivered to a port closed after calling postMessage.');
+
+async_test(t => {
+ let c1 = new BroadcastChannel('create-in-onmessage');
+ let c2 = new BroadcastChannel('create-in-onmessage');
+
+ c2.onmessage = t.step_func(e => {
+ assert_equals(e.data, 'first');
+ c2.close();
+ let c3 = new BroadcastChannel('create-in-onmessage');
+ c3.onmessage = t.step_func(event => {
+ assert_equals(event.data, 'done');
+ t.done();
+ });
+ c1.postMessage('done');
+ });
+ c1.postMessage('first');
+ c2.postMessage('second');
+ }, 'closing and creating channels during message delivery works correctly');
+
+async_test(t => {
+ let c1 = new BroadcastChannel('close-in-onmessage');
+ let c2 = new BroadcastChannel('close-in-onmessage');
+ let c3 = new BroadcastChannel('close-in-onmessage');
+ let events = [];
+ c1.onmessage = e => events.push('c1: ' + e.data);
+ c2.onmessage = e => events.push('c2: ' + e.data);
+ c3.onmessage = e => events.push('c3: ' + e.data);
+
+ // c2 closes itself when it receives the first message
+ c2.addEventListener('message', e => {
+ c2.close();
+ });
+
+ c3.addEventListener('message', t.step_func(e => {
+ if (e.data == 'done') {
+ assert_array_equals(events, [
+ 'c2: first',
+ 'c3: first',
+ 'c3: done']);
+ t.done();
+ }
+ }));
+ c1.postMessage('first');
+ c1.postMessage('done');
+ }, 'Closing a channel in onmessage prevents already queued tasks from firing onmessage events');
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/blobs.html b/testing/web-platform/tests/webmessaging/broadcastchannel/blobs.html
new file mode 100644
index 0000000000..ab5096b63c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/blobs.html
@@ -0,0 +1,82 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/gc.js"></script>
+<script>
+async_test(t => {
+ const c1 = new BroadcastChannel('blob');
+ const c2 = new BroadcastChannel('blob');
+ const c3 = new BroadcastChannel('blob');
+
+ let readCount = 0;
+ c2.onmessage = t.step_func(e => {
+ // check blob
+ assert_true('blob' in e.data);
+ assert_true(e.data.blob instanceof Blob);
+ assert_equals(e.data.blob.size, 6);
+ const reader = new FileReader();
+ reader.onerror = t.unreached_func();
+ reader.onload = t.step_func(() => {
+ assert_equals(reader.result, 'foobar');
+ if (++readCount == 2)
+ t.done();
+ });
+ reader.readAsText(e.data.blob);
+ });
+ c3.onmessage = c2.onmessage;
+ (() => {
+ c1.postMessage({blob: new Blob(['foo', 'bar'])});
+ })();
+ garbageCollect();
+ }, 'Blobs work on BroadcastChannel');
+
+async_test(t => {
+ const c1 = new BroadcastChannel('blobworker');
+ const c2 = new BroadcastChannel('blobworker');
+ const events = [];
+
+ const verifyEvents = function() {
+ assert_equals(events.length, 5);
+ assert_equals(events[0], 'from worker');
+ assert_equals(events[1], 'from worker');
+ assert_true(events[2].blob instanceof Blob);
+ assert_equals(events[2].blob.size, 11);
+ assert_true(events[3].blob instanceof Blob);
+ assert_equals(events[3].blob.size, 11);
+ assert_equals(events[4], 'done');
+ const reader = new FileReader();
+ reader.onerror = t.unreached_func();
+ reader.onload = t.step_func(() => {
+ assert_equals(reader.result, 'hello-world');
+ t.done();
+ });
+ reader.readAsText(events[3].blob);
+ };
+
+ let receivedDone = false;
+ let receivedWorkerDone = false;
+
+ c1.onmessage = e => events.push(e.data);
+ c2.onmessage = e => events.push(e.data);
+ c2.addEventListener('message', t.step_func(e => {
+ if (e.data.blob)
+ c1.postMessage('done');
+ if (e.data === 'done')
+ receivedDone = true;
+ if (receivedDone && receivedWorkerDone)
+ verifyEvents();
+ }));
+
+ const worker = new Worker('resources/worker.js');
+ worker.onmessage = t.step_func(e => {
+ receivedWorkerDone = true;
+ if (receivedDone && receivedWorkerDone)
+ verifyEvents();
+ });
+ worker.postMessage({channel: 'blobworker'});
+ worker.postMessage({blob: ['hello-world']});
+
+ }, 'Blobs work with workers on BroadcastChannel');
+
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/cross-origin.html b/testing/web-platform/tests/webmessaging/broadcastchannel/cross-origin.html
new file mode 100644
index 0000000000..ee4b2f21c8
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/cross-origin.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+const events = [];
+
+function testCompletion(t) {
+ return new Promise((resolve) => {
+ window.addEventListener("message", t.step_func(e => {
+ if (e.data == 'done') {
+ assert_equals(events.length, 0);
+ resolve();
+ }
+ }));
+ });
+}
+
+promise_test(async t => {
+
+ const bc0 = new BroadcastChannel('no-cross-origin-messages');
+ bc0.onmessage = e => {window.events.push(e);};
+
+ const testResults = testCompletion(t);
+ const url = get_host_info().HTTPS_NOTSAMESITE_ORIGIN +
+ '/webmessaging/broadcastchannel/resources/cross-origin.html';
+ await with_iframe(url);
+
+ return testResults;
+}, "Messages aren't delivered across origins");
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/cross-partition.https.tentative.html b/testing/web-platform/tests/webmessaging/broadcastchannel/cross-partition.https.tentative.html
new file mode 100644
index 0000000000..4e91da5546
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/cross-partition.https.tentative.html
@@ -0,0 +1,356 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<script src="/common/utils.js"></script>
+<script src="/common/dispatcher/dispatcher.js"></script>
+<!-- Pull in executor_path needed by newPopup / newIframe -->
+<script src="/html/cross-origin-embedder-policy/credentialless/resources/common.js"></script>
+<!-- Pull in importScript / newPopup / newIframe -->
+<script src="/html/anonymous-iframe/resources/common.js"></script>
+<body>
+<script>
+
+const bc_postmessage_js = (channel_name, message, done_queue_name) => `
+ const bc = new BroadcastChannel("${channel_name}");
+ bc.postMessage("${message}");
+ send("${done_queue_name}", "done");
+`;
+
+const add_iframe_js = (iframe_origin, response_queue_uuid) => `
+ const importScript = ${importScript};
+ await importScript("/html/cross-origin-embedder-policy/credentialless" +
+ "/resources/common.js");
+ await importScript("/html/anonymous-iframe/resources/common.js");
+ await importScript("/common/utils.js");
+ send("${response_queue_uuid}", newIframe("${iframe_origin}"));
+`;
+
+const same_site_origin = get_host_info().HTTPS_ORIGIN;
+const cross_site_origin = get_host_info().HTTPS_NOTSAMESITE_ORIGIN;
+
+async function create_test_iframes(t, response_queue_uuid) {
+
+ // Create a same-origin iframe in a cross-site popup.
+ const not_same_site_popup_uuid = newPopup(t, cross_site_origin);
+ send(not_same_site_popup_uuid,
+ add_iframe_js(same_site_origin, response_queue_uuid));
+ const iframe_1_uuid = await receive(response_queue_uuid);
+
+ // Create a same-origin iframe in a same-site popup.
+ const same_origin_popup_uuid = newPopup(t, same_site_origin);
+ send(same_origin_popup_uuid,
+ add_iframe_js(same_site_origin, response_queue_uuid));
+ const iframe_2_uuid = await receive(response_queue_uuid);
+
+ return [iframe_1_uuid, iframe_2_uuid];
+}
+
+promise_test(t => {
+ return new Promise(async (resolve, reject) => {
+ const response_queue_uuid = token();
+
+ const [iframe_1_uuid, iframe_2_uuid] =
+ await create_test_iframes(t, response_queue_uuid);
+
+ const channel_name = token();
+ const bc = new BroadcastChannel(channel_name);
+ bc.onmessage = resolve;
+
+ // Instruct the not-same-top-level-site iframe to send a message on the BC
+ // channel we are listening on. This message should not be received since
+ // the iframe should be in a different partition.
+ send(iframe_1_uuid,
+ bc_postmessage_js(channel_name, "iframe1 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger iframe1 BroadcastChannel message creation");
+ }
+
+ // Now instruct the same-top-level-site iframe to send a BC message. By
+ // the time we send the script to execute, have it send the BC message,
+ // and then receive the BC message in our BC instance, it should be
+ // reasonable to assume that the message from the first iframe would have
+ // been delivered if it was going to be.
+ send(iframe_2_uuid,
+ bc_postmessage_js(channel_name, "iframe2 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger iframe2 BroadcastChannel message creation");
+ }
+
+ }).then(event => {
+ assert_equals(event.data, "iframe2 msg");
+ });
+
+}, "BroadcastChannel messages aren't received from a cross-partition iframe");
+
+// Optional Test: Checking for partitioned BroadcastChannels in an A->B->A
+// (nested-iframe with cross-site ancestor chain) scenario.
+promise_test(t => {
+ return new Promise(async (resolve, reject) => {
+ const response_queue_uuid = token();
+
+ const [cross_site_iframe_uuid, all_same_parent_iframe_uuid] =
+ await create_test_iframes(t, response_queue_uuid);
+
+ // Create a same-origin iframe in a cross-site iframe in a same-site popup.
+ // Create the same-site child iframe of the cross-site iframe (A->B->A).
+ send(cross_site_iframe_uuid,
+ add_iframe_js(same_site_origin, response_queue_uuid));
+ const same_site_iframe_uuid = await receive(response_queue_uuid);
+
+ // Create a same-origin iframe in a same-site iframe in a same-site popup.
+ // Create the same-site child iframe of the same-site parent iframe (A->A->A).
+ send(all_same_parent_iframe_uuid,
+ add_iframe_js(same_site_origin, response_queue_uuid));
+ const all_same_child_iframe_uuid = await receive(response_queue_uuid);
+
+ const channel_name = token();
+ const bc = new BroadcastChannel(channel_name);
+ bc.onmessage = resolve;
+
+ // Instruct the A->B->A child iframe to send a message on the BC
+ // channel we are listening on. This message should not be received since
+ // the iframe should be in a different partition.
+ send(same_site_iframe_uuid,
+ bc_postmessage_js(channel_name, "iframe1 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger A->B->A BroadcastChannel message creation");
+ }
+
+ // Now instruct the A->A->A child iframe to send a BC message. By
+ // the time we send the script to execute, send the BC message,
+ // and receive the BC message in our BC instance, it should be
+ // reasonable to assume that the message from the first iframe would have
+ // been delivered if it was going to be.
+ send(all_same_child_iframe_uuid,
+ bc_postmessage_js(channel_name, "iframe2 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger A->A->A BroadcastChannel message creation");
+ }
+
+ }).then(event => {
+ assert_equals(event.data, "iframe2 msg");
+ });
+
+}, "BroadcastChannel messages aren't received from a nested iframe with a cross-site ancestor");
+
+const newWorker = (origin) => {
+ const worker_token = token();
+ const worker_url = origin + executor_worker_path + `&uuid=${worker_token}`;
+ const worker = new Worker(worker_url);
+ return worker_token;
+}
+
+promise_test(t => {
+ return new Promise(async (resolve, reject) => {
+ const response_queue_uuid = token();
+
+ const create_worker_js = (origin) => `
+ const importScript = ${importScript};
+ await importScript("/html/cross-origin-embedder-policy/credentialless" +
+ "/resources/common.js");
+ await importScript("/html/anonymous-iframe/resources/common.js");
+ await importScript("/common/utils.js");
+ const newWorker = ${newWorker};
+ send("${response_queue_uuid}", newWorker("${origin}"));
+ `;
+
+ const [iframe_1_uuid, iframe_2_uuid] =
+ await create_test_iframes(t, response_queue_uuid);
+
+ // Create a dedicated worker in the cross-top-level-site iframe.
+ send(iframe_1_uuid, create_worker_js(same_site_origin));
+ const worker_1_uuid = await receive(response_queue_uuid);
+
+ // Create a dedicated worker in the same-top-level-site iframe.
+ send(iframe_2_uuid, create_worker_js(same_site_origin));
+ const worker_2_uuid = await receive(response_queue_uuid);
+
+ const channel_name = token();
+ const bc = new BroadcastChannel(channel_name);
+ bc.onmessage = async (e) => {
+ await send(worker_1_uuid, "self.close();");
+ await send(worker_2_uuid, "self.close();");
+ resolve(e);
+ };
+
+ // Instruct the not-same-top-level-site worker to send a message on the BC
+ // channel we are listening on. This message should not be received since
+ // the worker should be in a different partition.
+ send(worker_1_uuid,
+ bc_postmessage_js(channel_name, "worker1 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker1 BroadcastChannel message creation");
+ }
+
+ // Now instruct the same-top-level-site worker to send a BC message. By
+ // the time we send the script to execute, have it send the BC message,
+ // and then receive the BC message in our BC instance, it should be
+ // reasonable to assume that the message from the first worker would have
+ // been delivered if it was going to be.
+ send(worker_2_uuid,
+ bc_postmessage_js(channel_name, "worker2 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker2 BroadcastChannel message creation");
+ }
+
+ }).then(event => {
+ assert_equals(event.data, "worker2 msg");
+ });
+
+}, "BroadcastChannel messages aren't received from a cross-partition dedicated worker");
+
+const newSharedWorker = (origin) => {
+ const worker_token = token();
+ const worker_url = origin + executor_worker_path + `&uuid=${worker_token}`;
+ const worker = new SharedWorker(worker_url, worker_token);
+ return worker_token;
+}
+
+promise_test(t => {
+ return new Promise(async (resolve, reject) => {
+ const response_queue_uuid = token();
+
+ const create_worker_js = (origin) => `
+ const importScript = ${importScript};
+ await importScript("/html/cross-origin-embedder-policy/credentialless" +
+ "/resources/common.js");
+ await importScript("/html/anonymous-iframe/resources/common.js");
+ await importScript("/common/utils.js");
+ const newSharedWorker = ${newSharedWorker};
+ send("${response_queue_uuid}", newSharedWorker("${origin}"));
+ `;
+
+ const [iframe_1_uuid, iframe_2_uuid] =
+ await create_test_iframes(t, response_queue_uuid);
+
+ // Create a shared worker in the cross-top-level-site iframe.
+ send(iframe_1_uuid, create_worker_js(same_site_origin));
+ const worker_1_uuid = await receive(response_queue_uuid);
+
+ // Create a shared worker in the same-top-level-site iframe.
+ send(iframe_2_uuid, create_worker_js(same_site_origin));
+ const worker_2_uuid = await receive(response_queue_uuid);
+
+ const channel_name = token();
+ const bc = new BroadcastChannel(channel_name);
+ bc.onmessage = async (e) => {
+ await send(worker_1_uuid, "self.close();");
+ await send(worker_2_uuid, "self.close();");
+ resolve(e);
+ };
+
+ // Instruct the not-same-top-level-site worker to send a message on the BC
+ // channel we are listening on. This message should not be received since
+ // the worker should be in a different partition.
+ send(worker_1_uuid,
+ bc_postmessage_js(channel_name, "worker1 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker1 BroadcastChannel message creation");
+ }
+
+ // Now instruct the same-top-level-site worker to send a BC message. By
+ // the time we send the script to execute, have it send the BC message,
+ // and then receive the BC message in our BC instance, it should be
+ // reasonable to assume that the message from the first worker would have
+ // been delivered if it was going to be.
+ send(worker_2_uuid,
+ bc_postmessage_js(channel_name, "worker2 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker2 BroadcastChannel message creation");
+ }
+
+ }).then(event => {
+ assert_equals(event.data, "worker2 msg");
+ });
+
+}, "BroadcastChannel messages aren't received from a cross-partition shared worker");
+
+const newServiceWorker = async (origin) => {
+ const worker_token = token();
+ const worker_url = origin + executor_service_worker_path +
+ `&uuid=${worker_token}`;
+ const worker_url_path = executor_service_worker_path.substring(0,
+ executor_service_worker_path.lastIndexOf('/'));
+ const scope = worker_url_path + "/not-used/";
+ const reg = await navigator.serviceWorker.register(worker_url,
+ {'scope': scope});
+ return worker_token;
+}
+
+promise_test(t => {
+ return new Promise(async (resolve, reject) => {
+ const response_queue_uuid = token();
+
+ const create_worker_js = (origin) => `
+ const importScript = ${importScript};
+ await importScript("/html/cross-origin-embedder-policy/credentialless" +
+ "/resources/common.js");
+ await importScript("/html/anonymous-iframe/resources/common.js");
+ await importScript("/common/utils.js");
+ const newServiceWorker = ${newServiceWorker};
+ send("${response_queue_uuid}", await newServiceWorker("${origin}"));
+ `;
+
+ const [iframe_1_uuid, iframe_2_uuid] =
+ await create_test_iframes(t, response_queue_uuid);
+
+ // Create a service worker in the cross-top-level-site iframe.
+ send(iframe_1_uuid, create_worker_js(same_site_origin));
+ var worker_1_uuid = await receive(response_queue_uuid);
+
+ const channel_name = token();
+ const bc = new BroadcastChannel(channel_name);
+ bc.onmessage = async (e) => {
+ if (worker_1_uuid) {
+ await send(worker_1_uuid, "self.registration.unregister();");
+ }
+ if (worker_2_uuid) {
+ await send(worker_2_uuid, "self.registration.unregister();");
+ }
+ resolve(e);
+ };
+
+ // Instruct the not-same-top-level-site worker to send a message on the BC
+ // channel we are listening on. This message should not be received since
+ // the worker should be in a different partition.
+ send(worker_1_uuid,
+ bc_postmessage_js(channel_name, "worker1 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker1 BroadcastChannel message creation");
+ }
+
+ await send(worker_1_uuid, "await self.registration.unregister();");
+ worker_1_uuid = undefined;
+
+ // Create a service worker in the same-top-level-site iframe. Note that
+ // if service workers are unpartitioned then this new service worker would
+ // replace the one created above. This is why we wait to create the second
+ // service worker until after we are done with the first one.
+ send(iframe_2_uuid, create_worker_js(same_site_origin));
+ var worker_2_uuid = await receive(response_queue_uuid);
+
+ // Now instruct the same-top-level-site worker to send a BC message. By
+ // the time we send the script to execute, have it send the BC message,
+ // and then receive the BC message in our BC instance, it should be
+ // reasonable to assume that the message from the first worker would have
+ // been delivered if it was going to be.
+ send(worker_2_uuid,
+ bc_postmessage_js(channel_name, "worker2 msg", response_queue_uuid));
+ if (await receive(response_queue_uuid) != "done") {
+ reject("Unable to trigger worker2 BroadcastChannel message creation");
+ }
+
+ await send(worker_2_uuid, "await self.registration.unregister();");
+ worker_2_uuid = undefined;
+
+ }).then(event => {
+ assert_equals(event.data, "worker2 msg");
+ });
+
+}, "BroadcastChannel messages aren't received from a cross-partition service worker");
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/detached-iframe.html b/testing/web-platform/tests/webmessaging/broadcastchannel/detached-iframe.html
new file mode 100644
index 0000000000..b9b06c3a46
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/detached-iframe.html
@@ -0,0 +1,174 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<body>
+<script>
+const TEST_IFRAME_CLASS_NAME = 'test-iframe';
+const events = [];
+var bc1;
+const DONE_MSG = 'done';
+
+function DetachedIframeTestCheckForOneMessage(t) {
+ return new Promise((resolve) => {
+ bc1.onmessage = t.step_func(e => {
+ events.push(e);
+ if (e.data == DONE_MSG) {
+ assert_equals(events.length, 1);
+ resolve();
+ }
+ });
+ });
+}
+
+const IframeAction = {
+ REMOVE_BEFORE_CREATION: 'remove-before-creation',
+ REMOVE_AFTER_CREATION: 'remove-after-creation',
+};
+
+async function doMessageSentTest(t, channelName, action) {
+ await with_iframe('about:blank');
+ const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+ const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+ if (action === IframeAction.REMOVE_BEFORE_CREATION) {
+ iframe.remove();
+ }
+
+ events.length = 0;
+
+ bc1 = new BroadcastChannel(channelName);
+ const bc2 = new BroadcastChannel(channelName);
+ const iframe_bc = new iframe_BroadcastChannel(channelName);
+
+ if (action === IframeAction.REMOVE_AFTER_CREATION) {
+ iframe.remove();
+ }
+
+ const testResultsPromise = DetachedIframeTestCheckForOneMessage(t);
+
+ iframe_bc.postMessage('test');
+ bc2.postMessage(DONE_MSG);
+
+ bc2.close();
+ iframe_bc.close();
+ t.add_cleanup(() => bc1.close());
+
+ return testResultsPromise;
+}
+
+promise_test(async t => {
+ return doMessageSentTest(
+ t, 'postMessage-from-detached-iframe-pre',
+ IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created before detaching)');
+
+promise_test(async t => {
+ return doMessageSentTest(
+ t, 'postMessage-from-detached-iframe-post',
+ IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created after detaching)');
+
+
+async function doMessageReceivedTest(t, channelName, action) {
+ await with_iframe('about:blank');
+ const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+ const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+ if (action === IframeAction.REMOVE_BEFORE_CREATION) {
+ iframe.remove();
+ }
+
+ events.length = 0;
+
+ // `iframe_bc` must be created first so that it receives messages before
+ // `bc1`. That way we can tell whether `iframe_bc` received a message by
+ // inspecting `events` in the `bc1` message handler.
+ const iframe_bc = new iframe_BroadcastChannel(channelName);
+ iframe_bc.onmessage = e => {
+ events.push(e)
+ };
+ bc1 = new BroadcastChannel(channelName);
+ const bc2 = new BroadcastChannel(channelName);
+
+ if (action === IframeAction.REMOVE_AFTER_CREATION) {
+ iframe.remove();
+ }
+
+ const testResultsPromise = DetachedIframeTestCheckForOneMessage(t);
+ bc2.postMessage(DONE_MSG);
+
+ bc2.close();
+ iframe_bc.close();
+ t.add_cleanup(() => bc1.close());
+}
+
+promise_test(async t => {
+ return doMessageReceivedTest(
+ t, 'postMessage-to-detached-iframe-pre',
+ IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created before detaching)');
+
+promise_test(async t => {
+ return doMessageReceivedTest(
+ t, 'postMessage-to-detached-iframe-post',
+ IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created after detaching)');
+
+
+async function doMessageSendReceiveTest(t, channelName, action) {
+ await with_iframe('about:blank');
+ const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0];
+ const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel;
+
+ if (action === IframeAction.REMOVE_BEFORE_CREATION) {
+ iframe.remove();
+ }
+
+ const iframe_bc1 = new iframe_BroadcastChannel(channelName);
+ const iframe_bc2 = new iframe_BroadcastChannel(channelName);
+ iframe_bc1.onmessage = t.unreached_func(
+ 'Detached iframe BroadcastChannel instance received message unexpectedly');
+
+ if (action === IframeAction.REMOVE_AFTER_CREATION) {
+ iframe.remove();
+ }
+
+ iframe_bc2.postMessage(DONE_MSG);
+
+ iframe_bc2.close();
+ t.add_cleanup(() => iframe_bc1.close());
+
+ // To avoid calling t.step_timeout here, instead just create two new
+ // BroadcastChannel instances and complete the test when a message is passed
+ // between them. Per the spec, all "BroadcastChannel objects whose relevant
+ // agents are the same" must have messages delivered to them in creation
+ // order, so if we get this message then it's safe to assume the earlier
+ // message would have been delivered if it was going to be.
+ const bc1 = new BroadcastChannel(channelName);
+ const bc2 = new BroadcastChannel(channelName);
+ return new Promise((resolve) => {
+ bc1.onmessage = t.step_func(e => {
+ resolve();
+ });
+ bc2.postMessage(DONE_MSG);
+ });
+}
+
+promise_test(async t => {
+ return doMessageSendReceiveTest(
+ t, 'postMessage-within-detached-iframe-pre',
+ IframeAction.REMOVE_AFTER_CREATION);
+}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created before detaching)');
+
+promise_test(async t => {
+ return doMessageSendReceiveTest(
+ t, 'postMessage-within-detached-iframe-post',
+ IframeAction.REMOVE_BEFORE_CREATION);
+}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created after detaching)');
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/interface.any.js b/testing/web-platform/tests/webmessaging/broadcastchannel/interface.any.js
new file mode 100644
index 0000000000..35e09d34b4
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/interface.any.js
@@ -0,0 +1,65 @@
+test(() => assert_throws_js(TypeError, () => new BroadcastChannel()),
+ 'Should throw if no name is provided');
+
+test(() => {
+ let c = new BroadcastChannel(null);
+ assert_equals(c.name, 'null');
+ }, 'Null name should not throw');
+
+test(() => {
+ let c = new BroadcastChannel(undefined);
+ assert_equals(c.name, 'undefined');
+ }, 'Undefined name should not throw');
+
+test(() => {
+ let c = new BroadcastChannel('fooBar');
+ assert_equals(c.name, 'fooBar');
+ }, 'Non-empty name should not throw');
+
+test(() => {
+ let c = new BroadcastChannel(123);
+ assert_equals(c.name, '123');
+ }, 'Non-string name should not throw');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ assert_throws_js(TypeError, () => c.postMessage());
+ }, 'postMessage without parameters should throw');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ c.postMessage(null);
+ }, 'postMessage with null should not throw');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ c.close();
+ }, 'close should not throw');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ c.close();
+ c.close();
+ }, 'close should not throw when called multiple times');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ c.close();
+ assert_throws_dom('InvalidStateError', () => c.postMessage(''));
+ }, 'postMessage after close should throw');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ assert_not_equals(c.onmessage, undefined);
+ }, 'BroadcastChannel should have an onmessage event');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ assert_throws_dom('DataCloneError', () => c.postMessage(Symbol()));
+ }, 'postMessage should throw with uncloneable data');
+
+test(() => {
+ let c = new BroadcastChannel('');
+ c.close();
+ assert_throws_dom('InvalidStateError', () => c.postMessage(Symbol()));
+ }, 'postMessage should throw InvalidStateError after close, even with uncloneable data');
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/opaque-origin.html b/testing/web-platform/tests/webmessaging/broadcastchannel/opaque-origin.html
new file mode 100644
index 0000000000..e09d935244
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/opaque-origin.html
@@ -0,0 +1,193 @@
+<!doctype html>
+<html>
+<head>
+<meta charset=utf-8>
+<meta name="timeout" content="long">
+<title></title>
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+</head>
+<body>
+<script>
+<!--
+promise_test(t => {
+ return new Promise((resolve) => {
+ let ifr = document.createElement("iframe");
+ ifr.src =
+ "data:text/html,<script> let bc = new BroadcastChannel(\"test\");" +
+ "bc.onmessage = (e) => {" +
+ " if (e.data == \"ping\") bc.postMessage('pong');"+
+ " else parent.postMessage({workerMessageOrigin: e.data, messageOrigin: e.origin}, \"*\"); };" +
+ "new Worker(URL.createObjectURL(new Blob([\"" +
+ "let bc2 = new BroadcastChannel('test'); bc2.postMessage('ping'); " +
+ "bc2.onmessage = e => bc2.postMessage(e.origin);" +
+ "\"], {type: 'text/javascript'}))); </script>";
+ window.addEventListener("message", t.step_func(e => {
+ assert_equals(e.data.workerMessageOrigin, "null");
+ assert_equals(e.data.messageOrigin, "null");
+ resolve();
+ }), {once: true});
+ t.add_cleanup(() => { document.body.removeChild(ifr) });
+ document.body.appendChild(ifr);
+ });
+}, "Opaque origin should be serialized to \"null\"");
+
+
+const iframe_src = (channel_name, iframe_name) => `data:text/html,<script>
+let bc2 = new BroadcastChannel("${channel_name}");
+bc2.onmessage = (e) => {
+ if (e.data == "from-${iframe_name}") {
+ parent.postMessage("${iframe_name}-done", "*");
+ } else {
+ parent.postMessage("fail", "*");
+ }
+};
+let bc3 = new BroadcastChannel("${channel_name}");
+bc3.postMessage("from-${iframe_name}");
+</script>`;
+
+promise_test(t => {
+ return new Promise((resolve, reject) => {
+ const channel_name = "opaque-origin-test-2";
+ const bc1 = new BroadcastChannel(channel_name);
+ bc1.onmessage = t.unreached_func("Received message from an opaque origin");
+
+ // We'll create an iframe and have it send a BroadcastChannel message
+ // between two instances. Once the message is received, it will postMessage
+ // back and we'll repeat this with another iframe. If the first
+ // BroadcastChannel message is received by `bc1`, or if the second
+ // BroadcastChannel message is received by `bc1` or `bc2` in the first
+ // iframe, then the test should fail.
+
+ window.addEventListener("message", e => {
+ if(e.data == "iframe1-done") {
+ let iframe2 = document.createElement("iframe");
+ iframe2.src = iframe_src(channel_name, "iframe2");
+ t.add_cleanup(() => { document.body.removeChild(iframe2) });
+ document.body.appendChild(iframe2);
+ } else if(e.data == "iframe2-done") {
+ resolve();
+ } else if(e.data == "fail") {
+ reject("One opaque origin received a message from the other");
+ } else {
+ reject("An unexpected error occurred");
+ }
+ });
+
+ let iframe1 = document.createElement("iframe");
+ iframe1.src = iframe_src(channel_name, "iframe1");
+ t.add_cleanup(() => { document.body.removeChild(iframe1) });
+ document.body.appendChild(iframe1);
+ });
+}, "BroadcastChannel messages from opaque origins should be self-contained");
+
+const data_url_worker_src = (channel_name, worker_name) => {
+ const source = `
+const handler = (reply) => {
+ let bc2 = new BroadcastChannel("${channel_name}");
+ bc2.onmessage = (e) => {
+ if (e.data == "from-${worker_name}") {
+ reply("${worker_name}-done");
+ } else {
+ reply("fail");
+ }
+ };
+ let bc3 = new BroadcastChannel("${channel_name}");
+ bc3.postMessage("from-${worker_name}");
+};
+// For dedicated workers:
+self.addEventListener("message", () => handler(self.postMessage));
+// For shared workers:
+self.addEventListener("connect", (e) => {
+ var port = e.ports[0];
+ port.onmessage = () => handler(msg => port.postMessage(msg));
+ port.start();
+
+});
+`;
+ return "data:,".concat(encodeURIComponent(source));
+}
+
+promise_test(t => {
+ return new Promise((resolve, reject) => {
+ const channel_name = "opaque-origin-test-3";
+ const bc1 = new BroadcastChannel(channel_name);
+ bc1.onmessage = e => { reject("Received message from an opaque origin"); };
+
+ // Same as the previous test but with data URL dedicated workers (which
+ // should have opaque origins per the HTML spec).
+ const worker_name_prefix = "data-url-dedicated-worker";
+ const worker_1_name = `${worker_name_prefix}-1`;
+ const worker_2_name = `${worker_name_prefix}-2`;
+
+ const handler = e => {
+ if(e.data == `${worker_1_name}-done`) {
+ const worker2 = new Worker(data_url_worker_src(channel_name, worker_2_name));
+ t.add_cleanup(() => worker2.terminate());
+ worker2.addEventListener("message", handler);
+ worker2.postMessage("go!");
+ } else if(e.data == `${worker_2_name}-done`) {
+ resolve();
+ } else if(e.data == "fail") {
+ reject("One opaque origin received a message from the other");
+ } else {
+ reject("An unexpected error occurred");
+ }
+ };
+
+ let worker1 = new Worker(data_url_worker_src(channel_name, worker_1_name));
+ t.add_cleanup(() => worker1.terminate());
+ worker1.addEventListener("message", handler);
+ worker1.postMessage("go!");
+ });
+}, "BroadcastChannel messages from data URL dedicated workers should be self-contained");
+
+promise_test(() => {
+ return new Promise((resolve, reject) => {
+ const channel_name = "opaque-origin-test-4";
+ const bc1 = new BroadcastChannel(channel_name);
+
+ // Same as the previous test but with data URL shared workers (which
+ // should have opaque origins per the HTML spec).
+ const worker_name_prefix = "data-url-shared-worker";
+ const worker_1_name = `${worker_name_prefix}-1`;
+ const worker_2_name = `${worker_name_prefix}-2`;
+
+ const handler = e => {
+ if (e.data == `${worker_1_name}-done`) {
+ const worker_script = data_url_worker_src(channel_name, worker_2_name);
+ const worker2 = new SharedWorker(worker_script, worker_2_name);
+ worker2.port.addEventListener("message", handler);
+ worker2.port.start();
+ worker2.port.postMessage("go!");
+ } else if(e.data == `${worker_2_name}-done`) {
+ resolve();
+ } else if(e.data == "fail") {
+ reject("One opaque origin received a message from the other");
+ } else {
+ reject("An unexpected error occurred");
+ }
+ };
+
+ bc1.onmessage = e => {
+ if (e.data == "go!") {
+ const worker_script = data_url_worker_src(channel_name, worker_1_name);
+ const worker1 = new SharedWorker(worker_script, worker_1_name);
+ worker1.port.addEventListener("message", handler);
+ worker1.port.start();
+ worker1.port.postMessage("go!");
+ } else {
+ reject("Received message from an opaque origin");
+ }
+ };
+
+ // Ensure that the BroadcastChannel instance above can receive messages
+ // before we create the first shared worker.
+ const bc2 = new BroadcastChannel(channel_name);
+ bc2.postMessage("go!");
+ });
+}, "BroadcastChannel messages from data URL shared workers should be self-contained");
+//-->
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/ordering.html b/testing/web-platform/tests/webmessaging/broadcastchannel/ordering.html
new file mode 100644
index 0000000000..2d521b9e0c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/ordering.html
@@ -0,0 +1,116 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<!-- Pull in the with_iframe helper function from the service worker tests -->
+<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script>
+<body>
+<script>
+
+const BC0_FIRST_MSG = 'from BC0 - first';
+const BC1_FIRST_MSG = 'from BC1 - first';
+const BC2_FIRST_MSG = 'from BC2 - first';
+const BC3_FIRST_MSG = 'from BC3 - first';
+const BC0_SECOND_MSG = 'from BC0 - second';
+const BC1_SECOND_MSG = 'from BC1 - second';
+const BC2_SECOND_MSG = 'from BC2 - second';
+const BC3_SECOND_MSG = 'done';
+const BC0_TARGET_NAME = 'BC1';
+const BC1_TARGET_NAME = 'BC1';
+const BC2_TARGET_NAME = 'BC2';
+const BC3_TARGET_NAME = 'BC3';
+const MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME = 'multi-frame-order';
+
+const bc0 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+const messages = [];
+
+function logReceivedMessage(targetname, e) {
+ messages.push({'target': targetname, 'data': e.data});
+}
+
+function postMessagesToChannel() {
+ return new Promise((resolve) => {
+ bc0.postMessage(BC0_FIRST_MSG);
+ bc0.postMessage(BC0_SECOND_MSG);
+ resolve();
+ });
+}
+
+// Expected flow of messages between the BroadcastChannel objects (based on
+// the requirement that messages get delivered to BroadcastChannel objects
+// "in creation order, oldest first") and comments describing the actions
+// taken in response to each event
+const EXPECTED_RESULTS = [
+ // -> BC0 sends two messages, BC1 and BC2 are connected to the channel
+
+ {'data': BC0_FIRST_MSG, 'target': BC1_TARGET_NAME},
+ // -> BC1 Creates BC3 and sends first message
+
+ {'data': BC0_FIRST_MSG, 'target': BC2_TARGET_NAME},
+ // -> BC2 sends two messages
+
+ // BC3 isn't expected to receive the messages sent before it was created, so
+ // no corresponding entries here for messages from BC0.
+
+ {'data': BC0_SECOND_MSG, 'target': BC1_TARGET_NAME},
+ // -> BC1 sends second message
+
+ {'data': BC0_SECOND_MSG, 'target': BC2_TARGET_NAME},
+ // -> BC2 closes
+
+ {'data': BC1_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+ {'data': BC1_FIRST_MSG, 'target': BC3_TARGET_NAME},
+ // -> BC3 sends first message
+
+ {'data': BC2_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+ {'data': BC2_FIRST_MSG, 'target': BC1_TARGET_NAME},
+ // -> BC1 closes
+
+ {'data': BC2_FIRST_MSG, 'target': BC3_TARGET_NAME},
+ // -> BC3 sends second message
+
+ {'data': BC2_SECOND_MSG, 'target': BC0_TARGET_NAME},
+
+ {'data': BC2_SECOND_MSG, 'target': BC3_TARGET_NAME},
+ // -> BC3 closes
+
+ {'data': BC1_SECOND_MSG, 'target': BC0_TARGET_NAME},
+
+ {'data': BC3_FIRST_MSG, 'target': BC0_TARGET_NAME},
+
+ {'data': BC3_SECOND_MSG, 'target': BC0_TARGET_NAME},
+];
+
+function testCompletion(t) {
+ return new Promise((resolve) => {
+ bc0.onmessage = t.step_func(e => {
+ logReceivedMessage(BC0_TARGET_NAME, e);
+ if (e.data == BC3_SECOND_MSG) {
+ assert_equals(messages.length, EXPECTED_RESULTS.length);
+ for(var i = 0; i < messages.length; i++) {
+ assert_equals(messages[i].target, EXPECTED_RESULTS[i].target, `Message ${i+1} has unexpected target`);
+ assert_equals(messages[i].data, EXPECTED_RESULTS[i].data, `Message ${i+1} has unexpected message contents`);
+ }
+ resolve();
+ }
+ });
+ });
+}
+
+promise_test(async t => {
+
+ const testResults = testCompletion(t);
+ // Await them sequentially because we need the BroadcastChannel object in
+ // iframe1 to be created first, we need the BroadcastChannel object in
+ // iframe2 to be created second, and then we only want to call
+ // postMessagesToChannel once both BroadcastChannels have been created.
+ await with_iframe('resources/ordering.html?id=iframe1');
+ await with_iframe('resources/ordering.html?id=iframe2');
+ await postMessagesToChannel();
+ return testResults;
+}, "Messages are delivered in port creation order across multiple frames");
+
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/origin.window.js b/testing/web-platform/tests/webmessaging/broadcastchannel/origin.window.js
new file mode 100644
index 0000000000..7e9d602af1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/origin.window.js
@@ -0,0 +1,10 @@
+async_test(t => {
+ const crossOriginURL = new URL("resources/origin.html", self.location.href).href.replace("://", "://天気の良い日."),
+ frame = document.createElement("iframe");
+ frame.src = crossOriginURL;
+ document.body.appendChild(frame);
+ t.add_cleanup(() => frame.remove());
+ self.onmessage = t.step_func_done(e => {
+ assert_equals(e.data, self.origin.replace("://", "://xn--n8j6ds53lwwkrqhv28a."));
+ });
+}, "Serialization of BroadcastChannel origin");
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/cross-origin.html b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/cross-origin.html
new file mode 100644
index 0000000000..5078b6fc8e
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/cross-origin.html
@@ -0,0 +1,15 @@
+<body></body>
+<script>
+ window.onload = function() {
+ bc1 = new BroadcastChannel('no-cross-origin-messages');
+ bc2 = new BroadcastChannel('no-cross-origin-messages');
+ bc2.onmessage = e => {
+ parent.postMessage('done', "*");
+ };
+ // Post a message on bc1 and once we receive it in bc2, we know that the
+ // message should have been sent to bc0 if messages were being passed
+ // across origin (assuming compliance with the spec regarding message
+ // delivery in port creation order).
+ bc1.postMessage('ignition');
+ }
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/ordering.html b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/ordering.html
new file mode 100644
index 0000000000..b7f12d865a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/ordering.html
@@ -0,0 +1,78 @@
+<body></body>
+<script>
+ const BC0_FIRST_MSG = 'from BC0 - first';
+ const BC1_FIRST_MSG = 'from BC1 - first';
+ const BC2_FIRST_MSG = 'from BC2 - first';
+ const BC3_FIRST_MSG = 'from BC3 - first';
+ const BC0_SECOND_MSG = 'from BC0 - second';
+ const BC1_SECOND_MSG = 'from BC1 - second';
+ const BC2_SECOND_MSG = 'from BC2 - second';
+ const BC3_SECOND_MSG = 'done';
+ const BC0_TARGET_NAME = 'BC1';
+ const BC1_TARGET_NAME = 'BC1';
+ const BC2_TARGET_NAME = 'BC2';
+ const BC3_TARGET_NAME = 'BC3';
+ const MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME = 'multi-frame-order';
+
+ var bc1, bc2, bc3;
+ var sentMessageCountForBc1 = 0;
+ var sentMessageCountForBc2 = 0;
+ var sentMessageCountForBc3 = 0;
+
+ var bc1_handler = e => {
+ window.top.logReceivedMessage(BC1_TARGET_NAME, e);
+ switch(sentMessageCountForBc1) {
+ case 0:
+ bc3 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+ bc3.onmessage = bc3_handler;
+ bc1.postMessage(BC1_FIRST_MSG);
+ break;
+ case 1:
+ bc1.postMessage(BC1_SECOND_MSG);
+ break;
+ case 2:
+ bc1.close();
+ return;
+ }
+ sentMessageCountForBc1 += 1;
+ }
+ var bc2_handler = e => {
+ window.top.logReceivedMessage(BC2_TARGET_NAME, e);
+ switch(sentMessageCountForBc2) {
+ case 0:
+ bc2.postMessage(BC2_FIRST_MSG);
+ bc2.postMessage(BC2_SECOND_MSG);
+ sentMessageCountForBc2 += 2;
+ break;
+ case 2:
+ bc2.close();
+ return;
+ }
+ };
+ var bc3_handler = e => {
+ window.top.logReceivedMessage(BC3_TARGET_NAME, e);
+ switch(sentMessageCountForBc3) {
+ case 0:
+ bc3.postMessage(BC3_FIRST_MSG);
+ break;
+ case 1:
+ bc3.postMessage(BC3_SECOND_MSG);
+ break;
+ case 2:
+ bc3.close();
+ return;
+ }
+ sentMessageCountForBc3 += 1;
+ };
+
+ window.onload = function() {
+ const params = new URLSearchParams(window.location.search);
+ if (params.get('id') === 'iframe1') {
+ bc1 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+ bc1.onmessage = bc1_handler;
+ } else if (params.get('id') === 'iframe2') {
+ bc2 = new BroadcastChannel(MULTI_FRAME_ORDERING_TEST_CHANNEL_NAME);
+ bc2.onmessage = bc2_handler;
+ }
+ }
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/origin.html b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/origin.html
new file mode 100644
index 0000000000..f57d582bbb
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/origin.html
@@ -0,0 +1,8 @@
+<script>
+const bc1 = new BroadcastChannel("ladila"),
+ bc2 = new BroadcastChannel("ladila");
+bc2.onmessage = e => {
+ parent.postMessage(e.origin, "*");
+}
+bc1.postMessage("does not matter");
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/sandboxed.html b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/sandboxed.html
new file mode 100644
index 0000000000..e32962cdfd
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/sandboxed.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script>
+try {
+ let c = new BroadcastChannel('foo');
+ parent.postMessage('Created', '*');
+} catch (e) {
+ parent.postMessage('Exception: ' + e.name, '*');
+}
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/service-worker.js b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/service-worker.js
new file mode 100644
index 0000000000..a3d17b9c65
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/service-worker.js
@@ -0,0 +1,15 @@
+let promise_func = null;
+let promise = new Promise(resolve => promise_func = resolve);
+
+const SERVICE_WORKER_TEST_CHANNEL_NAME = 'service worker';
+const bc3 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+bc3.onmessage = e => {
+ bc3.postMessage('done');
+ promise_func();
+};
+bc3.postMessage('from worker');
+
+// Ensure that the worker stays alive for the duration of the test
+self.addEventListener('install', evt => {
+ evt.waitUntil(promise);
+});
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/resources/worker.js b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/worker.js
new file mode 100644
index 0000000000..ee2d51a254
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/resources/worker.js
@@ -0,0 +1,37 @@
+importScripts("/common/gc.js");
+
+var c;
+
+async function handler(e, reply) {
+ if (e.data.ping) {
+ c.postMessage(e.data.ping);
+ return;
+ }
+ if (e.data.blob) {
+ (() => {
+ c.postMessage({blob: new Blob(e.data.blob)});
+ })();
+ await garbageCollect();
+ }
+ c = new BroadcastChannel(e.data.channel);
+ let messages = [];
+ c.onmessage = e => {
+ if (e.data === 'ready') {
+ // Ignore any 'ready' messages from the other thread since there could
+ // be some race conditions between this BroadcastChannel instance
+ // being created / ready to receive messages and the message being sent.
+ return;
+ }
+ messages.push(e.data);
+ if (e.data == 'done')
+ reply(messages);
+ };
+ c.postMessage('from worker');
+}
+
+onmessage = e => handler(e, postMessage);
+
+onconnect = e => {
+ let port = e.ports[0];
+ port.onmessage = e => handler(e, msg => port.postMessage(msg));
+};
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/sandbox.html b/testing/web-platform/tests/webmessaging/broadcastchannel/sandbox.html
new file mode 100644
index 0000000000..aedf3c0d6f
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/sandbox.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<title>Creating BroadcastChannel in an opaque origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+async_test(t => {
+ self.onmessage = t.step_func(e => {
+ assert_equals(e.data, 'Created');
+ t.done();
+ });
+ });
+</script>
+<iframe sandbox="allow-scripts" src="resources/sandboxed.html"></iframe>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/service-worker.https.html b/testing/web-platform/tests/webmessaging/broadcastchannel/service-worker.https.html
new file mode 100644
index 0000000000..d605434ae1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/service-worker.https.html
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+const SERVICE_WORKER_TEST_CHANNEL_NAME = 'service worker';
+const events = [];
+const c1 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+const c2 = new BroadcastChannel(SERVICE_WORKER_TEST_CHANNEL_NAME);
+c1.onmessage = e => events.push(e);
+c2.onmessage = e => events.push(e);
+
+function testCompletion(t) {
+ return new Promise((resolve) => {
+ c2.addEventListener("message", t.step_func(e => {
+ if (e.data == 'from worker') {
+ c2.postMessage('from c2');
+ } else if (e.data == 'done') {
+ assert_equals(events.length, 5);
+ assert_equals(events[0].data, 'from worker');
+ assert_equals(events[0].target, c1);
+ assert_equals(events[1].data, 'from worker');
+ assert_equals(events[1].target, c2);
+ assert_equals(events[2].data, 'from c2');
+ assert_equals(events[3].data, 'done');
+ assert_equals(events[3].target, c1);
+ assert_equals(events[4].data, 'done');
+ assert_equals(events[4].target, c2);
+ resolve();
+ }
+ }));
+ });
+}
+
+promise_test(async t => {
+
+ const testResults = testCompletion(t);
+ const SCRIPT = "resources/service-worker.js";
+ const SCOPE = "/webmessaging/broadcastchannel/resources/not-used/";
+
+ const reg = await navigator.serviceWorker.register(SCRIPT, {'scope': SCOPE});
+ t.add_cleanup(() => reg.unregister());
+
+ return testResults;
+ }, 'BroadcastChannel works in service workers');
+</script>
diff --git a/testing/web-platform/tests/webmessaging/broadcastchannel/workers.html b/testing/web-platform/tests/webmessaging/broadcastchannel/workers.html
new file mode 100644
index 0000000000..8b55492f3c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/broadcastchannel/workers.html
@@ -0,0 +1,375 @@
+<!DOCTYPE html>
+<meta charset=utf-8>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+
+async_test(t => {
+ let c1 = new BroadcastChannel('worker');
+ let c2 = new BroadcastChannel('worker');
+ let events = [];
+
+ c1.onmessage = e => events.push(e);
+ c2.onmessage = e => events.push(e);
+
+ let doneCount = 0;
+ c2.addEventListener('message', t.step_func(e => {
+ if (e.data == 'from worker') {
+ c2.postMessage('from c2');
+ c1.postMessage('done');
+ } else if (e.data == 'done') {
+ assert_equals(events.length, 4);
+ assert_equals(events[0].data, 'from worker');
+ assert_equals(events[0].target, c1);
+ assert_equals(events[1].data, 'from worker');
+ assert_equals(events[1].target, c2);
+ assert_equals(events[2].data, 'from c2');
+ assert_equals(events[3].data, 'done');
+ if (++doneCount == 2) t.done();
+ }
+ }));
+
+ let worker = new Worker('resources/worker.js');
+ worker.onmessage = t.step_func(e => {
+ assert_array_equals(e.data, ['from c2', 'done']);
+ if (++doneCount == 2) t.done();
+ });
+ worker.postMessage({channel: 'worker'});
+
+ }, 'BroadcastChannel works in workers');
+
+async_test(t => {
+ let c1 = new BroadcastChannel('shared worker');
+ let c2 = new BroadcastChannel('shared worker');
+ let events = [];
+
+ c1.onmessage = e => events.push(e);
+ c2.onmessage = e => events.push(e);
+
+ let doneCount = 0;
+ c2.addEventListener('message', t.step_func(e => {
+ if (e.data == 'from worker') {
+ c2.postMessage('from c2');
+ c1.postMessage('done');
+ } else if (e.data == 'done') {
+ assert_equals(events.length, 4);
+ assert_equals(events[0].data, 'from worker');
+ assert_equals(events[0].target, c1);
+ assert_equals(events[1].data, 'from worker');
+ assert_equals(events[1].target, c2);
+ assert_equals(events[2].data, 'from c2');
+ assert_equals(events[3].data, 'done');
+ if (++doneCount == 2) t.done();
+ }
+ }));
+
+ let worker = new SharedWorker('resources/worker.js');
+ worker.port.onmessage = t.step_func(e => {
+ assert_array_equals(e.data, ['from c2', 'done']);
+ if (++doneCount == 2) t.done();
+ });
+ worker.port.postMessage({channel: 'shared worker'});
+
+ }, 'BroadcastChannel works in shared workers');
+
+async_test(t => {
+ let c = new BroadcastChannel('worker-close');
+ let events = [];
+
+ c.onmessage = e => events.push('c1: ' + e.data);
+
+ let worker = new Worker('resources/worker.js');
+ worker.onmessage = t.step_func(e => {
+ assert_array_equals(events,
+ ['c1: from worker', 'c2: ready', 'c2: echo'],
+ 'messages in document');
+ assert_array_equals(e.data, ['done'], 'messages in worker');
+ t.done();
+ });
+ worker.onmessagerror =
+ t.unreached_func('Worker\'s onmessageerror handler called');
+
+ c.addEventListener('message', e => {
+ if (e.data == 'from worker') {
+ c.close();
+ if (self.gc) self.gc();
+ window.setTimeout(() => {
+ let c2 = new BroadcastChannel('worker-close');
+ c2.onmessage = e => {
+ events.push('c2: ' + e.data);
+ if (e.data === 'ready') {
+ worker.postMessage({ping: 'echo'});
+ } else {
+ c2.postMessage('done');
+ c2.close();
+ }
+ };
+ // For some implementations there may be a race condition between
+ // when the BroadcastChannel instance above is created / ready to
+ // receive messages and when the worker calls postMessage on it's
+ // BroadcastChannel instance. To avoid this, confirm that our
+ // instance can receive a message before indicating to the other
+ // thread that we are ready. For more details, see:
+ // https://github.com/whatwg/html/issues/7267
+ let c3 = new BroadcastChannel('worker-close');
+ c3.postMessage('ready');
+ c3.close();
+ }, 1);
+ }
+ });
+
+ worker.postMessage({channel: 'worker-close'});
+ t.add_cleanup(() => worker.terminate());
+
+ }, 'Closing and re-opening a channel works.');
+
+async_test(t => {
+ function workerCode() {
+ close();
+ try {
+ var bc = new BroadcastChannel('worker-create-after-close');
+ } catch (e) {
+ postMessage(e);
+ return;
+ }
+ postMessage(true);
+ }
+
+ var workerBlob = new Blob(
+ [workerCode.toString() + ';workerCode();'],
+ {type: 'application/javascript'});
+
+ var w = new Worker(URL.createObjectURL(workerBlob));
+ w.onmessage = t.step_func_done(function(e) {
+ assert_equals(
+ e.data, true,
+ 'BroadcastChannel creation in closed worker triggered exception: ' +
+ e.data.message);
+ });
+ t.add_cleanup(() => w.terminate());
+}, 'BroadcastChannel created after a worker self.close()');
+
+
+function postMessageFromWorkerWorkerCode(workerName, channelName) {
+ if (workerName === 'close-before-create-worker') {
+ close();
+ }
+ let bc = new BroadcastChannel(channelName);
+ if (workerName === 'close-after-create-worker') {
+ close();
+ }
+ bc.postMessage(workerName + ' done');
+ postMessage(true);
+}
+
+function doPostMessageFromWorkerTest(t, workerName, channelName) {
+ var bc = new BroadcastChannel(channelName);
+ bc.onmessage = t.step_func_done(function(e) {
+ assert_equals(
+ e.data, 'done-worker done',
+ 'BroadcastChannel message should only be received from the second worker');
+ });
+ t.add_cleanup(() => bc.close());
+
+ var testMessageHandler = t.step_func(function(e) {
+ assert_equals(
+ e.data, true,
+ 'Worker sent postMessage indicating it sent a BroadcastChannel message');
+
+ var w = createWorker(
+ postMessageFromWorkerWorkerCode, 'done-worker', channelName);
+ t.add_cleanup(() => w.terminate());
+ });
+ createWorker(
+ postMessageFromWorkerWorkerCode, workerName, channelName,
+ testMessageHandler);
+
+ // To avoid calling t.step_timeout here, have the worker postMessage(true)
+ // once it is finished and then we'll instantiate another worker that
+ // performs the same test steps but doesn't close. By the time the
+ // BroadcastChannel message in that worker gets sent successfully it should
+ // be safe to assume that any BroadcastChannel messages from the previous
+ // worker would have been sent if they were going to be.
+}
+
+function createWorker(workerCode, workerName, channelName, handler = null) {
+ var workerCodeStr = workerCode.toString() +
+ `;${workerCode.name}("${workerName}", "${channelName}");`;
+ var workerBlob = new Blob([workerCodeStr], {type: 'application/javascript'});
+ var w = new Worker(URL.createObjectURL(workerBlob));
+ if (handler !== null) {
+ w.onmessage = handler;
+ }
+ return w;
+}
+
+async_test(t => {
+ const workerName = 'close-after-create-worker';
+ const channelName = workerName + '-postmessage-from-worker';
+ doPostMessageFromWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from closed worker to parent should be ignored (BC created before closing)');
+
+async_test(t => {
+ const workerName = 'close-before-create-worker';
+ const channelName = workerName + '-postmessage-from-worker';
+ doPostMessageFromWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from closed worker to parent should be ignored (BC created after closing)');
+
+
+function postMessageToWorkerWorkerCode(workerName, channelName) {
+ self.addEventListener('message', () => {
+ if (workerName === 'close-before-create-worker') {
+ close();
+ }
+ try {
+ let bc1 = new BroadcastChannel(channelName);
+ bc1.onmessage = e => {
+ if (e.data === 'ready') {
+ postMessage(e.data);
+ } else if (e.data === 'test') {
+ postMessage(workerName + ' done');
+ }
+ };
+ bc1.onmessageerror = () => {
+ postMessage('onmessageerror called from worker BroadcastChannel');
+ };
+ if (workerName === 'close-after-create-worker') {
+ close();
+ }
+ } catch (e) {
+ postMessage(e);
+ return;
+ }
+
+ if (workerName === 'done-worker') {
+ // For some implementations there may be a race condition between when
+ // the BroadcastChannel instance above is created / ready to receive
+ // messages and when the parent calls postMessage on it's
+ // BroadcastChannel instance. To avoid this, confirm that our instance
+ // can receive a message before indicating to the other thread that we
+ // are ready. For more details, see:
+ // https://github.com/whatwg/html/issues/7267
+ let bc2 = new BroadcastChannel(channelName);
+ bc2.postMessage('ready');
+ bc2.close();
+ } else {
+ // Since the worker has closed, it's not expected that the
+ // BroadcastChannel will receive messages (there's a separate test for
+ // that), so just indicate directly that it's ready to test receiving
+ // a message from the parent dispite the possibility of a race condition.
+ postMessage('ready');
+ }
+ });
+ self.addEventListener('messageerror', () => {
+ postMessage('onmessageerror called from worker');
+ });
+}
+
+function doPostMessageToWorkerTest(t, workerName, channelName) {
+ var bc = new BroadcastChannel(channelName);
+ t.add_cleanup(() => bc.close());
+
+ var doneMessageHandler = t.step_func(function(e) {
+ if (e.data === 'ready') {
+ bc.postMessage('test');
+ } else if (e.data === 'done-worker done') {
+ t.done();
+ } else {
+ assert_unreached(
+ 'BroadcastChannel.postMessage triggered exception within second worker: ' +
+ e.data.message);
+ }
+ });
+ var testMessageHandler = t.step_func(function(e) {
+ assert_equals(
+ e.data, 'ready',
+ 'Worker sent postMessage indicating its BroadcastChannel instance is ready');
+ bc.postMessage('test');
+
+ var doneWorker = createWorker(
+ postMessageToWorkerWorkerCode, 'done-worker', channelName,
+ doneMessageHandler);
+ t.add_cleanup(() => {
+ doneWorker.terminate();
+ });
+ doneWorker.postMessage('start');
+ });
+ var testWorker = createWorker(
+ postMessageToWorkerWorkerCode, workerName, channelName,
+ testMessageHandler);
+ testWorker.postMessage('start');
+}
+
+async_test(t => {
+ const workerName = 'close-after-create-worker';
+ const channelName = workerName + '-postmessage-to-worker';
+ doPostMessageToWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from parent to closed worker should be ignored (BC created before closing)');
+
+async_test(t => {
+ const workerName = 'close-before-create-worker';
+ const channelName = workerName + '-postmessage-to-worker';
+ doPostMessageToWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages from parent to closed worker should be ignored (BC created after closing)');
+
+
+function postMessageWithinWorkerWorkerCode(workerName, channelName) {
+ if (workerName === 'close-before-create-worker') {
+ close();
+ }
+ try {
+ let bc1 = new BroadcastChannel(channelName);
+ let bc2 = new BroadcastChannel(channelName);
+ bc1.onmessage = e => {
+ postMessage(workerName + ' done')
+ };
+ if (workerName === 'close-after-create-worker') {
+ close();
+ }
+ bc2.postMessage(true);
+ postMessage(true);
+ } catch (e) {
+ postMessage(e);
+ }
+}
+
+function doPostMessageWithinWorkerTest(t, workerName, channelName) {
+ var doneMessageHandler = t.step_func(function(e) {
+ if (e.data === true) {
+ // Done worker has finished - no action needed
+ } else if (e.data === 'done-worker done') {
+ t.done();
+ } else {
+ assert_unreached(
+ 'BroadcastChannel.postMessage triggered exception within second worker: ' +
+ e.data.message);
+ }
+ });
+ var testMessageHandler = t.step_func(function(e) {
+ assert_equals(
+ e.data, true,
+ 'Worker indicated that the test procedures were executed successfully');
+
+ var w = createWorker(
+ postMessageWithinWorkerWorkerCode, 'done-worker', channelName,
+ doneMessageHandler);
+ t.add_cleanup(() => w.terminate());
+ });
+ createWorker(
+ postMessageWithinWorkerWorkerCode, workerName, channelName,
+ testMessageHandler);
+}
+
+async_test(t => {
+ const workerName = 'close-after-create-worker';
+ const channelName = workerName + '-postmessage-within-worker';
+ doPostMessageWithinWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages within closed worker should be ignored (BCs created before closing)');
+
+async_test(t => {
+ const workerName = 'close-before-create-worker';
+ const channelName = workerName + '-postmessage-within-worker';
+ doPostMessageWithinWorkerTest(t, workerName, channelName);
+}, 'BroadcastChannel messages within closed worker should be ignored (BCs created after closing)');
+
+</script>
diff --git a/testing/web-platform/tests/webmessaging/event.data.sub.htm b/testing/web-platform/tests/webmessaging/event.data.sub.htm
new file mode 100644
index 0000000000..6858ef4c69
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/event.data.sub.htm
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> event.data returns the data of the message </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<script>
+
+
+ var description = "Test Description: event.data returns the data of the message.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var DATA = "STRING";
+ var TYPE = "string";
+ var XORIGIN = "{{location[scheme]}}://{{domains[www]}}" + PORT;
+ var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT;
+ var ExpectedResult = [DATA, TYPE, DATA, TYPE];
+ var ActualResult = [];
+
+ window.onmessage = t.step_func(function(e)
+ {
+ if (e.data.toString() === "STRING") {
+ ActualResult.push(e.data, typeof(e.data));
+
+ if (ActualResult.length >= ExpectedResult.length) {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ }
+ });
+</script>
+
+<div style="display:none">
+ <iframe width="70%" onload="this.contentWindow.postMessage(DATA, XORIGIN)" src="{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+ <iframe width="70%" onload="this.contentWindow.postMessage(DATA, SORIGIN)" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/event.origin.sub.htm b/testing/web-platform/tests/webmessaging/event.origin.sub.htm
new file mode 100644
index 0000000000..5b1ab3e3c3
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/event.origin.sub.htm
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> event.origin returns the origin of the message </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[天気の良い日]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: event.origin returns the origin of the message.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var TARGET1 = document.querySelectorAll("iframe")[0];
+ var TARGET2 = document.querySelectorAll("iframe")[1];
+ var XORIGIN = "{{location[scheme]}}://{{domains[天気の良い日]}}" + PORT;
+ var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT;
+ var ExpectedResult = ["#1", XORIGIN, "#2", SORIGIN];
+ var ActualResult = [];
+ var loaded = 0;
+
+ function PostMessageTest()
+ {
+ loaded++;
+
+ if (loaded == 2)
+ {
+ TARGET1.contentWindow.postMessage("#1", XORIGIN);
+ TARGET2.contentWindow.postMessage("#2", SORIGIN);
+ }
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ // Messages from TARGET1 and TARGET2 can come in any order
+ // (since one of them is cross-origin and can run in parallel).
+ // To make the tests immune to message reordering, always
+ // put the response from TARGET1 at the start of the list.
+ if (e.data.toString() === "#1")
+ {
+ ActualResult = [e.data, e.origin].concat(ActualResult);
+ }
+ else if (e.data.toString() === "#2")
+ {
+ ActualResult = ActualResult.concat([e.data, e.origin]);
+ }
+
+ if (ActualResult.length >= ExpectedResult.length)
+ {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/event.ports.sub.htm b/testing/web-platform/tests/webmessaging/event.ports.sub.htm
new file mode 100644
index 0000000000..a4ca24b15e
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/event.ports.sub.htm
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> event.ports returns the MessagePort array sent with the message </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: event.ports returns the MessagePort array sent with the message.";
+
+ var t = async_test(description);
+
+ var DATA = {test: "e.source.postMessage(e.ports.toString(), '*', e.ports)"};
+ var TARGET = document.querySelector("iframe");
+ var ExpectedResult = "";
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_own_property(window, "MessageChannel", "window");
+
+ var channel = new MessageChannel();
+ var ports = [channel.port1, channel.port2];
+ ExpectedResult = ports.toString();
+ TARGET.contentWindow.postMessage(DATA, "*", ports);
+
+ }, "MessageChannel is supported.");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(e.data, ExpectedResult, "e.data");
+ assert_true(e.ports[0] instanceof MessagePort, e.ports[0] + " instanceof MessageChannel");
+ assert_true(e.ports[1] instanceof MessagePort, e.ports[1] + " instanceof MessageChannel");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/event.source.htm b/testing/web-platform/tests/webmessaging/event.source.htm
new file mode 100644
index 0000000000..365a5feb47
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/event.source.htm
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Same-origin: event.source returns the WindowProxy of the source window </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: Same-origin: event.source returns the WindowProxy of the source window.";
+
+ var t = async_test(description);
+
+ var DATA = "foo";
+ var TARGET = document.querySelector("iframe");
+ var SORIGIN = location.protocol + "//" + location.host;
+ var ExpectedResult = [SORIGIN, "AccessCookieAllowed"];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, SORIGIN);
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ try
+ {
+ var sdomainCookie = e.source.document.cookie;
+ ActualResult.push(e.origin, "AccessCookieAllowed");
+ }
+ catch(ex)
+ {
+ ActualResult.push(e.origin, "AccessCookieDenied");
+ }
+
+ assert_equals(e.source, TARGET.contentWindow);
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/event.source.xorigin.sub.htm b/testing/web-platform/tests/webmessaging/event.source.xorigin.sub.htm
new file mode 100644
index 0000000000..7327f78667
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/event.source.xorigin.sub.htm
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Corss-origin: event.source returns the WindowProxy of the source window </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+ var description = "Test Description: Cross-origin: event.source returns the WindowProxy of the source window.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var DATA = "foo";
+ var TARGET = document.querySelector("iframe");
+ var XORIGIN = "{{location[scheme]}}://{{domains[www1]}}" + PORT;
+ var ExpectedResult = [XORIGIN, "AccessCookieDenied"];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, XORIGIN);
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ try
+ {
+ var sdomainCookie = e.source.document.cookie;
+ ActualResult.push(e.origin, "AccessCookieAllowed");
+ }
+ catch(ex)
+ {
+ ActualResult.push(e.origin, "AccessCookieDenied");
+ }
+
+ assert_equals(e.source.parent, window);
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/message-channels/basics.any.js b/testing/web-platform/tests/webmessaging/message-channels/basics.any.js
new file mode 100644
index 0000000000..5732fb268a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/basics.any.js
@@ -0,0 +1,12 @@
+// META: title=basic messagechannel test
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port1.postMessage(1);
+ channel.port2.onmessage = t.step_func(
+ function(e) {
+ assert_equals(e.data, 1);
+ t.done();
+ });
+ channel.port2.start();
+});
diff --git a/testing/web-platform/tests/webmessaging/message-channels/close.any.js b/testing/web-platform/tests/webmessaging/message-channels/close.any.js
new file mode 100644
index 0000000000..8741d894b9
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/close.any.js
@@ -0,0 +1,62 @@
+// How long (in ms) these tests should wait before deciding no further messages
+// will be received.
+const time_to_wait_for_messages = 100;
+
+async_test(t => {
+ const c = new MessageChannel();
+ c.port1.onmessage = t.unreached_func('Should not have delivered message');
+ c.port1.close();
+ c.port2.postMessage('TEST');
+ setTimeout(t.step_func_done(), time_to_wait_for_messages);
+ }, 'Message sent to closed port should not arrive.');
+
+async_test(t => {
+ const c = new MessageChannel();
+ c.port1.onmessage = t.unreached_func('Should not have delivered message');
+ c.port2.close();
+ c.port2.postMessage('TEST');
+ setTimeout(t.step_func_done(), time_to_wait_for_messages);
+ }, 'Message sent from closed port should not arrive.');
+
+async_test(t => {
+ const c = new MessageChannel();
+ c.port1.onmessage = t.unreached_func('Should not have delivered message');
+ c.port1.close();
+ const c2 = new MessageChannel();
+ c2.port1.onmessage = t.step_func(e => {
+ e.ports[0].postMessage('TESTMSG');
+ setTimeout(t.step_func_done(), time_to_wait_for_messages);
+ });
+ c2.port2.postMessage('TEST', [c.port2]);
+ }, 'Message sent to closed port from transferred port should not arrive.');
+
+async_test(t => {
+ const c = new MessageChannel();
+ let isClosed = false;
+ c.port1.onmessage = t.step_func_done(e => {
+ assert_true(isClosed);
+ assert_equals(e.data, 'TEST');
+ });
+ c.port2.postMessage('TEST');
+ c.port2.close();
+ isClosed = true;
+ }, 'Inflight messages should be delivered even when sending port is closed afterwards.');
+
+async_test(t => {
+ const c = new MessageChannel();
+ c.port1.onmessage = t.step_func_done(e => {
+ if (e.data == 'DONE') t.done();
+ assert_equals(e.data, 'TEST');
+ c.port1.close();
+ });
+ c.port2.postMessage('TEST');
+ c.port2.postMessage('DONE');
+ }, 'Close in onmessage should not cancel inflight messages.');
+
+test(() => {
+ const c1 = new MessageChannel();
+ const c2 = new MessageChannel();
+ c1.port1.close();
+ assert_throws_dom("DataCloneError", () => c2.port1.postMessage(null, [c1.port1]));
+ c2.port1.postMessage(null, [c1.port2]);
+}, "close() detaches a MessagePort (but not the one its entangled with)");
diff --git a/testing/web-platform/tests/webmessaging/message-channels/cross-document.html b/testing/web-platform/tests/webmessaging/message-channels/cross-document.html
new file mode 100644
index 0000000000..f4512ba5a2
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/cross-document.html
@@ -0,0 +1,22 @@
+<!doctype html>
+<title>cross-document channel</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src=resources/cross-document-1.html></iframe><iframe src=resources/cross-document-2.html></iframe>
+<div id="log"></div>
+<script>
+var t = async_test();
+onload = t.step_func(
+ function() {
+ var channel = new MessageChannel();
+ window[0].postMessage(1, '*', [channel.port1]);
+ window[1].postMessage(2, '*', [channel.port2]);
+ channel = null;
+ window.onmessage = t.step_func(
+ function(e) {
+ assert_equals(e.data, 1);
+ t.done();
+ });
+ }
+);
+</script>
diff --git a/testing/web-platform/tests/webmessaging/message-channels/detached-iframe.window.js b/testing/web-platform/tests/webmessaging/message-channels/detached-iframe.window.js
new file mode 100644
index 0000000000..c19f50ff93
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/detached-iframe.window.js
@@ -0,0 +1,46 @@
+// META: title=MessageChannel in a detached iframe test
+// META: script=/service-workers/service-worker/resources/test-helpers.sub.js
+// META: script=/common/gc.js
+// Pull in the with_iframe helper function from the service worker tests
+
+
+const IframeAction = {
+ REMOVE_BEFORE_CREATION: 'remove-before-creation',
+ REMOVE_AFTER_CREATION: 'remove-after-creation',
+};
+
+async function detached_frame_test(t, action) {
+ const iframe = await with_iframe('about:blank');
+ const iframe_MessageChannel = iframe.contentWindow.MessageChannel;
+
+ if (action === IframeAction.REMOVE_BEFORE_CREATION) {
+ iframe.remove();
+ }
+
+ (() => {
+ const mc = new iframe_MessageChannel();
+ mc.port1.postMessage("boo");
+ mc.port2.onmessage = t.unreached_func("message event received");
+ mc.port2.onmessageerror = t.unreached_func("message event received");
+ })();
+
+ if (action === IframeAction.REMOVE_AFTER_CREATION) {
+ iframe.remove();
+ }
+
+ await garbageCollect();
+
+ // We are testing that neither of the above two events fire. We assume that a 2 second timeout
+ // is good enough. We can't use any other API for an end condition because each MessagePort has
+ // its own independent port message queue, which has no ordering guarantees relative to other
+ // APIs.
+ await new Promise(resolve => t.step_timeout(resolve, 2000));
+}
+
+promise_test(async (t) => {
+ return detached_frame_test(t, IframeAction.REMOVE_AFTER_CREATION);
+}, 'MessageChannel created from a detached iframe should not send messages (remove after create)');
+
+promise_test(async (t) => {
+ return detached_frame_test(t, IframeAction.REMOVE_BEFORE_CREATION);
+}, 'MessageChannel created from a detached iframe should not send messages (remove before create)');
diff --git a/testing/web-platform/tests/webmessaging/message-channels/dictionary-transferrable.any.js b/testing/web-platform/tests/webmessaging/message-channels/dictionary-transferrable.any.js
new file mode 100644
index 0000000000..bf49fddb99
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/dictionary-transferrable.any.js
@@ -0,0 +1,13 @@
+// META: title=basic messagechannel with transfer
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ var ab = new ArrayBuffer(1);
+ channel.port1.postMessage(ab, {transfer: [ab]});
+ channel.port2.onmessage = t.step_func(
+ function(e) {
+ assert_equals(e.data.byteLength, 1);
+ t.done();
+ });
+ channel.port2.start();
+});
diff --git a/testing/web-platform/tests/webmessaging/message-channels/implied-start.any.js b/testing/web-platform/tests/webmessaging/message-channels/implied-start.any.js
new file mode 100644
index 0000000000..460d26b7e4
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/implied-start.any.js
@@ -0,0 +1,14 @@
+// META: title=onmessage implied start()
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port1.postMessage(1);
+ channel.port2.onmessage = function() {
+ setTimeout(t.step_func(function() {
+ t.done();
+ }), 50);
+ channel.port2.onmessage = t.step_func(function() {
+ assert_unreached();
+ });
+ }; // implies start()
+});
diff --git a/testing/web-platform/tests/webmessaging/message-channels/no-start.any.js b/testing/web-platform/tests/webmessaging/message-channels/no-start.any.js
new file mode 100644
index 0000000000..75b1ea1b26
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/no-start.any.js
@@ -0,0 +1,9 @@
+// META: title=without start()
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port1.postMessage(1);
+ var i = 0;
+ channel.port2.addEventListener('message', function() { i++; }, false);
+ setTimeout(t.step_func(function() { assert_equals(i, 0); t.done();}), 50);
+});
diff --git a/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-1.html b/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-1.html
new file mode 100644
index 0000000000..93725a93f8
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-1.html
@@ -0,0 +1,8 @@
+<!doctype html>
+<title>crosss-document-1</title>
+<script>
+onmessage = function(e) {
+ var port = e.ports[0];
+ port.postMessage(e.data);
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-2.html b/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-2.html
new file mode 100644
index 0000000000..1b8ef0a7a0
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/resources/cross-document-2.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>004-2</title>
+<script>
+onmessage = function(e) {
+ var port = e.ports[0];
+ port.onmessage = function(e) { // implied start()
+ parent.postMessage(e.data, '*');
+ }
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/webmessaging/message-channels/user-activation.tentative.any.js b/testing/web-platform/tests/webmessaging/message-channels/user-activation.tentative.any.js
new file mode 100644
index 0000000000..175662873c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/user-activation.tentative.any.js
@@ -0,0 +1,21 @@
+// META: title=user activation messagechannel test
+
+async_test(function(t) {
+ var channel = new MessageChannel();
+ channel.port1.postMessage(1, {includeUserActivation: true});
+ channel.port1.postMessage(2);
+ var expected_data = 1;
+ channel.port2.onmessage = t.step_func(
+ function(e) {
+ assert_equals(e.data, expected_data);
+ expected_data++;
+ if (e.data == 1) {
+ assert_false(e.userActivation.isActive);
+ assert_false(e.userActivation.hasBeenActive);
+ } else {
+ assert_equals(e.userActivation, null);
+ t.done();
+ }
+ });
+ channel.port2.start();
+});
diff --git a/testing/web-platform/tests/webmessaging/message-channels/worker-post-after-close.any.js b/testing/web-platform/tests/webmessaging/message-channels/worker-post-after-close.any.js
new file mode 100644
index 0000000000..2de0c434de
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/worker-post-after-close.any.js
@@ -0,0 +1,28 @@
+async_test(t => {
+ function workerCode() {
+ onmessage = function(e) {
+ close();
+ var mc = new MessageChannel();
+ mc.port1.onmessage = function() {
+ postMessage("message received!");
+ }
+ mc.port2.postMessage(42);
+ postMessage("done");
+ }
+ }
+
+ var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], {type:"application/javascript"});
+
+ var w = new Worker(URL.createObjectURL(workerBlob));
+ w.postMessage('');
+ w.onmessage = function(e) {
+ if (e.data == "done") {
+ setTimeout(function() {
+ t.done();
+ }, 250);
+ } else {
+ assert_true(false, "A wrong message has been received!");
+ }
+ }
+}, 'MessageChannel/MessagePort should not work after a worker self.close()');
+
diff --git a/testing/web-platform/tests/webmessaging/message-channels/worker.any.js b/testing/web-platform/tests/webmessaging/message-channels/worker.any.js
new file mode 100644
index 0000000000..633d89a371
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/message-channels/worker.any.js
@@ -0,0 +1,17 @@
+async_test(t => {
+ function workerCode() {
+ close();
+ var mc = new MessageChannel();
+ mc.port1.postMessage(42);
+ mc.port2.postMessage(42);
+ postMessage(true);
+ }
+
+ var workerBlob = new Blob([workerCode.toString() + ";workerCode();"], {type:"application/javascript"});
+
+ var w = new Worker(URL.createObjectURL(workerBlob));
+ w.onmessage = function(e) {
+ assert_true(e.data, "MessageChannel created on worker shutdown.");
+ t.done();
+ }
+}, 'MessageChannel/MessagePort created and used after a worker self.close()');
diff --git a/testing/web-platform/tests/webmessaging/messageerror.html b/testing/web-platform/tests/webmessaging/messageerror.html
new file mode 100644
index 0000000000..2cb51ee3c0
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/messageerror.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<title>onmessageerror content attribute</title>
+<link rel="author" title="Domenic Denicola" href="mailto:d@domenic.me">
+<link rel="help" href="https://html.spec.whatwg.org/multipage/#handler-onmessageerror">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<body>
+
+<script>
+"use strict";
+window.messageErrorHappened = false;
+
+function cleanup() {
+ window.messageErrorHappened = false;
+ document.body.removeAttribute("onmessageerror");
+}
+
+test(() => {
+ assert_equals(document.body.onmessageerror, null, "body");
+ assert_equals(window.onmessageerror, null, "window");
+}, "The default value of onmessageerror is null");
+
+test(t => {
+ t.add_cleanup(cleanup);
+
+ document.body.setAttribute("onmessageerror", "window.messageErrorHappened = true;")
+ const compiledHandler = document.body.onmessageerror;
+
+ assert_equals(typeof compiledHandler, "function", "The onmessageerror property must be a function");
+ compiledHandler();
+ assert_true(window.messageErrorHappened, "Calling the handler must run the code");
+}, "The onmessageerror content attribute must be compiled into the onmessageerror property");
+
+test(t => {
+ t.add_cleanup(cleanup);
+
+ document.body.setAttribute("onmessageerror", "window.messageErrorHappened = true;")
+
+ window.dispatchEvent(new Event("messageerror"));
+
+ assert_true(window.messageErrorHappened, "Dispatching the event must run the code");
+}, "The onmessageerror content attribute must execute when an event is dispatched on the window");
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-current.sub.html b/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-current.sub.html
new file mode 100644
index 0000000000..ae2369394e
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-current.sub.html
@@ -0,0 +1,45 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>The current page being cross-origin must prevent the BroadcastChannel message from being seen</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This is the entry global -->
+
+<iframe src="support/incumbent-document-domain.sub.html" id="incumbent"></iframe>
+<iframe src="http://{{hosts[][www]}}:{{ports[http][0]}}/webmessaging/multi-globals/support/current-document-domain.sub.html" id="current"></iframe>
+
+<script>
+"use strict";
+document.domain = "{{hosts[][]}}";
+
+setup({ explicit_done: true });
+
+const incumbentIframe = document.querySelector("#incumbent");
+const currentIframe = document.querySelector("#current");
+
+window.onload = () => {
+ promise_test(async t => {
+ const createdCrossOrigin = frames[0].createBroadcastChannel("current");
+ const createdSameOrigin = new BroadcastChannel("current");
+
+ createdSameOrigin.onmessage = t.unreached_func("message event fired");
+ createdSameOrigin.onmessageerror = t.unreached_func("messageerror event fired");
+
+ createdCrossOrigin.postMessage("the message");
+
+ // BroadcastChannel messages are guaranteed to be ordered within an event loop, as they all use
+ // the DOM manipulation task source. So, any messages from the "current" channel, if they are
+ // going to be erroneously delivered, would have to be delivered before those from this
+ // channel. I.e., if we recieve a message from this channel without first recieving one from
+ // the "current" channel, then the test passes.
+ const testEnder = new BroadcastChannel("current / test-ender");
+ const testEnder2 = new BroadcastChannel("current / test-ender");
+
+ testEnder.postMessage("end test");
+ await new Promise(resolve => testEnder2.onmessage = resolve);
+ });
+
+ done();
+};
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-incumbent.sub.html b/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-incumbent.sub.html
new file mode 100644
index 0000000000..31a4221c1d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/broadcastchannel-incumbent.sub.html
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>The incumbent page being cross-origin must not prevent the BroadcastChannel message from being seen</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This is the entry global -->
+
+<iframe src="http://{{hosts[][www]}}:{{ports[http][0]}}/webmessaging/multi-globals/support/incumbent-document-domain.sub.html" id="incumbent"></iframe>
+<iframe src="support/current-document-domain.sub.html" id="current"></iframe>
+
+<script>
+"use strict";
+document.domain = "{{hosts[][]}}";
+
+setup({ explicit_done: true });
+
+const incumbentIframe = document.querySelector("#incumbent");
+const currentIframe = document.querySelector("#current");
+
+window.onload = () => {
+ async_test(t => {
+ const createdThroughCrossOrigin = frames[0].createBroadcastChannel("incumbent");
+ const createdSameOrigin = new BroadcastChannel("incumbent");
+
+ createdSameOrigin.onmessage = () => t.done();
+ createdSameOrigin.onmessageerror = t.unreached_func("messageerror event fired");
+
+ createdThroughCrossOrigin.postMessage("the message");
+ });
+
+ done();
+};
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/messageport-current.html b/testing/web-platform/tests/webmessaging/multi-globals/messageport-current.html
new file mode 100644
index 0000000000..ee172c6138
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/messageport-current.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Making the current page become non-active must prevent message transmission</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This is the entry global -->
+
+<iframe src="support/incumbent.html" id="incumbent"></iframe>
+<iframe src="support/current.html" id="current"></iframe>
+
+<script>
+"use strict";
+const incumbentIframe = document.querySelector("#incumbent");
+const currentIframe = document.querySelector("#current");
+
+window.addEventListener("load", () => {
+ promise_test(async t => {
+ // This will invoke the constructor from currentIframe, but with incumbentIframe as the incumbent.
+ const messageChannel = incumbentIframe.contentWindow.createMessageChannel();
+
+ await new Promise((resolve, reject) => {
+ currentIframe.onload = () => resolve();
+ currentIframe.onerror = () => reject(new Error("Could not navigate the iframe"));
+ currentIframe.src = "/common/blank.html";
+ });
+
+ messageChannel.port1.onmessage = t.unreached_func("message event recieved");
+ messageChannel.port1.onmessageerror = t.unreached_func("messageerror event recieved");
+ messageChannel.port2.postMessage("boo");
+
+ // We are testing that neither of the above two events fire. We assume that a 3 second timeout
+ // is good enough. We can't use any other API for an end condition because each MessagePort has
+ // its own independent port message queue, which has no ordering guarantees relative to other
+ // APIs.
+ await new Promise(resolve => t.step_timeout(resolve, 3000));
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/messageport-incumbent.html b/testing/web-platform/tests/webmessaging/multi-globals/messageport-incumbent.html
new file mode 100644
index 0000000000..4d47fb8124
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/messageport-incumbent.html
@@ -0,0 +1,35 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Making the incumbent page become non-active must not prevent message transmission</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<!-- This is the entry global -->
+
+<iframe src="support/incumbent.html" id="incumbent"></iframe>
+<iframe src="support/current.html" id="current"></iframe>
+
+<script>
+"use strict";
+const incumbentIframe = document.querySelector("#incumbent");
+const currentIframe = document.querySelector("#current");
+
+window.addEventListener("load", () => {
+ promise_test(async () => {
+ // This will invoke the constructor from currentIframe, but with incumbentIframe as the incumbent.
+ const messageChannel = incumbentIframe.contentWindow.createMessageChannel();
+
+ await new Promise((resolve, reject) => {
+ incumbentIframe.onload = () => resolve();
+ incumbentIframe.onerror = () => reject(new Error("Could not navigate the iframe"));
+ incumbentIframe.src = "/common/blank.html";
+ });
+
+ await new Promise((resolve, reject) => {
+ messageChannel.port1.onmessage = () => resolve();
+ messageChannel.port1.onmessageerror = () => reject("messageerror event recieved");
+ messageChannel.port2.postMessage("boo");
+ });
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/support/current-document-domain.sub.html b/testing/web-platform/tests/webmessaging/multi-globals/support/current-document-domain.sub.html
new file mode 100644
index 0000000000..1b15f72ca4
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/support/current-document-domain.sub.html
@@ -0,0 +1,10 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Current page used as a test helper</title>
+
+<h1>Current</h1>
+
+<script>
+"use strict";
+document.domain = "{{hosts[][]}}";
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/support/current.html b/testing/web-platform/tests/webmessaging/multi-globals/support/current.html
new file mode 100644
index 0000000000..d05709dd43
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/support/current.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Current page used as a test helper</title>
+
+<h1>Current</h1>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent-document-domain.sub.html b/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent-document-domain.sub.html
new file mode 100644
index 0000000000..4791c29be7
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent-document-domain.sub.html
@@ -0,0 +1,14 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Incumbent page used as a test helper</title>
+
+<h1>Incumbent</h1>
+
+<script>
+"use strict";
+document.domain = "{{hosts[][]}}";
+
+window.createBroadcastChannel = (...args) => {
+ return new parent.frames[1].BroadcastChannel(...args);
+};
+</script>
diff --git a/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent.html b/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent.html
new file mode 100644
index 0000000000..a06e93c7ab
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/multi-globals/support/incumbent.html
@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Incumbent page used as a test helper</title>
+
+<h1>Incumbent</h1>
+
+<script>
+"use strict";
+
+window.createMessageChannel = () => {
+ return new parent.frames[1].MessageChannel();
+};
+</script>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_ArrayBuffer.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_ArrayBuffer.sub.htm
new file mode 100644
index 0000000000..457cf94fa5
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_ArrayBuffer.sub.htm
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with ArrayBuffer object </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: postMessage with ArrayBuffer object.";
+
+ var t = async_test(description);
+
+ var DATA;
+ var TYPE = "object";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ DATA = new ArrayBuffer(32);
+ TARGET.contentWindow.postMessage(DATA, "*");
+ }, "ArrayBuffer is supported.");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(typeof(e.data), TYPE);
+ assert_equals(e.data.toString(), DATA.toString());
+ assert_equals(e.data.byteLength, 32);
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_CryptoKey_insecure.sub.html b/testing/web-platform/tests/webmessaging/postMessage_CryptoKey_insecure.sub.html
new file mode 100644
index 0000000000..8e5bdcb9c6
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_CryptoKey_insecure.sub.html
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<body>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+promise_test(async t => {
+ let nextMessageEvent = new Promise((resolve, reject) => {
+ window.addEventListener('message', e => resolve(e));
+ window.addEventListener('messageerror', e => resolve(e));
+ });
+ let w = window.open('https://{{hosts[][]}}:{{ports[https][0]}}/webmessaging/resources/post-cryptokey-to-opener.html');
+ try {
+ let event = await nextMessageEvent;
+ assert_equals(event.type, 'messageerror');
+ } finally {
+ w.close();
+ }
+}, "insecure context should not receive an object for secure contexts only");
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_Date.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_Date.sub.htm
new file mode 100644
index 0000000000..0f89738f3a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_Date.sub.htm
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with Date object </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: Messages can contain JavaScript values (e.g., Dates).";
+
+ var t = async_test(description);
+
+ var DATA = new Date();
+ var TYPE = "object";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, "*");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(typeof(e.data), TYPE);
+ assert_equals(e.data.valueOf(), DATA.valueOf());
+ assert_not_equals(e.data, DATA, "Object is cloned");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_Document.htm b/testing/web-platform/tests/webmessaging/postMessage_Document.htm
new file mode 100644
index 0000000000..c00a09a865
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_Document.htm
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with Document object </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "postMessage with Document object: Throw a DataCloneError if message could not be cloned.";
+
+ var DATA = document;
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_throws_dom("DATA_CLONE_ERR", TARGET.contentWindow.DOMException, function()
+ {
+ TARGET.contentWindow.postMessage(DATA, "*");
+ });
+ }, description);
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_Function.htm b/testing/web-platform/tests/webmessaging/postMessage_Function.htm
new file mode 100644
index 0000000000..3976cebb74
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_Function.htm
@@ -0,0 +1,36 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with Function object </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "postMessage with Function object: Throw a DataCloneError if message could not be cloned.";
+
+ var DATA = new Function();
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_throws_dom("DATA_CLONE_ERR", TARGET.contentWindow.DOMException, function()
+ {
+ TARGET.contentWindow.postMessage(DATA, "*");
+ });
+ }, description);
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_sorigin.htm b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_sorigin.htm
new file mode 100644
index 0000000000..6526e972c4
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_sorigin.htm
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage to same-origin iframe with MessagePort array [100 ports] </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: postMessage to same-origin iframe with MessagePort array containing 100 ports.";
+
+ var t = async_test(description);
+
+ var TOTALPORTS = 100;
+ var LocalPorts = [];
+ var RemotePorts = [];
+ var PassedResult = 0;
+ var sum = 0;
+ var TARGET = document.querySelector("iframe").contentWindow;
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_own_property(window, "MessageChannel", "window");
+
+ var channels = [];
+
+ for (var i=0; i<TOTALPORTS; i++)
+ {
+ channels[i] = new MessageChannel();
+ LocalPorts[i] = channels[i].port1;
+ LocalPorts[i].foo = i;
+ RemotePorts[i] = channels[i].port2;
+
+ LocalPorts[i].onmessage = t.step_func(function(e)
+ {
+ assert_equals(e.target.foo, e.data);
+
+ PassedResult++;
+ sum += e.data;
+
+ if (PassedResult == TOTALPORTS)
+ {
+ assert_equals(sum, 4950);
+ t.done();
+ }
+ });
+ }
+
+ TARGET.postMessage("ports", "*", RemotePorts);
+
+ }, "MessageChannel is supported.");
+ }
+
+ window.onmessage = function(e)
+ {
+ if (e.data === "ports")
+ {
+ for (var i=0; i<TOTALPORTS; i++)
+ {
+ LocalPorts[i].postMessage(LocalPorts[i].foo);
+ }
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xorigin.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xorigin.sub.htm
new file mode 100644
index 0000000000..cf2b8eb4c1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xorigin.sub.htm
@@ -0,0 +1,76 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage to cross-origin iframe with MessagePort array [100 ports] </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: postMessage to cross-origin iframe with MessagePort array containing 100 ports.";
+
+ var t = async_test(description);
+
+ var TOTALPORTS = 100;
+ var LocalPorts = [];
+ var RemotePorts = [];
+ var PassedResult = 0;
+ var sum = 0;
+ var TARGET = document.querySelector("iframe").contentWindow;
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_own_property(window, "MessageChannel", "window");
+
+ var channels = [];
+
+ for (var i=0; i<TOTALPORTS; i++)
+ {
+ channels[i] = new MessageChannel();
+ LocalPorts[i] = channels[i].port1;
+ LocalPorts[i].foo = i;
+ RemotePorts[i] = channels[i].port2;
+
+ LocalPorts[i].onmessage = t.step_func(function(e)
+ {
+ assert_equals(e.target.foo, e.data);
+
+ PassedResult++;
+ sum += e.data;
+
+ if (PassedResult == TOTALPORTS)
+ {
+ assert_equals(sum, 4950);
+ t.done();
+ }
+ });
+ }
+
+ TARGET.postMessage("ports", "*", RemotePorts);
+
+ }, "MessageChannel is supported.");
+ }
+
+ window.onmessage = function(e)
+ {
+ if (e.data === "ports")
+ {
+ for (var i=0; i<TOTALPORTS; i++)
+ {
+ LocalPorts[i].postMessage(LocalPorts[i].foo);
+ }
+ }
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xsite.sub.window.js b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xsite.sub.window.js
new file mode 100644
index 0000000000..ca1e510eda
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_MessagePorts_xsite.sub.window.js
@@ -0,0 +1,66 @@
+// META: script=/common/get-host-info.sub.js
+
+async_test(function(t) {
+ var host = get_host_info();
+ var noteSameSiteURL = host.HTTP_NOTSAMESITE_ORIGIN + "/webmessaging/support/ChildWindowPostMessage.htm";
+ var TOTALPORTS = 100;
+ var LocalPorts = [];
+ var RemotePorts = [];
+ var PassedResult = 0;
+ var sum = 0;
+ let iframe = document.createElement('iframe');
+ iframe.src = noteSameSiteURL;
+ document.body.appendChild(iframe);
+ var TARGET = document.querySelector("iframe").contentWindow;
+ iframe.onload = t.step_func(function() {
+ assert_own_property(window, "MessageChannel", "window");
+
+ var channels = [];
+
+ for (var i=0; i<TOTALPORTS; i++)
+ {
+ channels[i] = new MessageChannel();
+ LocalPorts[i] = channels[i].port1;
+ LocalPorts[i].foo = i;
+ RemotePorts[i] = channels[i].port2;
+
+ LocalPorts[i].onmessage = t.step_func(function(e)
+ {
+ assert_equals(e.target.foo, e.data);
+
+ PassedResult++;
+ sum += e.data;
+
+ if (PassedResult == TOTALPORTS)
+ {
+ assert_equals(sum, 4950);
+ t.done();
+ }
+ });
+ }
+ // Sending in two batches, to test the two postMessage variants.
+ var firstBatch = RemotePorts.slice(0, 50);
+ var secondBatch = RemotePorts.slice(50, 100);
+ TARGET.postMessage("ports", "*", firstBatch);
+ TARGET.postMessage("ports", {targetOrigin: '*', transfer: secondBatch});
+ });
+ var counter = 0;
+ window.onmessage = function(e)
+ {
+ if (e.data === "ports")
+ {
+ if (counter == 0) {
+ for (var i=0; i<51; i++)
+ {
+ LocalPorts[i].postMessage(LocalPorts[i].foo);
+ }
+ counter = 1;
+ } else {
+ for (var i=51; i<100; i++)
+ {
+ LocalPorts[i].postMessage(LocalPorts[i].foo);
+ }
+ }
+ }
+ }
+}, "Test Description: postMessage to cross-site iframe with MessagePort array containing 100 ports.");
diff --git a/testing/web-platform/tests/webmessaging/postMessage_arrays.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_arrays.sub.htm
new file mode 100644
index 0000000000..41e4a75eda
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_arrays.sub.htm
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with arrays </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: Messages can be structured objects, e.g., arrays.";
+
+ var t = async_test(description);
+
+ var DATA = [1,2,3,4,5,6,7,8];
+ var TYPE = "object";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, "*");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(typeof(e.data), TYPE);
+ assert_array_equals(e.data, DATA);
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_asterisk_xorigin.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_asterisk_xorigin.sub.htm
new file mode 100644
index 0000000000..2fab9431ef
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_asterisk_xorigin.sub.htm
@@ -0,0 +1,52 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Cross-origin postMessage with targetOrigin == "*" </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<script>
+
+
+ var description = "Test Description: To send the message to the target regardless of origin, set the target origin to '*'.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var XORIGIN = "{{location[scheme]}}://{{domains[www]}}" + PORT;
+ var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT;
+ var ExpectedResult = ["#1", XORIGIN, "#2", SORIGIN];
+ var ActualResult = [];
+
+ window.onmessage = t.step_func(function(e)
+ {
+ // Messages from TARGET1 and TARGET2 can come in any order
+ // (since one of them is cross-origin and can run in parallel).
+ // To make the tests immune to message reordering, always
+ // put the response from TARGET1 at the start of the list.
+ if (e.data.toString() === "#1")
+ {
+ ActualResult = [e.data, e.origin].concat(ActualResult);
+ }
+ else if (e.data.toString() === "#2")
+ {
+ ActualResult = ActualResult.concat([e.data, e.origin]);
+ }
+
+ if (ActualResult.length >= ExpectedResult.length)
+ {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ });
+</script>
+
+<div style="display:none">
+ <iframe width="70%" onload="this.contentWindow.postMessage('#1', '*')" src="{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+ <iframe width="70%" onload="this.contentWindow.postMessage('#2', '*')" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_cross_domain_image_transfer_2d.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_cross_domain_image_transfer_2d.sub.htm
new file mode 100644
index 0000000000..4faf979274
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_cross_domain_image_transfer_2d.sub.htm
@@ -0,0 +1,34 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="/common/get-host-info.sub.js"></script>
+<body>
+<script>
+// Create a 2D canvas filled in solid gray.
+var size = 4;
+var sourceCanvas = document.createElement('canvas');
+sourceCanvas.width = sourceCanvas.height = size;
+var ctx = sourceCanvas.getContext('2d');
+ctx.fillStyle = "gray";
+ctx.fillRect(0, 0, size, size);
+const expectedPixels = "{\"0\":128,\"1\":128,\"2\":128,\"3\":255,\"4\":128,\"5\":128,\"6\":128,\"7\":255,\"8\":128,\"9\":128,\"10\":128,\"11\":255,\"12\":128,\"13\":128,\"14\":128,\"15\":255,\"16\":128,\"17\":128,\"18\":128,\"19\":255,\"20\":128,\"21\":128,\"22\":128,\"23\":255,\"24\":128,\"25\":128,\"26\":128,\"27\":255,\"28\":128,\"29\":128,\"30\":128,\"31\":255,\"32\":128,\"33\":128,\"34\":128,\"35\":255,\"36\":128,\"37\":128,\"38\":128,\"39\":255,\"40\":128,\"41\":128,\"42\":128,\"43\":255,\"44\":128,\"45\":128,\"46\":128,\"47\":255,\"48\":128,\"49\":128,\"50\":128,\"51\":255,\"52\":128,\"53\":128,\"54\":128,\"55\":255,\"56\":128,\"57\":128,\"58\":128,\"59\":255,\"60\":128,\"61\":128,\"62\":128,\"63\":255}";
+
+const {ORIGIN, REMOTE_ORIGIN, HTTP_NOTSAMESITE_ORIGIN} = get_host_info();
+for (let origin of [ORIGIN, REMOTE_ORIGIN, HTTP_NOTSAMESITE_ORIGIN]) {
+ promise_test(async t => {
+ let imageBitmap = await createImageBitmap(sourceCanvas);
+
+ let frame = document.createElement('iframe');
+ frame.src = origin + '/webmessaging/support/cross-domain-image-receive.htm';
+ document.body.appendChild(frame);
+ await new Promise(resolve => { frame.onload = e => resolve(); });
+
+ frame.contentWindow.postMessage({image: imageBitmap}, "*", [imageBitmap]);
+ let reply = await new Promise(resolve => {
+ window.addEventListener('message', e => resolve(e.data), {once: true});
+ });
+ assert_equals(reply, expectedPixels);
+ }, `sending 2D canvas ImageBitmap to ${origin}`);
+}
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_crosssite.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_crosssite.sub.htm
new file mode 100644
index 0000000000..25bccd9df2
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_crosssite.sub.htm
@@ -0,0 +1,29 @@
+<!DOCTYPE html>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<body>
+<script>
+async function addIframeAndReceiveMessage(path) {
+ let url = new URL('resources/transfer-arraybuffer-to-parent.html', location);
+ url.hostname = '{{hosts[alt][]}}';
+
+ let frame = document.createElement('iframe');
+ try {
+ frame.src = url;
+ document.body.appendChild(frame);
+ return await new Promise((resolve, reject) => {
+ window.addEventListener('message', e => resolve(e));
+ window.addEventListener('messageerror', e => reject(new Error('received messageerror')));
+ });
+ } finally {
+ frame.remove();
+ }
+}
+
+promise_test(async () => {
+ let messageEvent = await addIframeAndReceiveMessage('resources/transfer-arraybuffer-to-parent.html');
+ assert_class_string(messageEvent.data, 'ArrayBuffer');
+ assert_array_equals(new Uint8Array(messageEvent.data), [42, 222]);
+}, "cross-site windows can send transferred ArrayBuffer");
+</script>
+</body>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_dup_transfer_objects.htm b/testing/web-platform/tests/webmessaging/postMessage_dup_transfer_objects.htm
new file mode 100644
index 0000000000..ade9515d3a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_dup_transfer_objects.htm
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with duplicate transfer objects raises DataCloneError exception </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "postMessage with duplicate transfer objects raises DataCloneError exception.";
+
+ var DATA = "ports";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_throws_dom("DATA_CLONE_ERR", TARGET.contentWindow.DOMException, function()
+ {
+ assert_own_property(window, "MessageChannel", "window");
+ var channel = new MessageChannel();
+ TARGET.contentWindow.postMessage(DATA, "*", [channel.port1, channel.port1]);
+ });
+ }, description);
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_invalid_targetOrigin.htm b/testing/web-platform/tests/webmessaging/postMessage_invalid_targetOrigin.htm
new file mode 100644
index 0000000000..e2b39df22d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_invalid_targetOrigin.htm
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with invalid targetOrigin raises SyntaxError exception </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "If the value of the targetOrigin argument is neither a single U+002A ASTERISK character (*), " +
+ "a single U+002F SOLIDUS character (/), nor an absolute URL, then throw a SyntaxError exception " +
+ "and abort the overall set of steps.";
+
+ var DATA = "InvalidOrigin";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ test(function()
+ {
+ assert_throws_dom("SYNTAX_ERR", TARGET.contentWindow.DOMException, function()
+ {
+ TARGET.contentWindow.postMessage(DATA, DATA);
+ });
+ }, description);
+ }
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_objects.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_objects.sub.htm
new file mode 100644
index 0000000000..dab207188a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_objects.sub.htm
@@ -0,0 +1,40 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> postMessage with nested objects </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: Messages can be structured objects, e.g., nested objects.";
+
+ var t = async_test(description);
+
+ var DATA = {foo: {bar: "wow"}};
+ var TYPE = "object";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, "*");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(typeof(e.data), TYPE);
+ assert_equals(typeof(e.data.foo), TYPE);
+ assert_object_equals(e.data, DATA);
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch.sub.htm
new file mode 100644
index 0000000000..6c8ac8353a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch.sub.htm
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Same-origin: Origin of the target window doesn't match the given origin </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "Same-origin: If the origin of the target window doesn't match the given origin, " +
+ "the message is discarded.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var TARGET = document.querySelector("iframe");
+ var XORIGIN = "{{location[scheme]}}://{{domains[www1]}}" + PORT;
+ var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT;
+ var ExpectedResult = ["#0", SORIGIN, "#3", SORIGIN];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage("#0", SORIGIN);
+ TARGET.contentWindow.postMessage("#1", "http://www.invalid-domain.com");
+ TARGET.contentWindow.postMessage("#2", XORIGIN);
+ TARGET.contentWindow.postMessage("#3", "*");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ ActualResult.push(e.data, e.origin);
+
+ if (ActualResult.length >= ExpectedResult.length)
+ {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch_xorigin.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch_xorigin.sub.htm
new file mode 100644
index 0000000000..d8e38e2919
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_origin_mismatch_xorigin.sub.htm
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Cross-origin: Origin of the target window doesn't match the given origin </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "Cross-origin: If the origin of the target window doesn't match the given origin, " +
+ "the message is discarded.";
+
+ var t = async_test(description);
+
+ var PORT = location.port !== "" ? ":" + location.port : "";
+ var TARGET = document.querySelector("iframe");
+ var XORIGIN = "{{location[scheme]}}://{{domains[www1]}}" + PORT;
+ var SORIGIN = "{{location[scheme]}}://{{host}}" + PORT;
+ var ExpectedResult = ["#0", XORIGIN, "#3", XORIGIN];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage("#0", XORIGIN);
+ TARGET.contentWindow.postMessage("#1", "http://www.invalid-domain.com");
+ TARGET.contentWindow.postMessage("#2", SORIGIN);
+ TARGET.contentWindow.postMessage("#3", "*");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ ActualResult.push(e.data, e.origin);
+
+ if (ActualResult.length >= ExpectedResult.length)
+ {
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ }
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_solidus_sorigin.htm b/testing/web-platform/tests/webmessaging/postMessage_solidus_sorigin.htm
new file mode 100644
index 0000000000..92f5afb798
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_solidus_sorigin.htm
@@ -0,0 +1,43 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Same-origin postMessage with targetOrigin == "/" </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="./support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "To restrict the message to same-origin targets only, without needing to explicitly " +
+ "state the origin, set the target origin to '/'.";
+
+ var t = async_test(description);
+
+ var DATA = "/";
+ var TARGET = document.querySelector("iframe");
+ var SORIGIN = location.protocol + "//" + location.host;
+ var ExpectedResult = [DATA, SORIGIN];
+ var ActualResult = [];
+
+ function PostMessageTest()
+ {
+ TARGET.contentWindow.postMessage(DATA, "/");
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ ActualResult.push(e.data, e.origin);
+ assert_array_equals(ActualResult, ExpectedResult, "ActualResult");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/postMessage_solidus_xorigin.sub.htm b/testing/web-platform/tests/webmessaging/postMessage_solidus_xorigin.sub.htm
new file mode 100644
index 0000000000..eebc85432f
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/postMessage_solidus_xorigin.sub.htm
@@ -0,0 +1,48 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title> Cross-origin postMessage with targetOrigin == "/" </title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+</head>
+<body>
+<div id=log></div>
+
+<div style="display:none">
+ <iframe width="70%" onload="PostMessageTest()" src="{{location[scheme]}}://{{domains[www1]}}:{{location[port]}}/webmessaging/support/ChildWindowPostMessage.htm"></iframe>
+</div>
+
+<script>
+
+
+ var description = "Test Description: " +
+ "If the targetOrigin argument is a single literal U+002F SOLIDUS character (/), and " +
+ "the Document of the Window object on which the method was invoked does not have the " +
+ "same origin as the entry script's document, then abort these steps silently.";
+
+ var t = async_test(description);
+
+ var DATA = "NoExceptionRaised";
+ var TARGET = document.querySelector("iframe");
+
+ function PostMessageTest()
+ {
+ try
+ {
+ TARGET.contentWindow.postMessage("/", "/");
+ TARGET.contentWindow.postMessage(DATA, "*");
+ }
+ catch(ex)
+ {
+ TARGET.contentWindow.postMessage("ExceptionRaised", "*");
+ }
+ }
+
+ window.onmessage = t.step_func(function(e)
+ {
+ assert_equals(e.data, DATA, "e.data");
+ t.done();
+ });
+</script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/resources/post-cryptokey-to-opener.html b/testing/web-platform/tests/webmessaging/resources/post-cryptokey-to-opener.html
new file mode 100644
index 0000000000..91c70165f0
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/resources/post-cryptokey-to-opener.html
@@ -0,0 +1,6 @@
+<!DOCTYPE html>
+<script>
+crypto.subtle.generateKey({name: 'AES-CBC', length: 128}, false, ['encrypt', 'decrypt'])
+.then(key => opener.postMessage({key}, '*'))
+.catch(error => opener.postMessage({error: error.toString()}, '*'));
+</script>
diff --git a/testing/web-platform/tests/webmessaging/resources/transfer-arraybuffer-to-parent.html b/testing/web-platform/tests/webmessaging/resources/transfer-arraybuffer-to-parent.html
new file mode 100644
index 0000000000..97cff4dcb3
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/resources/transfer-arraybuffer-to-parent.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<script>
+let ab = new Uint8Array([42, 222]).buffer;
+window.parent.postMessage(ab, '*', [ab]);
+</script>
diff --git a/testing/web-platform/tests/webmessaging/support/ChildWindowPostMessage.htm b/testing/web-platform/tests/webmessaging/support/ChildWindowPostMessage.htm
new file mode 100644
index 0000000000..13d4103a82
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/support/ChildWindowPostMessage.htm
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title> Child window for Web Messaging tests </title>
+</head>
+<body>
+ <script>
+ if (window.opener)
+ {
+ window.onload = function()
+ {
+ try
+ {
+ window.opener.postMessage("MSG_ONLOAD_FIRED", "*");
+ }
+ catch(ex)
+ {
+ window.close();
+ }
+ }
+ }
+
+ window.onmessage = function(e)
+ {
+ try
+ {
+ if (typeof(e.data) == "object" && typeof(e.data.test) == "string")
+ {
+ eval(e.data.test);
+ }
+ else if (e.data == "*" || e.data == "/")
+ {
+ e.source.postMessage(e.data, e.data);
+ }
+ else
+ {
+ e.source.postMessage(e.data, e.origin);
+ }
+
+ if (e.data == "ports")
+ {
+ var total = e.ports.length;
+ for (var i=0; i<total; i++)
+ {
+ e.ports[i].onmessage = function (evt)
+ {
+ evt.target.postMessage(evt.data);
+ }
+ }
+ }
+ }
+ catch(ex)
+ {
+ }
+ }
+ </script>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/support/MessageEvent-trusted-worker.js b/testing/web-platform/tests/webmessaging/support/MessageEvent-trusted-worker.js
new file mode 100644
index 0000000000..6e8c3a781b
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/support/MessageEvent-trusted-worker.js
@@ -0,0 +1,4 @@
+"use strict";
+
+const channel = new BroadcastChannel("channel name");
+channel.postMessage("ping");
diff --git a/testing/web-platform/tests/webmessaging/support/compare.js b/testing/web-platform/tests/webmessaging/support/compare.js
new file mode 100644
index 0000000000..5341b37438
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/support/compare.js
@@ -0,0 +1,39 @@
+function sameDate(d1, d2) {
+ return (d1 instanceof Date && d2 instanceof Date && d1.valueOf() == d2.valueOf());
+}
+
+function sameRE(r1, r2) {
+ return (r1 instanceof RegExp && r2 instanceof RegExp && r1.toString() == r2.toString());
+}
+
+function assert_array_equals_(observed, expected, msg) {
+ if (observed.length == expected.length) {
+ for (var i = 0; i < observed.length; i++) {
+ if (observed[i] instanceof Date) {
+ observed[i] = sameDate(observed[i], expected[i]);
+ expected[i] = true;
+ } else if (observed[i] instanceof RegExp) {
+ observed[i] = sameRE(observed[i], expected[i]);
+ expected[i] = true;
+ }
+ }
+ }
+
+ assert_array_equals(observed, expected, msg);
+}
+
+function assert_object_equals_(observed, expected, msg) {
+ for (var p in observed) {
+ if (observed[p] instanceof Date) {
+ observed[p] = sameDate(observed[p], expected[p]);
+ expected[p] = true;
+ } else if (observed[p] instanceof RegExp) {
+ observed[p] = sameRE(observed[p], expected[p]);
+ expected[p] = true;
+ } else if (observed[p] instanceof Array || String(observed[p]) === '[object Object]') {
+ observed[p] = String(observed[p]) === String(expected[p]);
+ expected[p] = true;
+ }
+ assert_equals(observed[p], expected[p], msg);
+ }
+}
diff --git a/testing/web-platform/tests/webmessaging/support/cross-domain-image-receive.htm b/testing/web-platform/tests/webmessaging/support/cross-domain-image-receive.htm
new file mode 100644
index 0000000000..253b34bd76
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/support/cross-domain-image-receive.htm
@@ -0,0 +1,25 @@
+<!DOCTYPE html>
+
+<html lang="en">
+<head>
+ <title>Cross-Domain image transfer test</title>
+</head>
+<script type="text/javascript" charset="utf-8">
+
+function receiver(e) {
+ var dstCanvas = document.createElement('canvas');
+ dstCanvas.width = e.data.image.width
+ dstCanvas.height = e.data.image.height
+ var dstCtx = dstCanvas.getContext('2d');
+ dstCtx.drawImage(e.data.image, 0, 0)
+ var imgData = dstCtx.getImageData(0, 0, dstCanvas.height, dstCanvas.width);
+
+ result = JSON.stringify(imgData.data);
+ e.source.postMessage(result, "*");
+}
+
+addEventListener('message', receiver, false);
+</script>
+<body>
+</body>
+</html>
diff --git a/testing/web-platform/tests/webmessaging/with-options/broken-origin.html b/testing/web-platform/tests/webmessaging/with-options/broken-origin.html
new file mode 100644
index 0000000000..795404b0ec
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/broken-origin.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving broken url</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom('SYNTAX_ERR', function() {
+ postMessage('', {targetOrigin: 'http://foo bar'});
+ }, 'should have failed to resolve');
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/host-specific-origin.html b/testing/web-platform/tests/webmessaging/with-options/host-specific-origin.html
new file mode 100644
index 0000000000..5003bcc807
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/host-specific-origin.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving url with stuff in host-specific</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', {targetOrigin: location.protocol + '//' + location.host + '//'});
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/message-channel-transferable.html b/testing/web-platform/tests/webmessaging/with-options/message-channel-transferable.html
new file mode 100644
index 0000000000..d42db10695
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/message-channel-transferable.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>message channel as ports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var channel = new MessageChannel();
+ postMessage('', {targetOrigin: '*', transfer: [channel.port1, channel.port2]});
+ onmessage = t.step_func(function(e) {
+ assert_equals(e.ports.length, 2);
+ t.done();
+ });
+}, "MessageChannel's ports as MessagePort objects");
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/no-target-origin.html b/testing/web-platform/tests/webmessaging/with-options/no-target-origin.html
new file mode 100644
index 0000000000..517466cc4c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/no-target-origin.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>no targetOrigin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', {});
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/null-transfer.html b/testing/web-platform/tests/webmessaging/with-options/null-transfer.html
new file mode 100644
index 0000000000..2ea09eb7ab
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/null-transfer.html
@@ -0,0 +1,10 @@
+<!doctype html>
+<title>null transfer</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function(t) {
+ assert_throws_js(TypeError, () => postMessage('', {transfer: null}));
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/one-arg.html b/testing/web-platform/tests/webmessaging/with-options/one-arg.html
new file mode 100644
index 0000000000..8246e55f31
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/one-arg.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>just one argument</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(t => {
+ postMessage('');
+ onmessage = t.step_func_done(e => {
+ assert_equals(e.data, '');
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/slash-origin.html b/testing/web-platform/tests/webmessaging/with-options/slash-origin.html
new file mode 100644
index 0000000000..8bfde73774
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/slash-origin.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>special value '/'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', {targetOrigin: '/'});
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/undefined-transferable.html b/testing/web-platform/tests/webmessaging/with-options/undefined-transferable.html
new file mode 100644
index 0000000000..a123b7d9bd
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/undefined-transferable.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>undefined as transferable</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ postMessage('', {transfer: undefined});
+ onmessage = this.step_func(function(e) {
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-options/unknown-parameter.html b/testing/web-platform/tests/webmessaging/with-options/unknown-parameter.html
new file mode 100644
index 0000000000..de050e74f5
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-options/unknown-parameter.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>unknown parameter</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', {someBogusParameterOnThisDictionary: 'food'});
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/001.html b/testing/web-platform/tests/webmessaging/with-ports/001.html
new file mode 100644
index 0000000000..62dcf5e9bf
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/001.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving broken url</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom('SYNTAX_ERR', function() {
+ postMessage('', 'http://foo bar', []);
+ }, 'should have failed to resolve');
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/002.html b/testing/web-platform/tests/webmessaging/with-ports/002.html
new file mode 100644
index 0000000000..f7d085937c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/002.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving url with stuff in host-specific</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host + '//', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/003.html b/testing/web-platform/tests/webmessaging/with-ports/003.html
new file mode 100644
index 0000000000..47ddfbe81a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/003.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving 'example.org'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom('SYNTAX_ERR', function() {
+ postMessage('', 'example.org', []);
+ }, 'targetOrigin is not an absolute url');
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/004.html b/testing/web-platform/tests/webmessaging/with-ports/004.html
new file mode 100644
index 0000000000..d129ad119a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/004.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>special value '/'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', '/', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/005.html b/testing/web-platform/tests/webmessaging/with-ports/005.html
new file mode 100644
index 0000000000..e803968919
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/005.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving a same origin targetOrigin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host, []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/006.html b/testing/web-platform/tests/webmessaging/with-ports/006.html
new file mode 100644
index 0000000000..4e3f1ede84
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/006.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving a same origin targetOrigin with trailing slash</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host + '/', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/007.html b/testing/web-platform/tests/webmessaging/with-ports/007.html
new file mode 100644
index 0000000000..c049a1337d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/007.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>targetOrigin '*'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', '*', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/010.html b/testing/web-platform/tests/webmessaging/with-ports/010.html
new file mode 100644
index 0000000000..05080e3f7a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/010.html
@@ -0,0 +1,113 @@
+<!doctype html>
+<title>message clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/compare.js"></script>
+<div id=log></div>
+<script>
+ var err = new Error('foo');
+ var date = new Date();
+
+ var test_array = [ undefined,
+ null,
+ false,
+ true,
+ 1,
+ NaN,
+ Infinity,
+ 'foo',
+ date,
+ /foo/,
+ null/*self*/,
+ null/*err*/];
+
+ var cloned_array = [ undefined,
+ null,
+ false,
+ true,
+ 1,
+ NaN,
+ Infinity,
+ 'foo',
+ date,
+ /foo/,
+ null/*self*/,
+ null/*err*/];
+
+ var test_object = {a: undefined,
+ b: null,
+ c: false,
+ d: true,
+ e: 1,
+ f: NaN,
+ g: Infinity,
+ h: 'foo',
+ i: date,
+ j: /foo/,
+ k: null/*self*/,
+ l: [],
+ m: {},
+ n: null /*err*/};
+
+ var cloned_object = {a:undefined, b:null, c:false, d:true, e:1, f:NaN, g:Infinity, h:'foo', i: date, j: /foo/, k:null, l: [], m: {}, n:null};
+
+ var tests = [undefined, null,
+ false, true,
+ 1, NaN, Infinity,
+ 'foo',
+ date,
+ /foo/,
+ /* ImageData, File, FileData, FileList, */
+ null /*self*/,
+ test_array,
+ test_object,
+ null /*err*/];
+
+ for (var i = 0; i < tests.length; ++i) {
+ postMessage(tests[i], '*', []);
+ }
+
+ var test_undefined = async_test('undefined');
+ var test_null = async_test('null');
+ var test_false = async_test('false');
+ var test_true = async_test('true');
+ var test_1 = async_test('1');
+ var test_NaN = async_test('NaN');
+ var test_Infinity = async_test('Infinity');
+ var test_string = async_test('string');
+ var test_date = async_test('date');
+ var test_regex = async_test('regex');
+ var test_self = async_test('self');
+ var test_array = async_test('array');
+ var test_object = async_test('object');
+ var test_error = async_test('error');
+ var test_unreached = async_test('unreached');
+
+ var j = 0;
+ onmessage = function(e) {
+ switch (j) {
+ case 0: test_undefined.step(function() { assert_equals(e.data, undefined); this.done(); }); break;
+ case 1: test_null.step(function() { assert_equals(e.data, null); this.done(); }); break;
+ case 2: test_false.step(function() { assert_false(e.data); this.done(); }); break;
+ case 3: test_true.step(function() { assert_true(e.data); this.done(); }); break;
+ case 4: test_1.step(function() { assert_equals(e.data, 1); this.done(); }); break;
+ case 5: test_NaN.step(function() { assert_equals(e.data, NaN); this.done(); }); break;
+ case 6: test_Infinity.step(function() { assert_equals(e.data, Infinity); this.done(); }); break;
+ case 7: test_string.step(function() { assert_equals(e.data, 'foo'); this.done(); }); break;
+ case 8: test_date.step(function() { assert_true(sameDate(e.data, date)); this.done(); }); break;
+ case 9: test_regex.step(function() { assert_equals('' + e.data, '/foo/'); assert_equals(e.data instanceof RegExp, true, 'e.data instanceof RegExp'); this.done(); }); break;
+ // not testing it any more, as cloning host objects will now raise exceptions. TODO: add (exceptional) tests for these.
+ case 10: test_self.step(function() { assert_equals(e.data, null); this.done(); }); break;
+ case 11: test_array.step(function() { assert_array_equals_(e.data, cloned_array, 'array'); this.done(); }); break;
+ case 12: test_object.step(function() { assert_object_equals_(e.data, cloned_object, 'object'); this.done(); }); break;
+ case 13:
+ test_error.step(function() { assert_equals(e.data, null, 'new Error()'); this.done(); });
+ setTimeout(test_unreached.step_func(function() { assert_equals(j, 14); this.done(); }), 50);
+ break;
+ default: test_unreached.step(function() { assert_unreached('got an unexpected message event ('+j+')'); });
+ };
+ j++;
+ }
+
+
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/011.html b/testing/web-platform/tests/webmessaging/with-ports/011.html
new file mode 100644
index 0000000000..782b3208ba
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/011.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>posting an imagedata (from a cloned canvas) in an array</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+
+ var canvas = document.createElement('canvas');
+ var clone = canvas.cloneNode(true);
+ var ctx = clone.getContext('2d');
+ var imagedata = ctx.getImageData(0, 0, 300, 150);
+ postMessage([imagedata], '*', []);
+
+ onmessage = this.step_func(function(e) {
+ function processPixels(imagedata) {
+ var pixeldata = imagedata.data;
+ for (var i = 0; i < pixeldata.length; i = i+4) {
+ pixeldata[i] = 128;
+ assert_equals(pixeldata[i], 128);
+ }
+ }
+ processPixels(e.data[0]);
+ this.done();
+ });
+
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/012.html b/testing/web-platform/tests/webmessaging/with-ports/012.html
new file mode 100644
index 0000000000..6efe4c114a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/012.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>loop in array in structured clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var x = [];
+ x[0] = x;
+ postMessage(x, '*', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, e.data[0]);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/013.html b/testing/web-platform/tests/webmessaging/with-ports/013.html
new file mode 100644
index 0000000000..248958ea10
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/013.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>loop in object in structured clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var x = {};
+ x.foo = x;
+ postMessage(x, '*', []);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, e.data.foo);
+ this.done();
+ });
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/014.html b/testing/web-platform/tests/webmessaging/with-ports/014.html
new file mode 100644
index 0000000000..3c970c42ad
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/014.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>structured clone vs reference</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function(t) {
+ var x = [];
+ y = [x,x];
+ postMessage(y, '*', []);
+ onmessage = t.step_func(function(e) {
+ assert_equals(e.data[0], e.data[1], 'e.data[0] === e.data[1]');
+ assert_not_equals(e.data[0], x, 'e.data[0] !== x');
+ t.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/with-ports/015.html b/testing/web-platform/tests/webmessaging/with-ports/015.html
new file mode 100644
index 0000000000..a17c97be19
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/015.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>different origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ postMessage('', 'http://example.org', []);
+ onmessage = this.step_func(function(e) {
+ assert_unreached();
+ });
+ setTimeout(this.step_func(function(){ this.done(); }), 50);
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/016.html b/testing/web-platform/tests/webmessaging/with-ports/016.html
new file mode 100644
index 0000000000..51cadec7c1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/016.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>origin of the script that invoked the method, data:</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="data:text/html,<script>onmessage = function(e) { parent.postMessage(e.origin, '*'); }; parent.postMessage('loaded', '*');</script>"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ onmessage = this.step_func(function(e) {
+ if (e.data === 'loaded') {
+ window[0].postMessage('', '*');
+ return;
+ }
+
+ assert_equals(e.data, location.protocol + '//' + location.host);
+ assert_equals(e.origin, 'null');
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/017.html b/testing/web-platform/tests/webmessaging/with-ports/017.html
new file mode 100644
index 0000000000..94cd3e6ae2
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/017.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>origin of the script that invoked the method, about:blank</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="about:blank"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ window[0].postMessage('', '*', []);
+ window[0].onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/018.html b/testing/web-platform/tests/webmessaging/with-ports/018.html
new file mode 100644
index 0000000000..5525206e44
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/018.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>origin of the script that invoked the method, javascript:</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="javascript:''"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ window[0].postMessage('', '*', []);
+ window[0].onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/019.html b/testing/web-platform/tests/webmessaging/with-ports/019.html
new file mode 100644
index 0000000000..e9de6c36e1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/019.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>origin of the script that invoked the method, scheme/host/port</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/019-1.html"></iframe>
+<div id=log></div>
+<script>
+async_test(function(test) {
+ onload = test.step_func(function() {
+ window[0].postMessage('', location.protocol.toUpperCase() + '//' + location.host.toUpperCase() + '/', []);
+ window[0].onmessage = test.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ assert_array_equals(e.ports, []);
+ test.done();
+ });
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/020.html b/testing/web-platform/tests/webmessaging/with-ports/020.html
new file mode 100644
index 0000000000..426a3d2700
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/020.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>cross-origin test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/020-1.html"></iframe>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var iframe = document.createElement('iframe');
+var url_prefix = location.href.replace('://', '://www1.').replace(/\/with(out)?-ports\/[^\/]+$/, '');
+var url = url_prefix + '/without-ports/020-1.html';
+iframe.src = url;
+document.body.appendChild(iframe);
+</script>
+<div id=log></div>
+<script>
+onload = function() {
+ window[0].postMessage(1, location.href, []);
+ window[1].postMessage(2, url, []);
+ var i = 0;
+ onmessage = function(e) {
+ i++;
+ assert_equals(e.data[0], i);
+ assert_equals(e.data[1], location.protocol + '//' + location.host);
+ if (i === 2) {
+ done();
+ }
+ };
+};
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/021.html b/testing/web-platform/tests/webmessaging/with-ports/021.html
new file mode 100644
index 0000000000..2801d45a44
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/021.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>cross-origin test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/020-1.html"></iframe>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var iframe = document.createElement('iframe');
+var url_prefix = location.href.replace('://', '://www1.').replace(/\/with(out)?-ports\/[^\/]+$/, '');
+var url = url_prefix + '/without-ports/020-1.html';
+iframe.src = url;
+document.body.appendChild(iframe);
+</script>
+<div id=log></div>
+<script>
+onload = function() {
+ window[0].postMessage(1, '*', []);
+ window[1].postMessage(2, '*', []);
+ var i = 0;
+ onmessage = function(e) {
+ i++;
+ assert_equals(e.data[0], i);
+ assert_equals(e.data[1], location.protocol + '//' + location.host);
+ if (i === 2) {
+ done();
+ }
+ };
+};
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/023.html b/testing/web-platform/tests/webmessaging/with-ports/023.html
new file mode 100644
index 0000000000..e2569a8463
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/023.html
@@ -0,0 +1,11 @@
+<!doctype html>
+<title>null ports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function(t) {
+ assert_throws_js(TypeError, () => postMessage('', '*', null));
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/024.html b/testing/web-platform/tests/webmessaging/with-ports/024.html
new file mode 100644
index 0000000000..e6c0dcba08
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/024.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>undefined as ports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ postMessage('', '*', undefined);
+ onmessage = this.step_func(function(e) {
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/025.html b/testing/web-platform/tests/webmessaging/with-ports/025.html
new file mode 100644
index 0000000000..7af2a852ed
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/025.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>1 as ports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ assert_throws_js(TypeError, function() {
+ postMessage('', '*', 1);
+ });
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/026.html b/testing/web-platform/tests/webmessaging/with-ports/026.html
new file mode 100644
index 0000000000..2af90e6be3
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/026.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>object with length as transferable</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ assert_throws_js(TypeError, function() {
+ postMessage('', '*', {length:1});
+ });
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/with-ports/027.html b/testing/web-platform/tests/webmessaging/with-ports/027.html
new file mode 100644
index 0000000000..7158351258
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/with-ports/027.html
@@ -0,0 +1,26 @@
+<!doctype html>
+<title>message channel as ports</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function(t) {
+ var channel = new MessageChannel();
+ postMessage('', '*', [channel.port1, channel.port2]);
+ onmessage = t.step_func(function(e) {
+ assert_equals(e.ports.length, 2);
+ t.done();
+ });
+}, "MessageChannel's ports as MessagePort objects");
+
+test(() => {
+ var channel = new MessageChannel();
+ channel[0] = channel.port1;
+ channel[1] = channel.port2;
+ channel.length = 2;
+ assert_throws_js(TypeError,
+ () => { postMessage('', '*', channel) },
+ 'Old-style WebIDL arrays must throw a type error');
+}, "Old-style array objects");
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/001.html b/testing/web-platform/tests/webmessaging/without-ports/001.html
new file mode 100644
index 0000000000..09c28c5a5c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/001.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving broken url</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom('SYNTAX_ERR', function() {
+ postMessage('', 'http://foo bar');
+ }, 'should have failed to resolve');
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/002.html b/testing/web-platform/tests/webmessaging/without-ports/002.html
new file mode 100644
index 0000000000..ef3eceb2a0
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/002.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving url with stuff in host-specific</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host + '//');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/003.html b/testing/web-platform/tests/webmessaging/without-ports/003.html
new file mode 100644
index 0000000000..6dc1e55777
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/003.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>resolving 'example.org'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_dom('SYNTAX_ERR', function() {
+ postMessage('', 'example.org');
+ }, 'targetOrigin is not an absolute url');
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/004.html b/testing/web-platform/tests/webmessaging/without-ports/004.html
new file mode 100644
index 0000000000..9a9eb81a5d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/004.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>special value '/'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', '/');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/005.html b/testing/web-platform/tests/webmessaging/without-ports/005.html
new file mode 100644
index 0000000000..ed05a476bc
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/005.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving a same origin targetOrigin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host);
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/006.html b/testing/web-platform/tests/webmessaging/without-ports/006.html
new file mode 100644
index 0000000000..47479ea011
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/006.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>resolving a same origin targetOrigin with trailing slash</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', location.protocol + '//' + location.host + '/');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/007.html b/testing/web-platform/tests/webmessaging/without-ports/007.html
new file mode 100644
index 0000000000..eb2b5c52e5
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/007.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>targetOrigin '*'</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ postMessage('', '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, '');
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/009.html b/testing/web-platform/tests/webmessaging/without-ports/009.html
new file mode 100644
index 0000000000..d613b4a073
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/009.html
@@ -0,0 +1,12 @@
+<!doctype html>
+<title>zero arguments</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+test(function() {
+ assert_throws_js(TypeError, function() {
+ postMessage();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/010.html b/testing/web-platform/tests/webmessaging/without-ports/010.html
new file mode 100644
index 0000000000..062316f680
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/010.html
@@ -0,0 +1,112 @@
+<!doctype html>
+<title>message clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script src="../support/compare.js"></script>
+<div id=log></div>
+<script>
+ var err = new Error('foo');
+ var date = new Date();
+
+ var test_array = [ undefined,
+ null,
+ false,
+ true,
+ 1,
+ NaN,
+ Infinity,
+ 'foo',
+ date,
+ /foo/,
+ null/*self*/,
+ null/*err*/];
+
+ var cloned_array = [ undefined,
+ null,
+ false,
+ true,
+ 1,
+ NaN,
+ Infinity,
+ 'foo',
+ date,
+ /foo/,
+ null/*self*/,
+ null/*err*/];
+
+ var test_object = {a: undefined,
+ b: null,
+ c: false,
+ d: true,
+ e: 1,
+ f: NaN,
+ g: Infinity,
+ h: 'foo',
+ i: date,
+ j: /foo/,
+ k: null/*self*/,
+ l: [],
+ m: {},
+ n: null /*err*/};
+
+ var cloned_object = {a:undefined, b:null, c:false, d:true, e:1, f:NaN, g:Infinity, h:'foo', i: date, j: /foo/, k:null, l: [], m: {}, n:null};
+
+ var tests = [undefined, null,
+ false, true,
+ 1, NaN, Infinity,
+ 'foo',
+ date,
+ /foo/,
+ /* ImageData, File, FileData, FileList, */
+ null /*self*/,
+ test_array,
+ test_object,
+ null /*err*/];
+
+ for (var i = 0; i < tests.length; ++i) {
+ postMessage(tests[i], '*');
+ }
+
+ var test_undefined = async_test('undefined');
+ var test_null = async_test('null');
+ var test_false = async_test('false');
+ var test_true = async_test('true');
+ var test_1 = async_test('1');
+ var test_NaN = async_test('NaN');
+ var test_Infinity = async_test('Infinity');
+ var test_string = async_test('string');
+ var test_date = async_test('date');
+ var test_regex = async_test('regex');
+ var test_self = async_test('self');
+ var test_array = async_test('array');
+ var test_object = async_test('object');
+ var test_error = async_test('error');
+ var test_unreached = async_test('unreached');
+
+ var j = 0;
+ onmessage = function(e) {
+ switch (j) {
+ case 0: test_undefined.step(function() { assert_equals(e.data, undefined); this.done(); }); break;
+ case 1: test_null.step(function() { assert_equals(e.data, null); this.done(); }); break;
+ case 2: test_false.step(function() { assert_false(e.data); this.done(); }); break;
+ case 3: test_true.step(function() { assert_true(e.data); this.done(); }); break;
+ case 4: test_1.step(function() { assert_equals(e.data, 1); this.done(); }); break;
+ case 5: test_NaN.step(function() { assert_equals(e.data, NaN); this.done(); }); break;
+ case 6: test_Infinity.step(function() { assert_equals(e.data, Infinity); this.done(); }); break;
+ case 7: test_string.step(function() { assert_equals(e.data, 'foo'); this.done(); }); break;
+ case 8: test_date.step(function() { assert_true(sameDate(e.data, date)); this.done(); }); break;
+ case 9: test_regex.step(function() { assert_equals('' + e.data, '/foo/'); assert_equals(e.data instanceof RegExp, true, 'e.data instanceof RegExp'); this.done(); }); break;
+ // not testing it any more, as cloning host objects will now raise exceptions. TODO: add (exceptional) tests for these.
+ case 10: test_self.step(function() { assert_equals(e.data, null); this.done(); }); break;
+ case 11: test_array.step(function() { assert_array_equals_(e.data, cloned_array, 'array'); this.done(); }); break;
+ case 12: test_object.step(function() { assert_object_equals_(e.data, cloned_object, 'object'); this.done(); }); break;
+ case 13:
+ test_error.step(function() { assert_equals(e.data, null, 'new Error()'); this.done(); });
+ setTimeout(test_unreached.step_func(function() { assert_equals(j, 14); this.done(); }), 50);
+ break;
+ default: test_unreached.step(function() { assert_unreached('got an unexpected message event ('+j+')'); });
+ };
+ j++;
+ }
+
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/011.html b/testing/web-platform/tests/webmessaging/without-ports/011.html
new file mode 100644
index 0000000000..cac2990c49
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/011.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>posting an imagedata (from a cloned canvas) in an array</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+
+ var canvas = document.createElement('canvas');
+ var clone = canvas.cloneNode(true);
+ var ctx = clone.getContext('2d');
+ var imagedata = ctx.getImageData(0, 0, 300, 150);
+ postMessage([imagedata], '*');
+
+ onmessage = this.step_func(function(e) {
+ function processPixels(imagedata) {
+ var pixeldata = imagedata.data;
+ for (var i = 0; i < pixeldata.length; i = i+4) {
+ pixeldata[i] = 128;
+ assert_equals(pixeldata[i], 128);
+ }
+ }
+ processPixels(e.data[0]);
+ this.done();
+ });
+
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/012.html b/testing/web-platform/tests/webmessaging/without-ports/012.html
new file mode 100644
index 0000000000..8eb46539b7
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/012.html
@@ -0,0 +1,16 @@
+<!doctype html>
+<title>loop in array in structured clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var x = [];
+ x[0] = x;
+ postMessage(x, '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, e.data[0]);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/013.html b/testing/web-platform/tests/webmessaging/without-ports/013.html
new file mode 100644
index 0000000000..34ba76221a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/013.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>loop in object in structured clone</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function() {
+ var x = {};
+ x.foo = x;
+ postMessage(x, '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data, e.data.foo);
+ this.done();
+ });
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/014.html b/testing/web-platform/tests/webmessaging/without-ports/014.html
new file mode 100644
index 0000000000..f200aa4673
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/014.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>structured clone vs reference</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+async_test(function(t) {
+ var x = [];
+ y = [x,x];
+ postMessage(y, '*');
+ onmessage = t.step_func(function(e) {
+ assert_equals(e.data[0], e.data[1], 'e.data[0] === e.data[1]');
+ assert_not_equals(e.data[0], x, 'e.data[0] !== x');
+ t.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/015.html b/testing/web-platform/tests/webmessaging/without-ports/015.html
new file mode 100644
index 0000000000..a17c97be19
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/015.html
@@ -0,0 +1,15 @@
+<!doctype html>
+<title>different origin</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ postMessage('', 'http://example.org', []);
+ onmessage = this.step_func(function(e) {
+ assert_unreached();
+ });
+ setTimeout(this.step_func(function(){ this.done(); }), 50);
+});
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/016.html b/testing/web-platform/tests/webmessaging/without-ports/016.html
new file mode 100644
index 0000000000..51cadec7c1
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/016.html
@@ -0,0 +1,23 @@
+<!doctype html>
+<title>origin of the script that invoked the method, data:</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="data:text/html,<script>onmessage = function(e) { parent.postMessage(e.origin, '*'); }; parent.postMessage('loaded', '*');</script>"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ onmessage = this.step_func(function(e) {
+ if (e.data === 'loaded') {
+ window[0].postMessage('', '*');
+ return;
+ }
+
+ assert_equals(e.data, location.protocol + '//' + location.host);
+ assert_equals(e.origin, 'null');
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/017.html b/testing/web-platform/tests/webmessaging/without-ports/017.html
new file mode 100644
index 0000000000..a4a0483624
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/017.html
@@ -0,0 +1,18 @@
+<!doctype html>
+<title>origin of the script that invoked the method, about:blank</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="about:blank"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ window[0].postMessage('', '*');
+ window[0].onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ assert_array_equals(e.ports, []);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/018.html b/testing/web-platform/tests/webmessaging/without-ports/018.html
new file mode 100644
index 0000000000..207ae36ed8
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/018.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>origin of the script that invoked the method, javascript:</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="javascript:''"></iframe>
+<div id=log></div>
+<script>
+async_test(function() {
+ window[0].postMessage('', '*');
+ window[0].onmessage = this.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ this.done();
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/019-1.html b/testing/web-platform/tests/webmessaging/without-ports/019-1.html
new file mode 100644
index 0000000000..513123ee6d
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/019-1.html
@@ -0,0 +1 @@
+<!-- blank --> \ No newline at end of file
diff --git a/testing/web-platform/tests/webmessaging/without-ports/019.html b/testing/web-platform/tests/webmessaging/without-ports/019.html
new file mode 100644
index 0000000000..38e7ca230e
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/019.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>origin of the script that invoked the method, scheme/host/port</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/019-1.html"></iframe>
+<div id=log></div>
+<script>
+async_test(function(test) {
+ onload = test.step_func(function() {
+ window[0].postMessage('', location.protocol.toUpperCase() + '//' + location.host.toUpperCase() + '/');
+ window[0].onmessage = test.step_func(function(e) {
+ assert_equals(e.origin, location.protocol + '//' + location.host);
+ assert_array_equals(e.ports, []);
+ test.done();
+ });
+ });
+});
+</script>
+
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/020-1.html b/testing/web-platform/tests/webmessaging/without-ports/020-1.html
new file mode 100644
index 0000000000..225bd7a41e
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/020-1.html
@@ -0,0 +1,5 @@
+<script>
+onmessage = function(e) {
+ parent.postMessage([e.data, e.origin], '*');
+}
+</script> \ No newline at end of file
diff --git a/testing/web-platform/tests/webmessaging/without-ports/020.html b/testing/web-platform/tests/webmessaging/without-ports/020.html
new file mode 100644
index 0000000000..61bfddb901
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/020.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>cross-origin test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/020-1.html"></iframe>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var iframe = document.createElement('iframe');
+var url_prefix = location.href.replace('://', '://www1.').replace(/\/with(out)?-ports\/[^\/]+$/, '');
+var url = url_prefix + '/without-ports/020-1.html';
+iframe.src = url;
+document.body.appendChild(iframe);
+</script>
+<div id=log></div>
+<script>
+onload = function() {
+ window[0].postMessage(1, location.href);
+ window[1].postMessage(2, url);
+ var i = 0;
+ onmessage = function(e) {
+ i++;
+ assert_equals(e.data[0], i);
+ assert_equals(e.data[1], location.protocol + '//' + location.host);
+ if (i == 2) {
+ done();
+ }
+ };
+};
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/021.html b/testing/web-platform/tests/webmessaging/without-ports/021.html
new file mode 100644
index 0000000000..5072508d9c
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/021.html
@@ -0,0 +1,32 @@
+<!doctype html>
+<title>cross-origin test</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<iframe src="../without-ports/020-1.html"></iframe>
+<div id="log"></div>
+<script>
+setup({ single_test: true });
+
+var iframe = document.createElement('iframe');
+var url_prefix = location.href.replace('://', '://www1.').replace(/\/with(out)?-ports\/[^\/]+$/, '');
+var url = url_prefix + '/without-ports/020-1.html';
+iframe.src = url;
+document.body.appendChild(iframe);
+</script>
+<div id=log></div>
+<script>
+onload = function() {
+ window[0].postMessage(1, '*');
+ window[1].postMessage(2, '*');
+ var i = 0;
+ onmessage = function(e) {
+ i++;
+ assert_equals(e.data[0], i);
+ assert_equals(e.data[1], location.protocol + '//' + location.host);
+ if (i === 2) {
+ done();
+ }
+ };
+};
+</script>
+
diff --git a/testing/web-platform/tests/webmessaging/without-ports/023.html b/testing/web-platform/tests/webmessaging/without-ports/023.html
new file mode 100644
index 0000000000..1e12ac4a55
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/023.html
@@ -0,0 +1,29 @@
+<!doctype html>
+<title>Object cloning: own properties only, don't follow prototype</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id="log"></div>
+<script>
+var Parent = function(){
+ this.c = "xyz";
+};
+
+var Child = function(a, b) {
+ this.a = a;
+ this.b = b;
+};
+Child.prototype = new Parent;
+
+async_test(function() {
+ var obj = new Child(1, 2);
+ var ch = new MessageChannel();
+ ch.port1.onmessage = this.step_func(function(e) {
+ for (var i in e.data.obj)
+ assert_not_equals(i, 'c');
+ this.done();
+ });
+ ch.port2.start();
+ ch.port2.postMessage({obj: obj});
+});
+
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/024.html b/testing/web-platform/tests/webmessaging/without-ports/024.html
new file mode 100644
index 0000000000..0e4651593a
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/024.html
@@ -0,0 +1,14 @@
+<!doctype html>
+<title>Object cloning: throw an exception if function values encountered</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ var obj = { f : function(){}};
+ var ch = new MessageChannel();
+ ch.port1.onmessage = function(){};
+ ch.port2.start();
+ assert_throws_dom('DATA_CLONE_ERR', function() { ch.port2.postMessage({obj: obj}); });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/025-1.js b/testing/web-platform/tests/webmessaging/without-ports/025-1.js
new file mode 100644
index 0000000000..bd1d778d9b
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/025-1.js
@@ -0,0 +1,15 @@
+importScripts("/resources/testharness.js");
+
+test(function() {
+ var ch = new MessageChannel();
+ assert_true(ch.port1 instanceof MessagePort,
+ "Worker MessageChannel's port not an instance of MessagePort");
+}, "Worker MessageChannel's port should be an instance of MessagePort");
+
+test(function() {
+ assert_throws_js(TypeError, function() {
+ new MessagePort()
+ }, "MessagePort is [[Callable]]");
+}, "Worker MessagePort should not be [[Callable]]");
+
+done();
diff --git a/testing/web-platform/tests/webmessaging/without-ports/025.html b/testing/web-platform/tests/webmessaging/without-ports/025.html
new file mode 100644
index 0000000000..4686febe94
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/025.html
@@ -0,0 +1,13 @@
+<!doctype html>
+<title>MessagePort constructor properties</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+test(function() {
+ var ch = new MessageChannel();
+ assert_true(ch.port1 instanceof MessagePort, "MessageChannel's port not an instance of MessagePort");
+ assert_throws_js(TypeError, function () { var p = new MessagePort();}, "MessagePort is [[Callable]]");
+});
+fetch_tests_from_worker(new Worker("025-1.js"));
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/026.html b/testing/web-platform/tests/webmessaging/without-ports/026.html
new file mode 100644
index 0000000000..546da8a91b
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/026.html
@@ -0,0 +1,17 @@
+<!doctype html>
+<title>Cloning objects with getter properties</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var obj = {};
+ var err = new Error("getter_should_propagate_exceptions");
+ obj.__defineGetter__( "field", function(){ throw err });
+
+ assert_throws_exactly(err, function() {
+ postMessage(obj, '*');
+ });
+ this.done();
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/027.html b/testing/web-platform/tests/webmessaging/without-ports/027.html
new file mode 100644
index 0000000000..36aa9446a5
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/027.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Cloning objects, preserving sharing</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var obj1 = {o: 1};
+ var obj2 = {d: obj1};
+ var obj3 = {d: obj1};
+ var obj_dag = {b: obj2, c: obj3};
+
+ postMessage(obj_dag, '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data.b.d, e.data.c.d);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/028.html b/testing/web-platform/tests/webmessaging/without-ports/028.html
new file mode 100644
index 0000000000..d51ad7d3b6
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/028.html
@@ -0,0 +1,19 @@
+<!doctype html>
+<title>Cloning objects, preserving sharing #2</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<canvas id="a" width=30 height=30></canvas>
+<div id=log></div>
+<script>
+async_test(function() {
+ var canvas = document.getElementsByTagName("canvas")[0];
+ var context = canvas.getContext("2d");
+ var img_data = context.getImageData(0, 0, 30, 30);
+ var obj = {a: img_data, b: {c: img_data, d: 3}};
+ postMessage(obj, '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data.a, e.data.b.c);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/without-ports/029.html b/testing/web-platform/tests/webmessaging/without-ports/029.html
new file mode 100644
index 0000000000..4b1b38f741
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/without-ports/029.html
@@ -0,0 +1,20 @@
+<!doctype html>
+<title>Check that getters don't linger after deletion wrt cloning</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<div id=log></div>
+<script>
+async_test(function() {
+ var obj = {};
+ obj.__defineGetter__( "a", function(){ return 2; } );
+ obj.__defineSetter__( "a", function(v){ return; } );
+ delete obj.a;
+ obj.a = 2;
+
+ postMessage(obj, '*');
+ onmessage = this.step_func(function(e) {
+ assert_equals(e.data.a, 2);
+ this.done();
+ });
+});
+</script>
diff --git a/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.js b/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.js
new file mode 100644
index 0000000000..e4c7eec2b7
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.js
@@ -0,0 +1,3 @@
+"use strict";
+
+onmessage = e => postMessage(e.userActivation !== null);
diff --git a/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.tentative.html b/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.tentative.html
new file mode 100644
index 0000000000..203bb14985
--- /dev/null
+++ b/testing/web-platform/tests/webmessaging/worker_postMessage_user_activation.tentative.html
@@ -0,0 +1,19 @@
+<!DOCTYPE html>
+<title>postMessage with user activtion to a worker</title>
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+
+<script>
+"use strict";
+
+promise_test(async t => {
+ var worker = new Worker("worker_postMessage_user_activation.js");
+ let workerReply = () => new Promise((resolve, reject) => {
+ worker.addEventListener('message', e => resolve(e.data), {once: true});
+ });
+ worker.postMessage(null, {includeUserActivation: true});
+ assert_equals(await workerReply(), true);
+ worker.postMessage(null, {includeUserActivation: false});
+ assert_equals(await workerReply(), false);
+}, "Post Message from a worker");
+</script>