| <!DOCTYPE html> |
| <title>Service Worker: Registration-updateViaCache</title> |
| <meta name="timeout" content="long"> |
| <script src="/resources/testharness.js"></script> |
| <script src="resources/testharness-helpers.js"></script> |
| <script src="/resources/testharnessreport.js"></script> |
| <script src="resources/test-helpers.sub.js"></script> |
| <script> |
| const UPDATE_VIA_CACHE_VALUES = [undefined, 'imports', 'all', 'none']; |
| const SCRIPT_URL = 'resources/update-max-aged-worker.py'; |
| const SCOPE = 'resources/blank.html'; |
| |
| async function cleanup() { |
| const reg = await navigator.serviceWorker.getRegistration(SCOPE); |
| if (!reg) return; |
| if (reg.scope == new URL(SCOPE, location).href) { |
| return reg.unregister(); |
| }; |
| } |
| |
| function getScriptTimes(sw, testName) { |
| return new Promise(resolve => { |
| navigator.serviceWorker.addEventListener('message', function listener(event) { |
| if (event.data.test !== testName) return; |
| navigator.serviceWorker.removeEventListener('message', listener); |
| resolve({ |
| mainTime: event.data.mainTime, |
| importTime: event.data.importTime |
| }); |
| }); |
| |
| sw.postMessage(''); |
| }); |
| } |
| |
| // Test creating registrations & triggering an update. |
| for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) { |
| const testName = `register-with-updateViaCache-${updateViaCache}`; |
| |
| promise_test(async t => { |
| await cleanup(); |
| |
| const opts = {scope: SCOPE}; |
| |
| if (updateViaCache) opts.updateViaCache = updateViaCache; |
| |
| const reg = await navigator.serviceWorker.register( |
| `${SCRIPT_URL}?test=${testName}`, |
| opts |
| ); |
| |
| assert_equals(reg.updateViaCache, updateViaCache || 'imports', "reg.updateViaCache"); |
| |
| const sw = reg.installing || reg.waiting || reg.active; |
| await wait_for_state(t, sw, 'activated'); |
| const values = await getScriptTimes(sw, testName); |
| await reg.update(); |
| |
| if (updateViaCache == 'all') { |
| assert_equals(reg.installing, null, "No new service worker"); |
| } |
| else { |
| const newWorker = reg.installing; |
| assert_true(!!newWorker, "New worker installing"); |
| const newValues = await getScriptTimes(newWorker, testName); |
| |
| if (!updateViaCache || updateViaCache == 'imports') { |
| assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); |
| assert_equals(values.importTime, newValues.importTime, "Imported script should be the same"); |
| } |
| else if (updateViaCache == 'none') { |
| assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); |
| assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated"); |
| } |
| else { |
| // We should have handled all of the possible values for updateViaCache. |
| // If this runs, something's gone very wrong. |
| throw Error(`Unexpected updateViaCache value: ${updateViaCache}`); |
| } |
| } |
| |
| await cleanup(); |
| }, testName); |
| } |
| |
| // Test changing the updateViaCache value of an existing registration. |
| for (const updateViaCache1 of UPDATE_VIA_CACHE_VALUES) { |
| for (const updateViaCache2 of UPDATE_VIA_CACHE_VALUES) { |
| const testName = `register-with-updateViaCache-${updateViaCache1}-then-${updateViaCache2}`; |
| |
| promise_test(async t => { |
| await cleanup(); |
| |
| const fullScriptUrl = `${SCRIPT_URL}?test=${testName}`; |
| let opts = {scope: SCOPE}; |
| if (updateViaCache1) opts.updateViaCache = updateViaCache1; |
| |
| const reg = await navigator.serviceWorker.register(fullScriptUrl, opts); |
| |
| const sw = reg.installing; |
| await wait_for_state(t, sw, 'activated'); |
| const values = await getScriptTimes(sw, testName); |
| |
| const frame = await with_iframe(SCOPE); |
| const reg_in_frame = await frame.contentWindow.navigator.serviceWorker.getRegistration(normalizeURL(SCOPE)); |
| assert_equals(reg_in_frame.updateViaCache, updateViaCache1 || 'imports', "reg_in_frame.updateViaCache"); |
| |
| opts = {scope: SCOPE}; |
| if (updateViaCache2) opts.updateViaCache = updateViaCache2; |
| |
| await navigator.serviceWorker.register(fullScriptUrl, opts); |
| |
| const expected_updateViaCache = updateViaCache2 || 'imports'; |
| |
| assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache updated"); |
| // If the update happens via the cache, the scripts will come back byte-identical. |
| // We bypass the byte-identical check if the script URL has changed, but not if |
| // only the updateViaCache value has changed. |
| if (updateViaCache2 == 'all') { |
| assert_equals(reg.installing, null, "No new service worker"); |
| } |
| // If there's no change to the updateViaCache value, register should be a no-op. |
| // The default value should behave as 'imports'. |
| else if ((updateViaCache1 || 'imports') == (updateViaCache2 || 'imports')) { |
| assert_equals(reg.installing, null, "No new service worker"); |
| } |
| else { |
| const newWorker = reg.installing; |
| assert_true(!!newWorker, "New worker installing"); |
| const newValues = await getScriptTimes(newWorker, testName); |
| |
| if (!updateViaCache2 || updateViaCache2 == 'imports') { |
| assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); |
| assert_equals(values.importTime, newValues.importTime, "Imported script should be the same"); |
| } |
| else if (updateViaCache2 == 'none') { |
| assert_not_equals(values.mainTime, newValues.mainTime, "Main script should have updated"); |
| assert_not_equals(values.importTime, newValues.importTime, "Imported script should have updated"); |
| } |
| else { |
| // We should have handled all of the possible values for updateViaCache2. |
| // If this runs, something's gone very wrong. |
| throw Error(`Unexpected updateViaCache value: ${updateViaCache}`); |
| } |
| } |
| |
| // Wait for all registration related tasks on |frame| to complete. |
| await wait_for_activation_on_dummy_scope(t, frame.contentWindow); |
| // The updateViaCache change should have been propagated to all |
| // corresponding JS registration objects. |
| assert_equals(reg_in_frame.updateViaCache, expected_updateViaCache, "reg_in_frame.updateViaCache updated"); |
| frame.remove(); |
| |
| await cleanup(); |
| }, testName); |
| } |
| } |
| |
| // Test accessing updateViaCache of an unregistered registration. |
| for (const updateViaCache of UPDATE_VIA_CACHE_VALUES) { |
| const testName = `access-updateViaCache-after-unregister-${updateViaCache}`; |
| |
| promise_test(async t => { |
| await cleanup(); |
| |
| const opts = {scope: SCOPE}; |
| |
| if (updateViaCache) opts.updateViaCache = updateViaCache; |
| |
| const reg = await navigator.serviceWorker.register( |
| `${SCRIPT_URL}?test=${testName}`, |
| opts |
| ); |
| |
| const expected_updateViaCache = updateViaCache || 'imports'; |
| assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache"); |
| |
| await reg.unregister(); |
| |
| // Keep the original value. |
| assert_equals(reg.updateViaCache, expected_updateViaCache, "reg.updateViaCache"); |
| |
| await cleanup(); |
| }, testName); |
| } |
| |
| promise_test(async t => { |
| await cleanup(); |
| t.add_cleanup(cleanup); |
| |
| const registration = await navigator.serviceWorker.register( |
| 'resources/empty.js', |
| {scope: SCOPE}); |
| assert_equals(registration.updateViaCache, 'imports', |
| 'before update attempt'); |
| |
| const fail = navigator.serviceWorker.register( |
| 'resources/malformed-worker.py?parse-error', |
| {scope: SCOPE, updateViaCache: 'none'}); |
| await promise_rejects(t, new TypeError(), fail); |
| assert_equals(registration.updateViaCache, 'imports', |
| 'after update attempt'); |
| }, 'updateViaCache is not updated if register() rejects'); |
| </script> |