1<!DOCTYPE html> 2<meta charset=utf-8> 3<script src="/resources/testharness.js"></script> 4<script src="/resources/testharnessreport.js"></script> 5<script src="/common/get-host-info.sub.js"></script> 6<!-- Pull in the with_iframe helper function from the service worker tests --> 7<script src="/service-workers/service-worker/resources/test-helpers.sub.js"></script> 8<body> 9<script> 10const TEST_IFRAME_CLASS_NAME = 'test-iframe'; 11const events = []; 12var bc1; 13const DONE_MSG = 'done'; 14 15function DetachedIframeTestCheckForOneMessage(t) { 16 return new Promise((resolve) => { 17 bc1.onmessage = t.step_func(e => { 18 events.push(e); 19 if (e.data == DONE_MSG) { 20 assert_equals(events.length, 1); 21 resolve(); 22 } 23 }); 24 }); 25} 26 27const IframeAction = { 28 REMOVE_BEFORE_CREATION: 'remove-before-creation', 29 REMOVE_AFTER_CREATION: 'remove-after-creation', 30}; 31 32async function doMessageSentTest(t, channelName, action) { 33 await with_iframe('about:blank'); 34 const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0]; 35 const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel; 36 37 if (action === IframeAction.REMOVE_BEFORE_CREATION) { 38 iframe.remove(); 39 } 40 41 events.length = 0; 42 43 bc1 = new BroadcastChannel(channelName); 44 const bc2 = new BroadcastChannel(channelName); 45 const iframe_bc = new iframe_BroadcastChannel(channelName); 46 47 if (action === IframeAction.REMOVE_AFTER_CREATION) { 48 iframe.remove(); 49 } 50 51 const testResultsPromise = DetachedIframeTestCheckForOneMessage(t); 52 53 iframe_bc.postMessage('test'); 54 bc2.postMessage(DONE_MSG); 55 56 bc2.close(); 57 iframe_bc.close(); 58 t.add_cleanup(() => bc1.close()); 59 60 return testResultsPromise; 61} 62 63promise_test(async t => { 64 return doMessageSentTest( 65 t, 'postMessage-from-detached-iframe-pre', 66 IframeAction.REMOVE_AFTER_CREATION); 67}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created before detaching)'); 68 69promise_test(async t => { 70 return doMessageSentTest( 71 t, 'postMessage-from-detached-iframe-post', 72 IframeAction.REMOVE_BEFORE_CREATION); 73}, 'BroadcastChannel messages from detached iframe to parent should be ignored (BC created after detaching)'); 74 75 76async function doMessageReceivedTest(t, channelName, action) { 77 await with_iframe('about:blank'); 78 const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0]; 79 const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel; 80 81 if (action === IframeAction.REMOVE_BEFORE_CREATION) { 82 iframe.remove(); 83 } 84 85 events.length = 0; 86 87 // `iframe_bc` must be created first so that it receives messages before 88 // `bc1`. That way we can tell whether `iframe_bc` received a message by 89 // inspecting `events` in the `bc1` message handler. 90 const iframe_bc = new iframe_BroadcastChannel(channelName); 91 iframe_bc.onmessage = e => { 92 events.push(e) 93 }; 94 bc1 = new BroadcastChannel(channelName); 95 const bc2 = new BroadcastChannel(channelName); 96 97 if (action === IframeAction.REMOVE_AFTER_CREATION) { 98 iframe.remove(); 99 } 100 101 const testResultsPromise = DetachedIframeTestCheckForOneMessage(t); 102 bc2.postMessage(DONE_MSG); 103 104 bc2.close(); 105 iframe_bc.close(); 106 t.add_cleanup(() => bc1.close()); 107} 108 109promise_test(async t => { 110 return doMessageReceivedTest( 111 t, 'postMessage-to-detached-iframe-pre', 112 IframeAction.REMOVE_AFTER_CREATION); 113}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created before detaching)'); 114 115promise_test(async t => { 116 return doMessageReceivedTest( 117 t, 'postMessage-to-detached-iframe-post', 118 IframeAction.REMOVE_BEFORE_CREATION); 119}, 'BroadcastChannel messages from parent to detached iframe should be ignored (BC created after detaching)'); 120 121 122async function doMessageSendReceiveTest(t, channelName, action) { 123 await with_iframe('about:blank'); 124 const iframe = document.getElementsByClassName(TEST_IFRAME_CLASS_NAME)[0]; 125 const iframe_BroadcastChannel = iframe.contentWindow.BroadcastChannel; 126 127 if (action === IframeAction.REMOVE_BEFORE_CREATION) { 128 iframe.remove(); 129 } 130 131 const iframe_bc1 = new iframe_BroadcastChannel(channelName); 132 const iframe_bc2 = new iframe_BroadcastChannel(channelName); 133 iframe_bc1.onmessage = t.unreached_func( 134 'Detached iframe BroadcastChannel instance received message unexpectedly'); 135 136 if (action === IframeAction.REMOVE_AFTER_CREATION) { 137 iframe.remove(); 138 } 139 140 iframe_bc2.postMessage(DONE_MSG); 141 142 iframe_bc2.close(); 143 t.add_cleanup(() => iframe_bc1.close()); 144 145 // To avoid calling t.step_timeout here, instead just create two new 146 // BroadcastChannel instances and complete the test when a message is passed 147 // between them. Per the spec, all "BroadcastChannel objects whose relevant 148 // agents are the same" must have messages delivered to them in creation 149 // order, so if we get this message then it's safe to assume the earlier 150 // message would have been delivered if it was going to be. 151 const bc1 = new BroadcastChannel(channelName); 152 const bc2 = new BroadcastChannel(channelName); 153 return new Promise((resolve) => { 154 bc1.onmessage = t.step_func(e => { 155 resolve(); 156 }); 157 bc2.postMessage(DONE_MSG); 158 }); 159} 160 161promise_test(async t => { 162 return doMessageSendReceiveTest( 163 t, 'postMessage-within-detached-iframe-pre', 164 IframeAction.REMOVE_AFTER_CREATION); 165}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created before detaching)'); 166 167promise_test(async t => { 168 return doMessageSendReceiveTest( 169 t, 'postMessage-within-detached-iframe-post', 170 IframeAction.REMOVE_BEFORE_CREATION); 171}, 'BroadcastChannel messages within detached iframe should be ignored (BCs created after detaching)'); 172 173</script> 174</body> 175