-
Notifications
You must be signed in to change notification settings - Fork 3.2k
/
Copy pathPresentationReceiver_create_receiving-ua.html
328 lines (298 loc) · 15.1 KB
/
PresentationReceiver_create_receiving-ua.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
<!DOCTYPE html>
<meta charset="utf-8">
<title>Creating a receiving browsing context</title>
<link rel="author" title="Tomoyuki Shimizu" href="https://github.com/tomoyukilabs/">
<link rel="help" href="https://w3c.github.io/presentation-api/#creating-a-receiving-browsing-context">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../common.js"></script>
<script src="stash.js"></script>
<style>
a { visibility: hidden; }
iframe { width: 100%; }
</style>
<iframe id="child" src="PresentationReceiver_create_receiving-ua_child.html"></iframe>
<p id="notice">Checking <code id="modal"></code>: if you see this message, please wait for test to time out.</p>
<a href="PresentationReceiver_unreached_receiving-ua.html">do not navigate</a>
<script>
let finished = false;
const sendResult = (test, status) => {
if(!finished) {
finished = true;
const stash = new Stash(stashIds.toReceiver, stashIds.toController);
stash.send(JSON.stringify({ test: test, status: status }));
}
};
add_completion_callback((tests, status) => {
// note: a single test result is supposed to appear here.
sendResult(tests[0], status);
});
const child = document.getElementById('child');
child.addEventListener('load', () => {
const notice = document.getElementById('notice');
const modal = document.getElementById('modal');
const dbName = {
controller: 'db-presentation-api-controlling-ua',
receiver: 'db-presentation-api-receiving-ua'
};
promise_test(t => {
t.add_cleanup(() => {
document.cookie = cookieName + '=False;Expires=' + new Date().toUTCString();
document.cookie = cookieNameChild + '=False;Expires=' + new Date().toUTCString();
sessionStorage.removeItem(storageName);
localStorage.removeItem(storageName);
sessionStorage.removeItem(storageNameChild);
localStorage.removeItem(storageNameChild);
Object.values(dbName).forEach(name => {
indexedDB.deleteDatabase(name);
});
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations().then(registrations => {
return Promise.all(registrations.map(reg => reg.unregister()));
});
}
if ('caches' in window) {
caches.keys().then(keys => {
return Promise.all(keys.map(key => caches.delete(key)));
});
}
});
// Session history
assert_equals(window.history.length, 1, 'Session history consists of the current page only.');
// The Sandboxed auxiliary navigation browsing context flag
assert_equals(window.open('PresentationReceiver_unreached_receiving-ua.html'), null, 'Sandboxed auxiliary navigation browsing context flag is set.');
// The sandboxed top-level navigation browsing context flag (codes below are expected to be ignored)
window.close();
document.querySelector('a').click();
location.href = 'PresentationReceiver_unreached_receiving-ua.html';
// The sandboxed modals flag (codes below are expected to be ignored):
// If user agent prompts user, a timeout will occur and the test will eventually fail
let message = 'If you see this prompt, do not dismiss it and wait for test to time out.';
notice.style.display = 'block';
modal.textContent = 'alert()';
alert(message);
modal.textContent = 'confirm()';
confirm(message);
modal.textContent = 'print()';
print();
modal.textContent = 'prompt()';
prompt(message);
notice.style.display = 'none';
// Permissions
const checkPermission = query => {
return navigator.permissions ? navigator.permissions.query(query).then(status => {
assert_equals(status.state, 'denied', 'The state of the "' + query.name + '" permission is set to "denied".');
}, () => { /* skip this assertion if the specified permission is not implemented */ }) : Promise.resolve();
}
// Cookie
assert_equals(document.cookie, '', 'A cookie store is set to an empty store.')
// Indexed Database
const checkIndexedDB = () => {
if ('indexedDB' in window) {
// The test would fail when the database is already created by the controlling UA
const req = indexedDB.open(dbName.controller);
const upgradeneededWatcher = new EventWatcher(t, req, 'upgradeneeded');
const successWatcher = new EventWatcher(t, req, 'success');
return Promise.race([
upgradeneededWatcher.wait_for('upgradeneeded').then(evt => {
evt.target.result.close();
const req = indexedDB.open(dbName.receiver, 2);
const eventWatcher = new EventWatcher(t, req, 'upgradeneeded');
return eventWatcher.wait_for('upgradeneeded');
}).then(evt => {
evt.target.result.close();
}),
successWatcher.wait_for('success').then(evt => {
evt.target.result.close();
// This would fail if the database created by the controlling UA is visible to the receiving UA
assert_unreached('Indexed Database is set to an empty storage.');
})
]);
}
else
return Promise.resolve();
};
// Web Storage
assert_equals(sessionStorage.length, 0, 'Session storage is set to an empty storage.');
assert_equals(localStorage.length, 0, 'Local storage is set to an empty storage.');
// Service Workers
const checkServiceWorkers = () => {
return 'serviceWorker' in navigator ? navigator.serviceWorker.getRegistrations().then(registrations => {
assert_equals(registrations.length, 0, 'List of registered service worker registrations is empty.');
}) : Promise.resolve();
};
const checkCaches = () => {
return 'caches' in window ? caches.keys().then(keys => {
assert_equals(keys.length, 0, 'Cache storage is empty.')
}) : Promise.resolve();
};
// Navigation
const checkNavigation = () => {
return navigator.presentation.receiver.connectionList.then(connectionList => {
assert_equals(connectionList.connections.length, 1, 'The initial number of presentation connections is one');
assert_equals(location.href, connectionList.connections[0].url, 'A receiving browsing context is navigated to the presentation URL.');
});
};
// Update storages and service workers shared with the top-level brosing context
const cookieName = 'PresentationApiTest';
const cookieValue = 'Receiving-UA';
const storageName = 'presentation_api_test';
const storageValue = 'receiving-ua';
document.cookie = cookieName + '=' + cookieValue;
sessionStorage.setItem(storageName, storageValue);
localStorage.setItem(storageName, storageValue);
// Service Workers and Caches
const cacheName = 'receiving-ua';
const getClientUrls = () => {
return new Promise(resolve => {
navigator.serviceWorker.getRegistration().then(reg => {
const channel = new MessageChannel();
channel.port1.onmessage = event => {
resolve(event.data);
};
reg.active.postMessage('test', [channel.port2]);
});
});
};
const registerServiceWorker = () => {
return ('serviceWorker' in navigator ?
navigator.serviceWorker.register('../serviceworker.js').then(registration => {
return new Promise((resolve, reject) => {
if (registration.installing) {
registration.installing.addEventListener('statechange', event => {
if(event.target.state === 'installed')
resolve();
});
}
else
resolve();
});
}) : Promise.resolve()).then(getClientUrls).then(urls => {
assert_true(urls.every(url => { return url !== new Request('../PresentationReceiver_create-manual.https.html').url }),
'A window client in a controlling user agent is not accessible to a service worker on a receiving user agent.');
});
};
const openCaches = () => {
return 'caches' in window ? caches.open(cacheName).then(cache => cache.add('../cache.txt')) : Promise.resolve();
};
const getChildFrameResult = () => {
return new Promise(resolve => {
window.addEventListener('message', t.step_func(event => {
const result = event.data;
if (result.type === 'presentation-api') {
// if the test in iframe failed, report the result and abort the test
if (result.test.status === 0)
resolve();
else {
sendResult(result.test, result.status);
assert_unreached('A test for a nested browsing context failed.');
}
}
}));
child.contentWindow.postMessage('start', location.origin);
});
};
// check the results from updates by iframe
const cookieNameChild = 'NestedBrowsingContext';
const cookieValueChild = 'True';
const storageNameChild = 'nested_browsing_context';
const storageValueChild = 'yes';
const checkUpdatedResult = () => {
// cookie
const cookies = document.cookie.split(/;\s*/).reduce((result, item) => {
const t = item.split('=');
result[t[0]] = t[1];
return result;
}, {});
message = 'A cookie store is shared by top-level and nested browsing contexts.'
assert_equals(Object.keys(cookies).length, 2, message);
assert_equals(cookies[cookieName], cookieValue, message);
assert_equals(cookies[cookieNameChild], cookieValueChild, message);
// Web Storage
message = 'Session storage is shared by top-level and nested browsing contexts.';
assert_equals(sessionStorage.length, 2, message);
assert_equals(sessionStorage.getItem(storageName), storageValue, message);
assert_equals(sessionStorage.getItem(storageNameChild), storageValueChild, message);
message = 'Local storage is shared by top-level and nested browsing contexts.';
assert_equals(localStorage.length, 2, message);
assert_equals(localStorage.getItem(storageName), storageValue, message);
assert_equals(localStorage.getItem(storageNameChild), storageValueChild, message);
};
// Indexed Database
const checkUpdatedIndexedDB = () => {
if ('indexedDB' in window) {
message = 'Indexed Database is shared by top-level and nested browsing contexts.';
const req = indexedDB.open(dbName.receiver);
const upgradeneededWatcher = new EventWatcher(t, req, 'upgradeneeded');
const successWatcher = new EventWatcher(t, req, 'success');
return Promise.race([
upgradeneededWatcher.wait_for('upgradeneeded').then(evt => {
evt.target.result.close();
// Check if the version of the database is upgraded to 3 by the nested browsing context
assert_unreached(message);
}),
successWatcher.wait_for('success').then(evt => {
const db = evt.target.result;
const version = db.version;
db.close();
// Check if the version of the database is upgraded to 3 by the nested browsing context
assert_equals(version, 3, message);
})
]);
}
else
return Promise.resolve();
};
// Service Workers
const checkUpdatedServiceWorkers = () => {
return 'serviceWorker' in window ? navigator.serviceWorker.getRegistrations().then(registrations => {
message = 'List of registered service worker registrations is shared by top-level and nested browsing contexts.';
assert_equals(registrations.length, 2, message);
const scriptURLs = registrations.map(reg => { return reg.active.scriptURL; }).sort();
assert_equals(scriptURLs[0], new Request('../serviceworker.js').url, message);
assert_equals(scriptURLs[1], new Request('serviceworker.js').url, message);
}) : Promise.resolve();
};
const cacheNameChild = 'nested-browsing-context';
const checkUpdatedCaches = () => {
message = 'Cache storage is shared by top-level and nested browsing contexts.';
return 'caches' in window ? caches.keys().then(keys => {
assert_equals(keys.length, 2, message);
const cacheKeys = keys.sort();
assert_equals(cacheKeys[0], cacheNameChild, message);
assert_equals(cacheKeys[1], cacheName, message);
return Promise.all(keys.map(
key => caches.open(key)
.then(cache => cache.matchAll())
.then(responses => {
assert_equals(responses.length, 1, message);
assert_equals(responses[0].url, new Request('../cache.txt').url, message);
})));
}) : Promise.resolve();
};
// Asynchronous tests
const permissionList = [
{ name: 'geolocation' },
{ name: 'notifications' },
{ name: 'push', userVisibleOnly: true },
{ name: 'midi' },
{ name: 'camera' },
{ name: 'microphone' },
{ name: 'speaker' },
{ name: 'background-sync' }
];
return Promise.all(permissionList.map(perm => { return checkPermission(perm); }))
.then(checkIndexedDB)
.then(checkServiceWorkers)
.then(checkCaches)
.then(checkNavigation)
.then(registerServiceWorker)
.then(openCaches)
.then(getChildFrameResult)
.then(checkUpdatedResult)
.then(checkUpdatedIndexedDB)
.then(checkUpdatedServiceWorkers)
.then(checkUpdatedCaches);
});
});
</script>