fetch-waits-for-activate.https.html (4692B)
1 <!DOCTYPE html> 2 <title>Service Worker: Fetch Event Waits for Activate Event</title> 3 <meta name=timeout content=long> 4 <script src="/resources/testharness.js"></script> 5 <script src="resources/testharness-helpers.js"></script> 6 <script src="/resources/testharnessreport.js"></script> 7 <script src="/common/get-host-info.sub.js"></script> 8 <script src="resources/test-helpers.sub.js"></script> 9 <body> 10 <script> 11 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; 110 }); 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.'); 126 127 </script> 128 </body>