windowclient-navigate.https.html (5471B)
1 <!DOCTYPE html> 2 <title>Service Worker: WindowClient.navigate() tests</title> 3 <meta name="timeout" content="long"> 4 <script src="/resources/testharness.js"></script> 5 <script src="/resources/testharnessreport.js"></script> 6 <script src="/common/get-host-info.sub.js"></script> 7 <script src="resources/test-helpers.sub.js"></script> 8 <body> 9 <script> 10 'use strict'; 11 12 const SCOPE = 'resources/blank.html'; 13 const SCRIPT_URL = 'resources/windowclient-navigate-worker.js'; 14 const CROSS_ORIGIN_URL = 15 get_host_info()['HTTPS_REMOTE_ORIGIN'] + base_path() + 'resources/blank.html'; 16 17 navigateTest({ 18 description: 'normal', 19 destUrl: 'blank.html?navigate', 20 expected: normalizeURL(SCOPE) + '?navigate', 21 }); 22 23 navigateTest({ 24 description: 'blank url', 25 destUrl: '', 26 expected: normalizeURL(SCRIPT_URL) 27 }); 28 29 navigateTest({ 30 description: 'in scope but not controlled test on installing worker', 31 destUrl: 'blank.html?navigate', 32 expected: 'TypeError', 33 waitState: 'installing', 34 }); 35 36 navigateTest({ 37 description: 'in scope but not controlled test on active worker', 38 destUrl: 'blank.html?navigate', 39 expected: 'TypeError', 40 controlled: false, 41 }); 42 43 navigateTest({ 44 description: 'out of scope', 45 srcUrl: '/common/blank.html', 46 destUrl: 'blank.html?navigate', 47 expected: 'TypeError', 48 }); 49 50 navigateTest({ 51 description: 'cross origin url', 52 destUrl: CROSS_ORIGIN_URL, 53 expected: null 54 }); 55 56 navigateTest({ 57 description: 'invalid url (http://[example.com])', 58 destUrl: 'http://[example].com', 59 expected: 'TypeError' 60 }); 61 62 navigateTest({ 63 description: 'invalid url (view-source://example.com)', 64 destUrl: 'view-source://example.com', 65 expected: 'TypeError' 66 }); 67 68 navigateTest({ 69 description: 'invalid url (file:///)', 70 destUrl: 'file:///', 71 expected: 'TypeError' 72 }); 73 74 navigateTest({ 75 description: 'invalid url (about:blank)', 76 destUrl: 'about:blank', 77 expected: 'TypeError' 78 }); 79 80 navigateTest({ 81 description: 'navigate on a top-level window client', 82 destUrl: 'blank.html?navigate', 83 srcUrl: 'resources/loaded.html', 84 scope: 'resources/loaded.html', 85 expected: normalizeURL(SCOPE) + '?navigate', 86 frameType: 'top-level' 87 }); 88 89 async function createFrame(t, parameters) { 90 if (parameters.frameType === 'top-level') { 91 // Wait for window.open is completed. 92 await new Promise(resolve => { 93 const win = window.open(parameters.srcUrl); 94 t.add_cleanup(() => win.close()); 95 window.addEventListener('message', (e) => { 96 if (e.data.type === 'LOADED') { 97 resolve(); 98 } 99 }); 100 }); 101 } 102 103 if (parameters.frameType === 'nested') { 104 const frame = await with_iframe(parameters.srcUrl); 105 t.add_cleanup(() => frame.remove()); 106 } 107 } 108 109 function navigateTest(overrideParameters) { 110 // default parameters 111 const parameters = { 112 description: null, 113 srcUrl: SCOPE, 114 destUrl: null, 115 expected: null, 116 waitState: 'activated', 117 scope: SCOPE, 118 controlled: true, 119 // `frameType` can be 'nested' for an iframe WindowClient or 'top-level' for 120 // a main frame WindowClient. 121 frameType: 'nested' 122 }; 123 124 for (const key in overrideParameters) 125 parameters[key] = overrideParameters[key]; 126 127 promise_test(async function(t) { 128 let pausedLifecyclePort; 129 let scriptUrl = SCRIPT_URL; 130 131 // For in-scope-but-not-controlled test on installing worker, 132 // if the waitState is "installing", then append the query to scriptUrl. 133 if (parameters.waitState === 'installing') { 134 scriptUrl += '?' + parameters.waitState; 135 136 navigator.serviceWorker.addEventListener('message', (event) => { 137 if (event.data.port) { 138 pausedLifecyclePort = event.data.port; 139 } 140 }); 141 } 142 143 t.add_cleanup(() => { 144 // Some tests require that the worker remain in a given lifecycle phase. 145 // "Clean up" logic for these tests requires signaling the worker to 146 // release the hold; this allows the worker to be properly discarded 147 // prior to the execution of additional tests. 148 if (pausedLifecyclePort) { 149 // The value of the posted message is inconsequential. A string is 150 // specified here solely to aid in test debugging. 151 pausedLifecyclePort.postMessage('continue lifecycle'); 152 } 153 }); 154 155 // Create a frame that is not controlled by a service worker. 156 if (!parameters.controlled) { 157 await createFrame(t, parameters); 158 } 159 160 const registration = await service_worker_unregister_and_register( 161 t, scriptUrl, parameters.scope); 162 const serviceWorker = registration.installing; 163 await wait_for_state(t, serviceWorker, parameters.waitState); 164 t.add_cleanup(() => registration.unregister()); 165 166 // Create a frame after a service worker is registered so that the frmae is 167 // controlled by an active service worker. 168 if (parameters.controlled) { 169 await createFrame(t, parameters); 170 } 171 172 const response = await new Promise(resolve => { 173 const channel = new MessageChannel(); 174 channel.port1.onmessage = t.step_func(resolve); 175 serviceWorker.postMessage({ 176 port: channel.port2, 177 url: parameters.destUrl, 178 clientUrl: new URL(parameters.srcUrl, location).toString(), 179 frameType: parameters.frameType, 180 expected: parameters.expected, 181 description: parameters.description, 182 }, [channel.port2]); 183 }); 184 185 assert_equals(response.data, null); 186 await fetch_tests_from_worker(serviceWorker); 187 }, parameters.description); 188 } 189 </script> 190 </body>