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 |