| OLD | NEW |
| 1 // Adapter for testharness.js-style tests with Service Workers | 1 // Adapter for testharness.js-style tests with Service Workers |
| 2 | 2 |
| 3 function service_worker_unregister_and_register(test, url, scope) { | 3 function service_worker_unregister_and_register(test, url, scope) { |
| 4 if (!scope || scope.length == 0) | 4 if (!scope || scope.length == 0) |
| 5 return Promise.reject(new Error('tests must define a scope')); | 5 return Promise.reject(new Error('tests must define a scope')); |
| 6 | 6 |
| 7 var options = { scope: scope }; | 7 var options = { scope: scope }; |
| 8 return service_worker_unregister(test, scope) | 8 return service_worker_unregister(test, scope) |
| 9 .then(function() { | 9 .then(function() { |
| 10 return navigator.serviceWorker.register(url, options); | 10 return navigator.serviceWorker.register(url, options); |
| 11 }) | 11 }) |
| 12 .catch(unreached_rejection(test, | 12 .catch(unreached_rejection(test, |
| 13 'unregister and register should not fail')); | 13 'unregister and register should not fail')); |
| 14 } | 14 } |
| 15 | 15 |
| 16 function service_worker_unregister(test, documentUrl) { | 16 // This unregisters the registration that precisely matches scope. Use this |
| 17 return navigator.serviceWorker.getRegistration(documentUrl) | 17 // when unregistering by scope. If no registration is found, it just resolves. |
| 18 function service_worker_unregister(test, scope) { |
| 19 var absoluteScope = (new URL(scope, window.location).href); |
| 20 return navigator.serviceWorker.getRegistration(scope) |
| 18 .then(function(registration) { | 21 .then(function(registration) { |
| 19 if (registration) | 22 if (registration && registration.scope === absoluteScope) |
| 20 return registration.unregister(); | 23 return registration.unregister(); |
| 21 }) | 24 }) |
| 22 .catch(unreached_rejection(test, 'unregister should not fail')); | 25 .catch(unreached_rejection(test, 'unregister should not fail')); |
| 23 } | 26 } |
| 24 | 27 |
| 25 function service_worker_unregister_and_done(test, scope) { | 28 function service_worker_unregister_and_done(test, scope) { |
| 26 return service_worker_unregister(test, scope) | 29 return service_worker_unregister(test, scope) |
| 27 .then(test.done.bind(test)); | 30 .then(test.done.bind(test)); |
| 28 } | 31 } |
| 29 | 32 |
| 30 function unreached_fulfillment(test, prefix) { | 33 function unreached_fulfillment(test, prefix) { |
| 31 return test.step_func(function(result) { | 34 return test.step_func(function(result) { |
| 32 var error_prefix = prefix || 'unexpected fulfillment'; | 35 var error_prefix = prefix || 'unexpected fulfillment'; |
| 33 assert_unreached(error_prefix + ': ' + result); | 36 assert_unreached(error_prefix + ': ' + result); |
| 34 }); | 37 }); |
| 35 } | 38 } |
| 36 | 39 |
| 37 // Rejection-specific helper that provides more details | 40 // Rejection-specific helper that provides more details |
| 38 function unreached_rejection(test, prefix) { | 41 function unreached_rejection(test, prefix) { |
| 39 return test.step_func(function(error) { | 42 return test.step_func(function(error) { |
| 40 var reason = error.message || error.name || error; | 43 var reason = error.message || error.name || error; |
| 41 var error_prefix = prefix || 'unexpected rejection'; | 44 var error_prefix = prefix || 'unexpected rejection'; |
| 42 assert_unreached(error_prefix + ': ' + reason); | 45 assert_unreached(error_prefix + ': ' + reason); |
| 43 }); | 46 }); |
| 44 } | 47 } |
| 45 | 48 |
| 46 // Adds an iframe to the document and returns a promise that resolves to the | 49 // Adds an iframe to the document and returns a promise that resolves to the |
| 47 // iframe when it finishes loading. When |options.auto_remove| is set to | 50 // iframe when it finishes loading. The caller is responsible for removing the |
| 48 // |false|, the caller is responsible for removing the iframe | 51 // iframe later if needed. |
| 49 // later. Otherwise, the frame will be removed after all tests are finished. | 52 function with_iframe(url) { |
| 50 function with_iframe(url, options) { | |
| 51 return new Promise(function(resolve) { | 53 return new Promise(function(resolve) { |
| 52 var frame = document.createElement('iframe'); | 54 var frame = document.createElement('iframe'); |
| 53 frame.src = url; | 55 frame.src = url; |
| 54 frame.onload = function() { resolve(frame); }; | 56 frame.onload = function() { resolve(frame); }; |
| 55 document.body.appendChild(frame); | 57 document.body.appendChild(frame); |
| 56 if (typeof options === 'undefined') | |
| 57 options = {}; | |
| 58 if (typeof options.auto_remove === 'undefined') | |
| 59 options.auto_remove = true; | |
| 60 if (options.auto_remove) | |
| 61 add_completion_callback(function() { frame.remove(); }); | |
| 62 }); | |
| 63 } | |
| 64 | |
| 65 function with_sandboxed_iframe(url, sandbox) { | |
| 66 return new Promise(function(resolve) { | |
| 67 var frame = document.createElement('iframe'); | |
| 68 frame.sandbox = sandbox; | |
| 69 frame.src = url; | |
| 70 frame.onload = function() { resolve(frame); }; | |
| 71 document.body.appendChild(frame); | |
| 72 }); | 58 }); |
| 73 } | 59 } |
| 74 | 60 |
| 75 function normalizeURL(url) { | 61 function normalizeURL(url) { |
| 76 return new URL(url, self.location).toString().replace(/#.*$/, ''); | 62 return new URL(url, self.location).toString().replace(/#.*$/, ''); |
| 77 } | 63 } |
| 78 | 64 |
| 79 function wait_for_update(test, registration) { | 65 function wait_for_update(test, registration) { |
| 80 if (!registration || registration.unregister == undefined) { | 66 if (!registration || registration.unregister == undefined) { |
| 81 return Promise.reject(new Error( | 67 return Promise.reject(new Error( |
| (...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 142 })); | 128 })); |
| 143 })); | 129 })); |
| 144 } | 130 } |
| 145 | 131 |
| 146 // Declare a test that runs entirely in the ServiceWorkerGlobalScope. The |url| | 132 // Declare a test that runs entirely in the ServiceWorkerGlobalScope. The |url| |
| 147 // is the service worker script URL. This function: | 133 // is the service worker script URL. This function: |
| 148 // - Instantiates a new test with the description specified in |description|. | 134 // - Instantiates a new test with the description specified in |description|. |
| 149 // The test will succeed if the specified service worker can be successfully | 135 // The test will succeed if the specified service worker can be successfully |
| 150 // registered and installed. | 136 // registered and installed. |
| 151 // - Creates a new ServiceWorker registration with a scope unique to the current | 137 // - Creates a new ServiceWorker registration with a scope unique to the current |
| 152 // document URL and the script URL. This allows more than one | 138 // document URL. Note that this doesn't allow more than one |
| 153 // service_worker_test() to be run from the same document. | 139 // service_worker_test() to be run from the same document. |
| 154 // - Waits for the new worker to begin installing. | 140 // - Waits for the new worker to begin installing. |
| 155 // - Imports tests results from tests running inside the ServiceWorker. | 141 // - Imports tests results from tests running inside the ServiceWorker. |
| 156 function service_worker_test(url, description) { | 142 function service_worker_test(url, description) { |
| 157 // If the document URL is https://example.com/document and the script URL is | 143 // If the document URL is https://example.com/document and the script URL is |
| 158 // https://example.com/script/worker.js, then the scope would be | 144 // https://example.com/script/worker.js, then the scope would be |
| 159 // https://example.com/script/scope/document/script/worker.js. | 145 // https://example.com/script/scope/document. |
| 160 var document_path = window.location.pathname; | 146 var scope = new URL('scope' + window.location.pathname, |
| 161 var script_path = new URL(url, window.location).pathname; | |
| 162 var scope = new URL('scope' + document_path + script_path, | |
| 163 new URL(url, window.location)).toString(); | 147 new URL(url, window.location)).toString(); |
| 164 promise_test(function(test) { | 148 promise_test(function(test) { |
| 165 return service_worker_unregister_and_register(test, url, scope) | 149 return service_worker_unregister_and_register(test, url, scope) |
| 166 .then(function(registration) { | 150 .then(function(registration) { |
| 167 add_completion_callback(function() { | 151 add_completion_callback(function() { |
| 168 registration.unregister(); | 152 registration.unregister(); |
| 169 }); | 153 }); |
| 170 return wait_for_update(test, registration) | 154 return wait_for_update(test, registration) |
| 171 .then(function(worker) { | 155 .then(function(worker) { |
| 172 return fetch_tests_from_worker(worker); | 156 return fetch_tests_from_worker(worker); |
| 173 }); | 157 }); |
| 174 }); | 158 }); |
| 175 }, description); | 159 }, description); |
| 176 } | 160 } |
| 177 | 161 |
| 178 function base_path() { | 162 function base_path() { |
| 179 return location.pathname.replace(/\/[^\/]*$/, '/'); | 163 return location.pathname.replace(/\/[^\/]*$/, '/'); |
| 180 } | 164 } |
| 181 | 165 |
| 182 function test_login(test, origin, username, password, cookie) { | 166 function test_login(test, origin, username, password, cookie) { |
| 183 return new Promise(function(resolve, reject) { | 167 return new Promise(function(resolve, reject) { |
| 184 with_iframe( | 168 with_iframe( |
| 185 origin + | 169 origin + base_path() + |
| 186 '/serviceworker/resources/fetch-access-control-login.html') | 170 'resources/fetch-access-control-login.html') |
| 187 .then(test.step_func(function(frame) { | 171 .then(test.step_func(function(frame) { |
| 188 var channel = new MessageChannel(); | 172 var channel = new MessageChannel(); |
| 189 channel.port1.onmessage = test.step_func(function() { | 173 channel.port1.onmessage = test.step_func(function() { |
| 190 frame.remove(); | 174 frame.remove(); |
| 191 resolve(); | 175 resolve(); |
| 192 }); | 176 }); |
| 193 frame.contentWindow.postMessage( | 177 frame.contentWindow.postMessage( |
| 194 {username: username, password: password, cookie: cookie}, | 178 {username: username, password: password, cookie: cookie}, |
| 195 origin, [channel.port2]); | 179 origin, [channel.port2]); |
| 196 })); | 180 })); |
| 197 }); | 181 }); |
| 198 } | 182 } |
| 199 | 183 |
| 200 function login(test, local, remote) { | 184 function test_websocket(test, frame, url) { |
| 201 var suffix = (local.indexOf("https") != -1) ? "s": ""; | 185 return new Promise(function(resolve, reject) { |
| 202 return test_login(test, local, 'username1' + suffix, 'password1' + suffix, | 186 var ws = new frame.contentWindow.WebSocket(url, ['echo', 'chat']); |
| 203 'cookie1') | 187 var openCalled = false; |
| 188 ws.addEventListener('open', test.step_func(function(e) { |
| 189 assert_equals(ws.readyState, 1, "The WebSocket should be open"); |
| 190 openCalled = true; |
| 191 ws.close(); |
| 192 }), true); |
| 193 |
| 194 ws.addEventListener('close', test.step_func(function(e) { |
| 195 assert_true(openCalled, "The WebSocket should be closed after being op
ened"); |
| 196 resolve(); |
| 197 }), true); |
| 198 |
| 199 ws.addEventListener('error', reject); |
| 200 }); |
| 201 } |
| 202 |
| 203 function login(test) { |
| 204 return test_login(test, 'http://{{domains[www1]}}:{{ports[http][0]}}', |
| 205 'username1', 'password1', 'cookie1') |
| 204 .then(function() { | 206 .then(function() { |
| 205 return test_login(test, remote, 'username2' + suffix, | 207 return test_login(test, 'http://{{host}}:{{ports[http][0]}}', |
| 206 'password2' + suffix, 'cookie2'); | 208 'username2', 'password2', 'cookie2'); |
| 207 }); | 209 }); |
| 208 } | 210 } |
| 211 |
| 212 function login_https(test) { |
| 213 return test_login(test, 'https://{{domains[www1]}}:{{ports[https][0]}}', |
| 214 'username1s', 'password1s', 'cookie1') |
| 215 .then(function() { |
| 216 return test_login(test, 'https://{{host}}:{{ports[https][0]}}', |
| 217 'username2s', 'password2s', 'cookie2'); |
| 218 }); |
| 219 } |
| 220 |
| 221 function websocket(test, frame) { |
| 222 return test_websocket(test, frame, get_websocket_url()); |
| 223 } |
| 224 |
| 225 function get_websocket_url() { |
| 226 return 'wss://{{host}}:{{ports[wss][0]}}/echo'; |
| 227 } |
| OLD | NEW |