diff options
Diffstat (limited to 'testing/web-platform/tests/webmessaging')
161 files changed, 5534 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..cce20869bc --- /dev/null +++ b/testing/web-platform/tests/webmessaging/META.yml @@ -0,0 +1,5 @@ +spec: https://html.spec.whatwg.org/multipage/web-messaging.html +suggested_reviewers: + - 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/WEB_FEATURES.yml b/testing/web-platform/tests/webmessaging/broadcastchannel/WEB_FEATURES.yml new file mode 100644 index 0000000000..378ed57dc5 --- /dev/null +++ b/testing/web-platform/tests/webmessaging/broadcastchannel/WEB_FEATURES.yml @@ -0,0 +1,3 @@ +features: +- name: broadcast-channel + files: "**" 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-event/document-destroyed.tentative.window.js b/testing/web-platform/tests/webmessaging/message-channels/close-event/document-destroyed.tentative.window.js new file mode 100644 index 0000000000..85e4ad30ad --- /dev/null +++ b/testing/web-platform/tests/webmessaging/message-channels/close-event/document-destroyed.tentative.window.js @@ -0,0 +1,43 @@ +// META: title=Close event test when the document is destroyed. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=resources/helper.js + +promise_test(async t => { + const rc = await addWindow(); + const waitForPort = expectMessagePortFromWindow(window); + await createMessageChannelAndSendPort(rc); + const closeEventPromise = createCloseEventPromise(await waitForPort); + rc.navigateToNew(); + await closeEventPromise; +}, 'The context is navigated to a new document and a close event is fired.') + +promise_test(async t => { + const rc = await addWindow(); + const waitForPort = expectMessagePortFromWindow(window); + await createMessageChannelAndSendPort(rc); + const closeEventPromise = createCloseEventPromise(await waitForPort); + rc.executeScript(() => window.close()); + await closeEventPromise; +}, 'The window is closed and a close event is fired.') + +promise_test(async t => { + let iframe; + const waitForLoad = new Promise(resolve => { + iframe = document.createElement('iframe'); + iframe.onload = resolve; + document.documentElement.appendChild(iframe); + }); + await waitForLoad; + + const waitForPort = expectMessagePortFromWindow(iframe.contentWindow); + const {port1, port2} = new MessageChannel(); + port1.start(); + iframe.contentWindow.postMessage('', '*', [port2]); + await waitForPort; + const closeEventPromise = createCloseEventPromise(port1); + iframe.remove(); + await closeEventPromise; +}, 'The iframe is deleted and a close event is fired.') diff --git a/testing/web-platform/tests/webmessaging/message-channels/close-event/entangled-after-back-forward-cache-restore.https.tentative.window.js b/testing/web-platform/tests/webmessaging/message-channels/close-event/entangled-after-back-forward-cache-restore.https.tentative.window.js new file mode 100644 index 0000000000..c99e89f02b --- /dev/null +++ b/testing/web-platform/tests/webmessaging/message-channels/close-event/entangled-after-back-forward-cache-restore.https.tentative.window.js @@ -0,0 +1,64 @@ +// META: timeout=long +// META: title=Confirm close event is not fired when the page enters BFCache and MessagePort still works after the page is restored. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=/service-workers/service-worker/resources/test-helpers.sub.js +// META: script=/html/browsers/browsing-the-web/back-forward-cache/resources/rc-helper.js + +promise_test(async t => { + // Register a service worker. + const scope = + '/html/browsers/browsing-the-web/remote-context-helper/resources' + const workerUrl = + `/html/browsers/browsing-the-web/back-forward-cache/resources/` + + `service-worker.js?pipe=header(Service-Worker-Allowed,${scope})`; + const registration = + await service_worker_unregister_and_register(t, workerUrl, scope); + t.add_cleanup(_ => registration.unregister()); + await wait_for_state(t, registration.installing, 'activated'); + + // Open a window with noopener so that BFCache will work. + const rcHelper = new RemoteContextHelper(); + const rc1 = await rcHelper.addWindow( + /*extraConfig=*/ null, /*options=*/ {features: 'noopener'}); + + // Confirm the page is controlled. + assert_true( + await rc1.executeScript( + () => (navigator.serviceWorker.controller !== null)), + 'The page should be controlled before navigation'); + + // Send MessagePort to the service worker. + await rc1.executeScript(() => { + const {port1, port2} = new MessageChannel(); + port1.start(); + const ctrl = navigator.serviceWorker.controller; + ctrl.postMessage({type: 'storeMessagePort'}, [port2]); + self.waitForMessage = (sentMessage) => { + return new Promise(resolve => { + port1.addEventListener('message', (event) => { + resolve(event.data); + }); + port1.postMessage(sentMessage); + }); + }; + }); + + // Verify that the page was BFCached. + await assertBFCacheEligibility(rc1, /*shouldRestoreFromBFCache=*/ true); + + // Confirm MessagePort can still work after the page is restored from + // BFCache. + assert_equals( + await rc1.executeScript( + async () => + await self.waitForMessage('Confirm the ports can communicate')), + 'Receive message'); + + // Confirm the close event was not fired. + assert_false(await rc1.executeScript( + async () => + await self.waitForMessage('Ask if the close event was fired'))); +}, 'MessagePort still works after the page is restored from BFCache');
\ No newline at end of file diff --git a/testing/web-platform/tests/webmessaging/message-channels/close-event/explicitly-closed.tentative.window.js b/testing/web-platform/tests/webmessaging/message-channels/close-event/explicitly-closed.tentative.window.js new file mode 100644 index 0000000000..612003d58e --- /dev/null +++ b/testing/web-platform/tests/webmessaging/message-channels/close-event/explicitly-closed.tentative.window.js @@ -0,0 +1,35 @@ +// META: title=Close event test when an entangled port is explicitly closed. +// META: script=/common/dispatcher/dispatcher.js +// META: script=/common/get-host-info.sub.js +// META: script=/common/utils.js +// META: script=/html/browsers/browsing-the-web/remote-context-helper/resources/remote-context-helper.js +// META: script=resources/helper.js + +async_test(t => { + const channel = new MessageChannel(); + channel.port1.start(); + channel.port2.start(); + channel.port2.onclose = t.step_func_done(); + channel.port1.close(); +}, 'Close event on port2 is fired when port1 is explicitly closed'); + +async_test(t => { + const channel = new MessageChannel(); + channel.port1.start(); + channel.port2.start(); + channel.port1.onclose = + t.unreached_func('Should not fire a close event on port1'); + channel.port1.close(); + t.step_timeout(t.step_func_done(), 1000); +}, 'Close event on port1 is not fired when port1 is explicitly closed'); + +promise_test(async t => { + const rc = await addWindow(); + const waitForPort = expectMessagePortFromWindow(window); + await createMessageChannelAndSendPort(rc); + const closeEventPromise = createCloseEventPromise(await waitForPort); + rc.executeScript(() => { + window.closePort(); + }); + await closeEventPromise; +}, 'Close event on port2 is fired when port1, which is in a different window, is explicitly closed.') diff --git a/testing/web-platform/tests/webmessaging/message-channels/close-event/garbage-collected.tentative.any.js b/testing/web-platform/tests/webmessaging/message-channels/close-event/garbage-collected.tentative.any.js new file mode 100644 index 0000000000..11f19c3b24 --- /dev/null +++ b/testing/web-platform/tests/webmessaging/message-channels/close-event/garbage-collected.tentative.any.js @@ -0,0 +1,23 @@ +// META: title=Close event test when an entangled port is GCed. +// META: script=/common/gc.js + +/** + * Create a new MessageChannel and return port1 and a weak reference to port2. + * It is expected that port2 will be garbage collected and a close event + * will be fired on port1. + * + * @returns {Array.<[MessagePort, WeakRef<MessagePort>]>} + */ +function createMessageChannelAndWeakReferToPort() { + const {port1, port2} = new MessageChannel(); + port1.start(); + return [port1, new WeakRef(port2)]; +} + +promise_test(async t => { + const [port1, weakport2] = createMessageChannelAndWeakReferToPort(); + const closeEventPromise = new Promise(resolve => port1.onclose = resolve); + garbageCollect(); + await closeEventPromise; + assert_equals(weakport2.deref(), undefined, 'port2 should be GCed'); +}, 'Entangled port is garbage collected, and the close event is fired.') diff --git a/testing/web-platform/tests/webmessaging/message-channels/close-event/resources/helper.js b/testing/web-platform/tests/webmessaging/message-channels/close-event/resources/helper.js new file mode 100644 index 0000000000..cb9ea9fe98 --- /dev/null +++ b/testing/web-platform/tests/webmessaging/message-channels/close-event/resources/helper.js @@ -0,0 +1,62 @@ +/** + * Create a new promise that resolves when the window receives + * the MessagePort and starts it. + * + * @param {Window} window - The window to wait for the MessagePort. + * @returns {Promise<MessagePort>} A promise you should await to ensure the + * window + * receives the MessagePort. + */ +function expectMessagePortFromWindow(window) { + return new Promise(resolve => { + window.onmessage = e => { + try { + assert_true(e.ports[0] instanceof window.MessagePort); + e.ports[0].start(); + resolve(e.ports[0]); + } catch (e) { + reject(e); + } + }; + }); +} + +/** + * Create a new MessageChannel and transfers one of the ports to + * the window which opened the window with a remote context provided + * as an argument. + * + * @param {RemoteContextWrapper} remoteContextWrapper + */ +async function createMessageChannelAndSendPort(remoteContextWrapper) { + await remoteContextWrapper.executeScript(() => { + const {port1, port2} = new MessageChannel(); + port1.start(); + window.opener.postMessage({}, '*', [port2]); + window.closePort = () => { + port1.close(); + } + }); +} + +/** + * Creates a window with a remote context. + * + * @returns {Promise<RemoteContextWrapper>} + */ +async function addWindow() { + const helper = new RemoteContextHelper(); + return helper.addWindow(); +} + +/** + * Creates a new promise that resolves when the close event is fired. + * + * @param {MessagePort} port - MessagePort on which the close event will + * be fired. + * @returns {Promise} A promise you should await to ensure the close event + * is dispatched. + */ +function createCloseEventPromise(port) { + return new Promise(resolve => port.onclose = resolve); +} 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> |