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