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
|
<!DOCTYPE html>
<title>Service Worker: Fetch Event Waits for Activate Event</title>
<meta name=timeout content=long>
<script src="/resources/testharness.js"></script>
<script src="resources/testharness-helpers.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/common/get-host-info.sub.js"></script>
<script src="resources/test-helpers.sub.js"></script>
<body>
<script>
const worker_url = 'resources/fetch-waits-for-activate-worker.js';
const normalized_worker_url = normalizeURL(worker_url);
const worker_scope = 'resources/fetch-waits-for-activate/';
// Resolves with the Service Worker's registration once it's reached the
// "activating" state. (The Service Worker should remain "activating" until
// explicitly told advance to the "activated" state).
async function registerAndWaitForActivating(t) {
const registration = await service_worker_unregister_and_register(
t, worker_url, worker_scope);
t.add_cleanup(() => service_worker_unregister(t, worker_scope));
await wait_for_state(t, registration.installing, 'activating');
return registration;
}
// Attempts to ensure that the "Handle Fetch" algorithm has reached the step
//
// "If activeWorker’s state is "activating", wait for activeWorker’s state to
// become "activated"."
//
// by waiting for some time to pass.
//
// WARNING: whether the algorithm has reached that step isn't directly
// observable, so this is best effort and can race. Note that this can only
// result in false positives (where the algorithm hasn't reached that step yet
// and any functional events haven't actually been handled by the Service
// Worker).
async function ensureFunctionalEventsAreWaiting(registration) {
await (new Promise(resolve => { setTimeout(resolve, 1000); }));
assert_equals(registration.active.scriptURL, normalized_worker_url,
'active worker should be present');
assert_equals(registration.active.state, 'activating',
'active worker should be in activating state');
}
promise_test(async t => {
const registration = await registerAndWaitForActivating(t);
let frame = null;
t.add_cleanup(() => {
if (frame) {
frame.remove();
}
});
// This should block until we message the worker to tell it to complete
// the activate event.
const frameLoadPromise = with_iframe(worker_scope).then(function(f) {
frame = f;
});
await ensureFunctionalEventsAreWaiting(registration);
assert_equals(frame, null, 'frame should not be loaded');
registration.active.postMessage('ACTIVATE');
await frameLoadPromise;
assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalized_worker_url,
'frame should now be loaded and controlled');
assert_equals(registration.active.state, 'activated',
'active worker should be in activated state');
}, 'Navigation fetch events should wait for the activate event to complete.');
promise_test(async t => {
const frame = await with_iframe(worker_scope);
t.add_cleanup(() => { frame.remove(); });
const registration = await registerAndWaitForActivating(t);
// Make the Service Worker control the frame so the frame can perform an
// intercepted fetch.
await (new Promise(resolve => {
navigator.serviceWorker.onmessage = e => {
assert_equals(
frame.contentWindow.navigator.serviceWorker.controller.scriptURL,
normalized_worker_url, 'frame should be controlled');
resolve();
};
registration.active.postMessage('CLAIM');
}));
const fetch_url = `${worker_scope}non/existent/path`;
const expected_fetch_result = 'Hello world';
let fetch_promise_settled = false;
// This should block until we message the worker to tell it to complete
// the activate event.
const fetchPromise = frame.contentWindow.fetch(fetch_url, {
method: 'POST',
body: expected_fetch_result,
}).then(response => {
fetch_promise_settled = true;
return response;
});
await ensureFunctionalEventsAreWaiting(registration);
assert_false(fetch_promise_settled,
"fetch()-ing a Service Worker-controlled scope shouldn't have " +
"settled yet");
registration.active.postMessage('ACTIVATE');
const response = await fetchPromise;
assert_equals(await response.text(), expected_fetch_result,
"Service Worker should have responded to request to" +
fetch_url)
assert_equals(registration.active.state, 'activated',
'active worker should be in activated state');
}, 'Subresource fetch events should wait for the activate event to complete.');
</script>
</body>
|