Source code
Revision control
Copy as Markdown
Other Tools
Test Info:
- This WPT test may be referenced by the following Test IDs:
- /webmessaging/broadcastchannel/detached-iframe.html - WPT Dashboard Interop Dashboard
<!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>