| <!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> |