From 6dc905f211c2ea39fdd5c6e356cf0f431a17dd89 Mon Sep 17 00:00:00 2001 From: Jeff Posnick Date: Wed, 21 Sep 2016 21:29:05 -0400 Subject: [PATCH 1/2] Refactors the tests of cache expiration options. --- test/browser-tests/options/options.js | 264 ++++++------------ .../serviceworkers/max-cache-age-global.js | 2 +- .../serviceworkers/max-cache-age-route.js | 2 +- .../max-entries-cache-age-global.js | 2 +- .../max-entries-cache-age-route.js | 22 -- .../serviceworkers/max-entries-global.js | 2 +- .../serviceworkers/max-entries-route.js | 2 +- 7 files changed, 91 insertions(+), 205 deletions(-) delete mode 100644 test/browser-tests/options/serviceworkers/max-entries-cache-age-route.js diff --git a/test/browser-tests/options/options.js b/test/browser-tests/options/options.js index 4bcdafb..ddd968a 100644 --- a/test/browser-tests/options/options.js +++ b/test/browser-tests/options/options.js @@ -20,209 +20,117 @@ describe('Test Options Parameters', function() { const swUtils = window.goog.swUtils; - const serviceWorkersFolder = '/test/browser-tests/options/serviceworkers'; - - const pausePromise = timeout => { - return new Promise(function(resolve) { - setTimeout(resolve, timeout); - }); + const serviceWorkersFolder = '/test/browser-tests/options/serviceworkers/'; + + /** + * @param {Number} timeout The number of milliseconds to pause for. + * @returns {Promise} A promise that resolves after a specified delay. + */ + const pause = timeout => { + return new Promise(resolve => setTimeout(resolve, timeout)); }; - const cleanUpIDB = () => { - return new Promise(resolve => { - const req = indexedDB.deleteDatabase('sw-toolbox-options-test'); - req.onsuccess = () => resolve(); - req.onerror = () => resolve(); - req.onblocked = () => resolve(); - }); + /** + * Performs a series of fetch() calls on an iframe, then pauses. + * @param {iframe} iframe The iframe whose contentWindow will be used to fetch(). + * @param {Array.} urls The URLs to fetch. + * @returns {Promise} A promise that resolves following the fetches and a delay. + */ + const sequentialFetch = (iframe, urls) => { + return urls.reduce((chain, url) => { + return chain.then(() => iframe.contentWindow.fetch(url)); + }, Promise.resolve()).then(() => pause(500)); }; - beforeEach(function() { - // Clear IndexDB - Used for max age / max Entries - return cleanUpIDB(); + /** + * Prepends a common prefix to several partial URLs, and returns the absolute URLs. + * @param urls The partial URLs. + * @returns {Array.} The absolute URLs. + */ + const absoluteTestDataFileUrls = urls => urls.map(url => { + return String(new URL(url, `${location.origin}/test/data/files/`)); }); - after(function() { - // Clear IndexDB - Used for max age / max Entries - return cleanUpIDB(); - }); + /** + * Asserts that the keys in cachedAssets match exactly the list of expected URLs. + * @param {Object} cachedAssets The result from a call to swUtils.getAllCachedAssets(). + * @param {Array.} expectedUrls The expected cache contents. + */ + const assertCacheContents = (cachedAssets, expectedUrls) => { + const expectedLength = expectedUrls.length; + const cachedUrls = Object.keys(cachedAssets); + const filteredUrls = cachedUrls.filter(url => expectedUrls.includes(url)); + filteredUrls.should.have.lengthOf(expectedLength); + cachedUrls.should.have.lengthOf(expectedLength); + }; describe('options.cache.maxEntries', function() { it('should cache according to global maxEntries option', function() { - const urls = [ - '/test/data/files/text-1.txt', - '/test/data/files/text-2.txt', - '/test/data/files/text-3.txt' - ]; - - return swUtils.activateSW(serviceWorkersFolder + '/max-entries-global.js') - .then(iframe => { - return urls.reduce((promiseChain, url) => { - return promiseChain - .then(() => { - // Pause is to ensure the cache has had time to finish. - return iframe.contentWindow.fetch(url) - .then(pausePromise.bind(null, 500)); - }); - }, Promise.resolve()); - }) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(2); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-2.txt').should.not.equal(-1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-3.txt').should.not.equal(-1); - }); + const urls = absoluteTestDataFileUrls([ + 'text-1.txt', 'text-2.txt', 'text-3.txt']); + + const swFile = `${serviceWorkersFolder}max-entries-global.js`; + return swUtils.activateSW(swFile).then(iframe => { + return sequentialFetch(iframe, urls) + .then(() => swUtils.getAllCachedAssets(iframe.src)); + }).then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(1))); }); it('should cache according to route specific maxEntries option', function() { - const urls = [ - '/test/data/files/text-1.txt', - '/test/data/files/text-2.txt', - '/test/data/files/text-3.txt' - ]; - - return swUtils.activateSW(serviceWorkersFolder + '/max-entries-route.js') - .then(iframe => { - return urls.reduce((promiseChain, url) => { - return promiseChain - .then(() => { - // Pause is to ensure the cache has had time to finish. - return iframe.contentWindow.fetch(url) - .then(pausePromise.bind(null, 500)); - }); - }, Promise.resolve()); - }) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(2); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-2.txt').should.not.equal(-1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-3.txt').should.not.equal(-1); - }); + const urls = absoluteTestDataFileUrls([ + 'text-1.txt', 'text-2.txt', 'text-3.txt']); + + const swFile =`${serviceWorkersFolder}max-entries-route.js`; + return swUtils.activateSW(swFile).then(iframe => { + return sequentialFetch(iframe, urls) + .then(() => swUtils.getAllCachedAssets(iframe.src)); + }).then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(1))); }); }); describe('options.cache.maxAgeSeconds', function() { it('should cache according to global maxAgeSeconds option', function() { - const urls = [ - '/test/data/files/text-1.txt', - '/test/data/files/text-2.txt', - '/test/data/files/text-3.txt' - ]; - - return swUtils.activateSW(serviceWorkersFolder + '/max-cache-age-global.js') - .then(iframe => { - return urls.reduce((promiseChain, url, index) => { - return promiseChain - .then(() => { - return iframe.contentWindow.fetch(url) - .then(() => { - if (index === 0) { - return pausePromise(1500); - } - }); - }); - }, Promise.resolve()); - }) - .then(() => { - // Give cache time to settle - return pausePromise(500); - }) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(2); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-2.txt').should.not.equal(-1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-3.txt').should.not.equal(-1); - }); + const urls = absoluteTestDataFileUrls([ + 'text-1.txt', 'text-2.txt', 'text-3.txt']); + + const swFile =`${serviceWorkersFolder}max-cache-age-global.js`; + return swUtils.activateSW(swFile).then(iframe => { + return iframe.contentWindow.fetch(urls[0]) + .then(() => pause(1500)) + .then(() => sequentialFetch(iframe, urls.slice(1))) + .then(() => swUtils.getAllCachedAssets(iframe.src)); + }).then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(1))); }); it('should cache according to route specific maxAgeSeconds option', function() { - const urls = [ - '/test/data/files/text-1.txt', - '/test/data/files/text-2.txt', - '/test/data/files/text-3.txt' - ]; - - return swUtils.activateSW(serviceWorkersFolder + '/max-cache-age-route.js') - .then(iframe => { - return urls.reduce((promiseChain, url, index) => { - return promiseChain - .then(() => { - // Pause is to ensure the cache has had time to finish. - return iframe.contentWindow.fetch(url) - .then(() => { - if (index === 0) { - return pausePromise(1500); - } - }); - }); - }, Promise.resolve()); - }) - .then(() => { - // Give cache time to settle - return pausePromise(500); - }) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(2); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-2.txt').should.not.equal(-1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-3.txt').should.not.equal(-1); - }); + const urls = absoluteTestDataFileUrls([ + 'text-1.txt', 'text-2.txt', 'text-3.txt']); + + const swFile =`${serviceWorkersFolder}max-cache-age-route.js`; + return swUtils.activateSW(swFile).then(iframe => { + return iframe.contentWindow.fetch(urls[0]) + .then(() => pause(1500)) + .then(() => sequentialFetch(iframe, urls.slice(1))) + .then(() => swUtils.getAllCachedAssets(iframe.src)); + }).then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(1))); }); }); describe('options.cache.maxEntries && options.cache.maxAgeSeconds', function() { it('should cache according to global maxEntries & maxAgeSeconds option', function() { - this.timeout(8000); - const urls = [ - '/test/data/files/text-1.txt', - '/test/data/files/text-2.txt', - '/test/data/files/text-3.txt' - ]; - - let iframe; - return swUtils.activateSW(serviceWorkersFolder + '/max-cache-age-global.js') - .then(newIframe => { - iframe = newIframe; - return urls.reduce((promiseChain, url, index) => { - return promiseChain - .then(() => { - return iframe.contentWindow.fetch(url) - .then(() => { - if (index === 0) { - return pausePromise(1500); - } - }); - }); - }, Promise.resolve()); - }) - .then(() => pausePromise(500)) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(2); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-2.txt').should.not.equal(-1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-3.txt').should.not.equal(-1); - }) - .then(() => pausePromise(1500)) - .then(() => { - return iframe.contentWindow.fetch('/test/data/files/text-4.txt'); - }) - .then(() => pausePromise(500)) - .then(() => { - return swUtils.getAllCachedAssets('options-test'); - }) - .then(cachedAssets => { - Object.keys(cachedAssets).length.should.equal(1); - Object.keys(cachedAssets).indexOf(location.origin + '/test/data/files/text-4.txt').should.not.equal(-1); + const urls = absoluteTestDataFileUrls([ + 'text-1.txt', 'text-2.txt', 'text-3.txt', 'text-4.txt']); + + const swFile =`${serviceWorkersFolder}max-entries-cache-age-global.js`; + return swUtils.activateSW(swFile).then(iframe => { + return iframe.contentWindow.fetch(urls[0]) + .then(() => pause(1500)) + .then(() => sequentialFetch(iframe, urls.slice(1, 3))) + .then(() => swUtils.getAllCachedAssets(iframe.src)) + .then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(1, 3))) + .then(() => sequentialFetch(iframe, urls.slice(2, 4))) + .then(() => swUtils.getAllCachedAssets(iframe.src)) + .then(cachedAssets => assertCacheContents(cachedAssets, urls.slice(2, 4))); }); }); }); diff --git a/test/browser-tests/options/serviceworkers/max-cache-age-global.js b/test/browser-tests/options/serviceworkers/max-cache-age-global.js index d1ae6f3..bdaa6d7 100644 --- a/test/browser-tests/options/serviceworkers/max-cache-age-global.js +++ b/test/browser-tests/options/serviceworkers/max-cache-age-global.js @@ -22,7 +22,7 @@ importScripts('/build/sw-toolbox.js'); importScripts('/test/data/skip-and-claim.js'); self.toolbox.options.cache = { - name: 'options-test', + name: self.registration.scope, maxAgeSeconds: 1 }; diff --git a/test/browser-tests/options/serviceworkers/max-cache-age-route.js b/test/browser-tests/options/serviceworkers/max-cache-age-route.js index 430e181..84fdf95 100644 --- a/test/browser-tests/options/serviceworkers/max-cache-age-route.js +++ b/test/browser-tests/options/serviceworkers/max-cache-age-route.js @@ -25,7 +25,7 @@ self.toolbox.options.debug = true; self.toolbox.router.get('/test/data/files/:foo', self.toolbox.networkFirst, { cache: { - name: 'options-test', + name: self.registration.scope, maxAgeSeconds: 1 } }); diff --git a/test/browser-tests/options/serviceworkers/max-entries-cache-age-global.js b/test/browser-tests/options/serviceworkers/max-entries-cache-age-global.js index a6c8155..e3380e4 100644 --- a/test/browser-tests/options/serviceworkers/max-entries-cache-age-global.js +++ b/test/browser-tests/options/serviceworkers/max-entries-cache-age-global.js @@ -22,7 +22,7 @@ importScripts('/build/sw-toolbox.js'); importScripts('/test/data/skip-and-claim.js'); self.toolbox.options.cache = { - name: 'options-test', + name: self.registration.scope, maxEntries: 2, maxAgeSeconds: 1 }; diff --git a/test/browser-tests/options/serviceworkers/max-entries-cache-age-route.js b/test/browser-tests/options/serviceworkers/max-entries-cache-age-route.js deleted file mode 100644 index 6b909df..0000000 --- a/test/browser-tests/options/serviceworkers/max-entries-cache-age-route.js +++ /dev/null @@ -1,22 +0,0 @@ -/* - Copyright 2016 Google Inc. All Rights Reserved. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. -*/ - -'use strict'; - -/* eslint-env worker, serviceworker */ - -importScripts('/build/sw-toolbox.js'); -importScripts('/test/data/skip-and-claim.js'); diff --git a/test/browser-tests/options/serviceworkers/max-entries-global.js b/test/browser-tests/options/serviceworkers/max-entries-global.js index abd71b8..63ea2d5 100644 --- a/test/browser-tests/options/serviceworkers/max-entries-global.js +++ b/test/browser-tests/options/serviceworkers/max-entries-global.js @@ -22,7 +22,7 @@ importScripts('/build/sw-toolbox.js'); importScripts('/test/data/skip-and-claim.js'); self.toolbox.options.cache = { - name: 'options-test', + name: self.registration.scope, maxEntries: 2 }; diff --git a/test/browser-tests/options/serviceworkers/max-entries-route.js b/test/browser-tests/options/serviceworkers/max-entries-route.js index a8a9c5e..21140d5 100644 --- a/test/browser-tests/options/serviceworkers/max-entries-route.js +++ b/test/browser-tests/options/serviceworkers/max-entries-route.js @@ -23,7 +23,7 @@ importScripts('/test/data/skip-and-claim.js'); self.toolbox.router.get('/test/data/files/:foo', self.toolbox.networkFirst, { cache: { - name: 'options-test', + name: self.registration.scope, maxEntries: 2 } }); From 808f6f2d5b79aab3a85180655cb4f6537e5ce3ba Mon Sep 17 00:00:00 2001 From: Jeff Posnick Date: Wed, 21 Sep 2016 21:34:51 -0400 Subject: [PATCH 2/2] Linting fixes. --- test/browser-tests/options/options.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/test/browser-tests/options/options.js b/test/browser-tests/options/options.js index ddd968a..4470908 100644 --- a/test/browser-tests/options/options.js +++ b/test/browser-tests/options/options.js @@ -24,7 +24,7 @@ describe('Test Options Parameters', function() { /** * @param {Number} timeout The number of milliseconds to pause for. - * @returns {Promise} A promise that resolves after a specified delay. + * @return {Promise} A promise that resolves after a specified delay. */ const pause = timeout => { return new Promise(resolve => setTimeout(resolve, timeout)); @@ -34,7 +34,7 @@ describe('Test Options Parameters', function() { * Performs a series of fetch() calls on an iframe, then pauses. * @param {iframe} iframe The iframe whose contentWindow will be used to fetch(). * @param {Array.} urls The URLs to fetch. - * @returns {Promise} A promise that resolves following the fetches and a delay. + * @return {Promise} A promise that resolves following the fetches and a delay. */ const sequentialFetch = (iframe, urls) => { return urls.reduce((chain, url) => { @@ -44,8 +44,8 @@ describe('Test Options Parameters', function() { /** * Prepends a common prefix to several partial URLs, and returns the absolute URLs. - * @param urls The partial URLs. - * @returns {Array.} The absolute URLs. + * @param {Array.} urls The partial URLs. + * @return {Array.} The absolute URLs. */ const absoluteTestDataFileUrls = urls => urls.map(url => { return String(new URL(url, `${location.origin}/test/data/files/`)); @@ -80,7 +80,7 @@ describe('Test Options Parameters', function() { const urls = absoluteTestDataFileUrls([ 'text-1.txt', 'text-2.txt', 'text-3.txt']); - const swFile =`${serviceWorkersFolder}max-entries-route.js`; + const swFile = `${serviceWorkersFolder}max-entries-route.js`; return swUtils.activateSW(swFile).then(iframe => { return sequentialFetch(iframe, urls) .then(() => swUtils.getAllCachedAssets(iframe.src)); @@ -93,7 +93,7 @@ describe('Test Options Parameters', function() { const urls = absoluteTestDataFileUrls([ 'text-1.txt', 'text-2.txt', 'text-3.txt']); - const swFile =`${serviceWorkersFolder}max-cache-age-global.js`; + const swFile = `${serviceWorkersFolder}max-cache-age-global.js`; return swUtils.activateSW(swFile).then(iframe => { return iframe.contentWindow.fetch(urls[0]) .then(() => pause(1500)) @@ -106,7 +106,7 @@ describe('Test Options Parameters', function() { const urls = absoluteTestDataFileUrls([ 'text-1.txt', 'text-2.txt', 'text-3.txt']); - const swFile =`${serviceWorkersFolder}max-cache-age-route.js`; + const swFile = `${serviceWorkersFolder}max-cache-age-route.js`; return swUtils.activateSW(swFile).then(iframe => { return iframe.contentWindow.fetch(urls[0]) .then(() => pause(1500)) @@ -121,7 +121,7 @@ describe('Test Options Parameters', function() { const urls = absoluteTestDataFileUrls([ 'text-1.txt', 'text-2.txt', 'text-3.txt', 'text-4.txt']); - const swFile =`${serviceWorkersFolder}max-entries-cache-age-global.js`; + const swFile = `${serviceWorkersFolder}max-entries-cache-age-global.js`; return swUtils.activateSW(swFile).then(iframe => { return iframe.contentWindow.fetch(urls[0]) .then(() => pause(1500))