fetch-event-within-sw-manual.https.html (3876B)
1 <!DOCTYPE html> 2 <script src="/resources/testharness.js"></script> 3 <script src="/resources/testharnessreport.js"></script> 4 <script src="/common/get-host-info.sub.js"></script> 5 <script src="resources/test-helpers.sub.js"></script> 6 <body> 7 <script> 8 const worker = 'resources/fetch-event-within-sw-worker.js'; 9 10 function wait(ms) { 11 return new Promise(r => setTimeout(r, ms)); 12 } 13 14 function reset() { 15 for (const iframe of [...document.querySelectorAll('.test-iframe')]) { 16 iframe.remove(); 17 } 18 return navigator.serviceWorker.getRegistrations().then(registrations => { 19 return Promise.all(registrations.map(r => r.unregister())); 20 }).then(() => caches.keys()).then(cacheKeys => { 21 return Promise.all(cacheKeys.map(c => caches.delete(c))); 22 }); 23 } 24 25 add_completion_callback(reset); 26 27 function regReady(reg) { 28 return new Promise((resolve, reject) => { 29 if (reg.active) { 30 resolve(); 31 return; 32 } 33 const nextWorker = reg.waiting || reg.installing; 34 35 nextWorker.addEventListener('statechange', () => { 36 if (nextWorker.state == 'redundant') { 37 reject(Error(`Service worker failed to install`)); 38 return; 39 } 40 if (nextWorker.state == 'activated') { 41 resolve(); 42 } 43 }); 44 }); 45 } 46 47 function getCookies() { 48 return new Map( 49 document.cookie 50 .split(/;/g) 51 .map(c => c.trim().split('=').map(s => s.trim())) 52 ); 53 } 54 55 function registerSwAndOpenFrame() { 56 return reset().then(() => navigator.serviceWorker.register(worker, {scope: 'resources/'})) 57 .then(reg => regReady(reg)) 58 .then(() => with_iframe('resources/simple.html')); 59 } 60 61 function raceBroadcastAndCookie(channel, cookie) { 62 const initialCookie = getCookies().get(cookie); 63 let done = false; 64 65 return Promise.race([ 66 new Promise(resolve => { 67 const bc = new BroadcastChannel(channel); 68 bc.onmessage = () => { 69 bc.close(); 70 resolve('broadcast'); 71 }; 72 }), 73 (function checkCookie() { 74 // Stop polling if the broadcast channel won 75 if (done == true) return; 76 if (getCookies().get(cookie) != initialCookie) return 'cookie'; 77 78 return wait(200).then(checkCookie); 79 }()) 80 ]).then(val => { 81 done = true; 82 return val; 83 }); 84 } 85 86 promise_test(() => { 87 return Notification.requestPermission().then(permission => { 88 if (permission != "granted") { 89 throw Error('You must allow notifications for this origin before running this test.'); 90 } 91 return registerSwAndOpenFrame(); 92 }).then(iframe => { 93 return Promise.resolve().then(() => { 94 // In this test, the service worker will ping the 'icon-request' channel 95 // if it intercepts a request for 'notification_icon.py'. If the request 96 // reaches the server it sets the 'notification' cookie to the value given 97 // in the URL. "raceBroadcastAndCookie" monitors both and returns which 98 // happens first. 99 const race = raceBroadcastAndCookie('icon-request', 'notification'); 100 const notification = new iframe.contentWindow.Notification('test', { 101 icon: `notification_icon.py?set-cookie-notification=${Math.random()}` 102 }); 103 notification.close(); 104 105 return race.then(winner => { 106 assert_equals(winner, 'broadcast', 'The service worker intercepted the from-window notification icon request'); 107 }); 108 }).then(() => { 109 // Similar race to above, but this time the service worker requests the 110 // notification. 111 const race = raceBroadcastAndCookie('icon-request', 'notification'); 112 iframe.contentWindow.fetch(`show-notification?set-cookie-notification=${Math.random()}`); 113 114 return race.then(winner => { 115 assert_equals(winner, 'broadcast', 'The service worker intercepted the from-service-worker notification icon request'); 116 }); 117 }) 118 }); 119 }, `Notification requests intercepted both from window and SW`); 120 121 </script> 122 </body>