detached-context.https.html (4895B)
1 <!DOCTYPE html> 2 <meta charset="utf-8"> 3 <title>Service WorkerRegistration from a removed iframe</title> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="resources/test-helpers.sub.js"></script> 7 <body> 8 </body> 9 <script> 10 // NOTE: This file tests corner case behavior that might not be defined in the 11 // spec. See https://github.com/w3c/ServiceWorker/issues/1221 12 13 promise_test(t => { 14 const url = 'resources/blank.html'; 15 const scope_for_iframe = 'removed-registration' 16 const scope_for_main = 'resources/' + scope_for_iframe; 17 const script = 'resources/empty-worker.js'; 18 let frame; 19 let resolvedCount = 0; 20 21 return service_worker_unregister(t, scope_for_main) 22 .then(() => { 23 return with_iframe(url); 24 }) 25 .then(f => { 26 frame = f; 27 return navigator.serviceWorker.register(script, 28 {scope: scope_for_main}); 29 }) 30 .then(r => { 31 add_completion_callback(() => { r.unregister(); }); 32 return wait_for_state(t, r.installing, 'activated'); 33 }) 34 .then(() => { 35 return frame.contentWindow.navigator.serviceWorker.getRegistration( 36 scope_for_iframe); 37 }) 38 .then(r => { 39 frame.remove(); 40 assert_equals(r.installing, null); 41 assert_equals(r.waiting, null); 42 assert_equals(r.active.state, 'activated'); 43 assert_equals(r.scope, normalizeURL(scope_for_main)); 44 r.onupdatefound = () => { /* empty */ }; 45 46 // We want to verify that unregister() and update() do not 47 // resolve on a detached registration. We can't check for 48 // an explicit rejection, though, because not all browsers 49 // fire rejection callbacks on detached promises. Instead 50 // we wait for a sample scope to install, activate, and 51 // unregister before declaring that the promises did not 52 // resolve. 53 r.unregister().then(() => resolvedCount += 1, 54 () => {}); 55 r.update().then(() => resolvedCount += 1, 56 () => {}); 57 return wait_for_activation_on_sample_scope(t, window); 58 }) 59 .then(() => { 60 assert_equals(resolvedCount, 0, 61 'methods called on a detached registration should not resolve'); 62 frame.remove(); 63 }) 64 }, 'accessing a ServiceWorkerRegistration from a removed iframe'); 65 66 promise_test(t => { 67 const script = 'resources/empty-worker.js'; 68 const scope = 'resources/scope/serviceworker-from-detached'; 69 70 return service_worker_unregister_and_register(t, script, scope) 71 .then(registration => { 72 add_completion_callback(() => { registration.unregister(); }); 73 return wait_for_state(t, registration.installing, 'activated'); 74 }) 75 .then(() => { return with_iframe(scope); }) 76 .then(frame => { 77 const worker = frame.contentWindow.navigator.serviceWorker.controller; 78 const ctor = frame.contentWindow.DOMException; 79 frame.remove(); 80 assert_equals(worker.scriptURL, normalizeURL(script)); 81 assert_equals(worker.state, 'activated'); 82 worker.onstatechange = () => { /* empty */ }; 83 assert_throws_dom( 84 'InvalidStateError', 85 ctor, 86 () => { worker.postMessage(''); }, 87 'postMessage on a detached client should throw an exception.'); 88 }); 89 }, 'accessing a ServiceWorker object from a removed iframe'); 90 91 promise_test(t => { 92 const iframe = document.createElement('iframe'); 93 iframe.src = 'resources/blank.html'; 94 document.body.appendChild(iframe); 95 const f = iframe.contentWindow.Function; 96 function get_navigator() { 97 return f('return navigator')(); 98 } 99 return new Promise(resolve => { 100 assert_equals(iframe.contentWindow.navigator, get_navigator()); 101 iframe.src = 'resources/blank.html?navigate-to-new-url'; 102 iframe.onload = resolve; 103 }).then(function() { 104 assert_not_equals(get_navigator().serviceWorker, null); 105 assert_equals( 106 get_navigator().serviceWorker, 107 iframe.contentWindow.navigator.serviceWorker); 108 iframe.remove(); 109 }); 110 }, 'accessing navigator.serviceWorker on a detached iframe'); 111 112 test(t => { 113 const iframe = document.createElement('iframe'); 114 iframe.src = 'resources/blank.html'; 115 document.body.appendChild(iframe); 116 const f = iframe.contentWindow.Function; 117 function get_navigator() { 118 return f('return navigator')(); 119 } 120 assert_not_equals(get_navigator().serviceWorker, null); 121 iframe.remove(); 122 assert_not_equals(get_navigator().serviceWorker, null); 123 }, 'accessing navigator on a removed frame'); 124 </script>