|
9 | 9 | <body>
|
10 | 10 | <script>
|
11 | 11 |
|
12 |
| -var worker = 'resources/fetch-waits-for-activate-worker.js'; |
13 |
| -var expected_url = normalizeURL(worker); |
14 |
| -var scope = 'resources/fetch-waits-for-activate/'; |
15 |
| - |
16 |
| -promise_test(function(t) { |
17 |
| - var registration; |
18 |
| - var frameLoadPromise; |
19 |
| - var frame; |
20 |
| - return service_worker_unregister_and_register(t, worker, scope).then(function(reg) { |
21 |
| - t.add_cleanup(function() { |
22 |
| - return service_worker_unregister(t, scope); |
23 |
| - }); |
24 |
| - |
25 |
| - registration = reg; |
26 |
| - return wait_for_state(t, reg.installing, 'activating'); |
27 |
| - }).then(function() { |
28 |
| - assert_equals(registration.active.scriptURL, expected_url, |
29 |
| - 'active worker should be present'); |
30 |
| - assert_equals(registration.active.state, 'activating', |
31 |
| - 'active worker should be in activating state'); |
32 |
| - |
33 |
| - // This should block until we message the worker to tell it to complete |
34 |
| - // the activate event. |
35 |
| - frameLoadPromise = with_iframe(scope).then(function(f) { |
36 |
| - frame = f; |
37 |
| - }); |
38 |
| - |
39 |
| - // Wait some time to allow frame loading to proceed. It should not, |
40 |
| - // however, if the fetch event is blocked on the activate. I don't |
41 |
| - // see any way to force this race without a timeout, unfortunately. |
42 |
| - return new Promise(function(resolve) { |
43 |
| - setTimeout(resolve, 1000); |
44 |
| - }); |
45 |
| - }).then(function() { |
46 |
| - assert_equals(frame, undefined, 'frame should not be loaded'); |
47 |
| - assert_equals(registration.active.scriptURL, expected_url, |
48 |
| - 'active worker should be present'); |
49 |
| - assert_equals(registration.active.state, 'activating', |
50 |
| - 'active worker should be in activating state'); |
51 |
| - |
52 |
| - // This signals the activate event to complete. The frame should now |
53 |
| - // load. |
54 |
| - registration.active.postMessage('GO'); |
55 |
| - return frameLoadPromise; |
56 |
| - }).then(function() { |
57 |
| - assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL, |
58 |
| - expected_url, 'frame should now be loaded and controlled'); |
59 |
| - assert_equals(registration.active.state, 'activated', |
60 |
| - 'active worker should be in activated state'); |
61 |
| - frame.remove(); |
| 12 | +const worker_url = 'resources/fetch-waits-for-activate-worker.js'; |
| 13 | +const normalized_worker_url = normalizeURL(worker_url); |
| 14 | +const worker_scope = 'resources/fetch-waits-for-activate/'; |
| 15 | + |
| 16 | +// Resolves with the Service Worker's registration once it's reached the |
| 17 | +// "activating" state. (The Service Worker should remain "activating" until |
| 18 | +// explicitly told advance to the "activated" state). |
| 19 | +async function registerAndWaitForActivating(t) { |
| 20 | + const registration = await service_worker_unregister_and_register( |
| 21 | + t, worker_url, worker_scope); |
| 22 | + t.add_cleanup(() => service_worker_unregister(t, worker_scope)); |
| 23 | + |
| 24 | + await wait_for_state(t, registration.installing, 'activating'); |
| 25 | + |
| 26 | + return registration; |
| 27 | +} |
| 28 | + |
| 29 | +// Attempts to ensure that the "Handle Fetch" algorithm has reached the step |
| 30 | +// |
| 31 | +// "If activeWorker’s state is "activating", wait for activeWorker’s state to |
| 32 | +// become "activated"." |
| 33 | +// |
| 34 | +// by waiting for some time to pass. |
| 35 | +// |
| 36 | +// WARNING: whether the algorithm has reached that step isn't directly |
| 37 | +// observable, so this is best effort and can race. Note that this can only |
| 38 | +// result in false positives (where the algorithm hasn't reached that step yet |
| 39 | +// and any functional events haven't actually been handled by the Service |
| 40 | +// Worker). |
| 41 | +async function ensureFunctionalEventsAreWaiting(registration) { |
| 42 | + await (new Promise(resolve => { setTimeout(resolve, 1000); })); |
| 43 | + |
| 44 | + assert_equals(registration.active.scriptURL, normalized_worker_url, |
| 45 | + 'active worker should be present'); |
| 46 | + assert_equals(registration.active.state, 'activating', |
| 47 | + 'active worker should be in activating state'); |
| 48 | +} |
| 49 | + |
| 50 | +promise_test(async t => { |
| 51 | + const registration = await registerAndWaitForActivating(t); |
| 52 | + |
| 53 | + let frame = null; |
| 54 | + t.add_cleanup(() => { |
| 55 | + if (frame) { |
| 56 | + frame.remove(); |
| 57 | + } |
| 58 | + }); |
| 59 | + |
| 60 | + // This should block until we message the worker to tell it to complete |
| 61 | + // the activate event. |
| 62 | + const frameLoadPromise = with_iframe(worker_scope).then(function(f) { |
| 63 | + frame = f; |
| 64 | + }); |
| 65 | + |
| 66 | + await ensureFunctionalEventsAreWaiting(registration); |
| 67 | + assert_equals(frame, null, 'frame should not be loaded'); |
| 68 | + |
| 69 | + registration.active.postMessage('ACTIVATE'); |
| 70 | + |
| 71 | + await frameLoadPromise; |
| 72 | + assert_equals(frame.contentWindow.navigator.serviceWorker.controller.scriptURL, |
| 73 | + normalized_worker_url, |
| 74 | + 'frame should now be loaded and controlled'); |
| 75 | + assert_equals(registration.active.state, 'activated', |
| 76 | + 'active worker should be in activated state'); |
| 77 | +}, 'Navigation fetch events should wait for the activate event to complete.'); |
| 78 | + |
| 79 | +promise_test(async t => { |
| 80 | + const frame = await with_iframe(worker_scope); |
| 81 | + t.add_cleanup(() => { frame.remove(); }); |
| 82 | + |
| 83 | + const registration = await registerAndWaitForActivating(t); |
| 84 | + |
| 85 | + // Make the Service Worker control the frame so the frame can perform an |
| 86 | + // intercepted fetch. |
| 87 | + await (new Promise(resolve => { |
| 88 | + navigator.serviceWorker.onmessage = e => { |
| 89 | + assert_equals( |
| 90 | + frame.contentWindow.navigator.serviceWorker.controller.scriptURL, |
| 91 | + normalized_worker_url, 'frame should be controlled'); |
| 92 | + resolve(); |
| 93 | + }; |
| 94 | + |
| 95 | + registration.active.postMessage('CLAIM'); |
| 96 | + })); |
| 97 | + |
| 98 | + const fetch_url = `${worker_scope}non/existent/path`; |
| 99 | + const expected_fetch_result = 'Hello world'; |
| 100 | + let fetch_promise_settled = false; |
| 101 | + |
| 102 | + // This should block until we message the worker to tell it to complete |
| 103 | + // the activate event. |
| 104 | + const fetchPromise = frame.contentWindow.fetch(fetch_url, { |
| 105 | + method: 'POST', |
| 106 | + body: expected_fetch_result, |
| 107 | + }).then(response => { |
| 108 | + fetch_promise_settled = true; |
| 109 | + return response; |
62 | 110 | });
|
63 |
| -}, 'Fetch events should wait for the activate event to complete.'); |
| 111 | + |
| 112 | + await ensureFunctionalEventsAreWaiting(registration); |
| 113 | + assert_false(fetch_promise_settled, |
| 114 | + "fetch()-ing a Service Worker-controlled scope shouldn't have " + |
| 115 | + "settled yet"); |
| 116 | + |
| 117 | + registration.active.postMessage('ACTIVATE'); |
| 118 | + |
| 119 | + const response = await fetchPromise; |
| 120 | + assert_equals(await response.text(), expected_fetch_result, |
| 121 | + "Service Worker should have responded to request to" + |
| 122 | + fetch_url) |
| 123 | + assert_equals(registration.active.state, 'activated', |
| 124 | + 'active worker should be in activated state'); |
| 125 | +}, 'Subresource fetch events should wait for the activate event to complete.'); |
64 | 126 |
|
65 | 127 | </script>
|
66 | 128 | </body>
|
0 commit comments