Skip to content

Commit

Permalink
Update tests to run in a SW env
Browse files Browse the repository at this point in the history
  • Loading branch information
philipwalton committed Apr 2, 2019
1 parent b637c89 commit b70cd0d
Show file tree
Hide file tree
Showing 6 changed files with 110 additions and 86 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Expand Up @@ -43,6 +43,7 @@ module.exports = {
globals: {
expectError: false,
waitUntil: false,
BROWSER_NAMESPACES: false,
},
rules: {
'max-len': 0,
Expand Down
7 changes: 7 additions & 0 deletions infra/testing/server/routes/sw-bundle.js
Expand Up @@ -11,8 +11,13 @@ const replace = require('rollup-plugin-replace');
const resolve = require('rollup-plugin-node-resolve');
const multiEntry = require('rollup-plugin-multi-entry');
const commonjs = require('rollup-plugin-commonjs');
const {getPackages} = require('../../../../gulp-tasks/utils/get-packages');


const BROWSER_NAMESPACES = getPackages({type: 'browser'}).map((pkg) => {
return pkg.workbox.browserNamespace;
});

const match = '/test/:package/*/sw-bundle.js';
const caches = {};

Expand All @@ -35,6 +40,8 @@ async function handler(req, res) {
}),
replace({
'process.env.NODE_ENV': JSON.stringify(env),
'BROWSER_NAMESPACES': JSON.stringify(BROWSER_NAMESPACES),
'WORKBOX_CDN_ROOT_URL': '/__WORKBOX/buildFile',
}),
],
cache: caches[env],
Expand Down
72 changes: 42 additions & 30 deletions infra/testing/server/templates/test-sw-runner.js.njk
Expand Up @@ -60,40 +60,52 @@ mocha.setup({
reporter: null,
});

addEventListener('message', (event) => {
if (event.data && event.data.type === 'RUN_TESTS') {
const testsComplete = new Promise((resolve) => {
const reports = [];
const runner = mocha.run();

runner.on('fail', (test, err) => {
const flattenTitles = (test) => {
const titles = [test.title];
while (test.parent.title) {
titles.push(test.parent.title);
test = test.parent;
}
return titles.reverse().join(' ');
};

reports.push({
name: flattenTitles(test),
result: false,
message: err.message,
stack: err.stack,
});
addEventListener('install', (event) => {
const testsComplete = new Promise((resolve, reject) => {
const reports = [];
const runner = mocha.run();

runner.on('fail', (test, err) => {
const flattenTitles = (test) => {
const titles = [test.title];
while (test.parent.title) {
titles.push(test.parent.title);
test = test.parent;
}
return titles.reverse().join(' ');
};

reports.push({
name: flattenTitles(test),
result: false,
message: err.message,
stack: err.stack,
});
});

runner.on('end', async () => {
const results = runner.stats;
results.reports = reports;

runner.on('end', async () => {
const results = runner.stats;
results.reports = reports;
event.ports[0].postMessage(results);
resolve(results);
const windows = await clients.matchAll({
type: 'window',
includeUncontrolled: true,
});

for (const win of windows) {
win.postMessage(results);
}

// Fail installation if the tests don't pass.
if (results.failures) {
reject();
} else {
resolve();
}
});
});

event.waitUntil(testsComplete);
}
});
event.waitUntil(testsComplete);
}, {once: true}); // Run once since `install` events are dispatched in tests.

importScripts('sw-bundle.js');
38 changes: 21 additions & 17 deletions infra/testing/server/templates/test-sw.html.njk
Expand Up @@ -45,25 +45,29 @@
(async () => {
// // Randomize the test URL so every test run forces a new SW install.
const wb = new Workbox('test-sw-runner.js.njk?v={{ uniqueID() }}');
await wb.register();
self.mochaResults = await wb.messageSW({type: 'RUN_TESTS'});
if (self.mochaResults.failures === 0) {
const styles = [
`color: hsl(150, 100%, 40%)`,
`font-weight: bold`,
`font-size: 1.5em`,
`padding: .25em 0`,
];
console.log('%cAll TESTS PASS!', styles.join(';'));
document.getElementById('success').textContent = 'ALL TESTS PASS!';
} else {
const errors = self.mochaResults.reports.map((report) => {
return `${report.name}\n${report.stack}`;
}).join('\n\n');
wb.addEventListener('message', (event) => {
self.mochaResults = event.data;
document.getElementById('errors').textContent = errors
}
if (self.mochaResults.failures === 0) {
const styles = [
`color: hsl(150, 100%, 40%)`,
`font-weight: bold`,
`font-size: 1.5em`,
`padding: .25em 0`,
];
console.log('%cAll TESTS PASS!', styles.join(';'));
document.getElementById('success').textContent = 'ALL TESTS PASS!';
} else {
const errors = self.mochaResults.reports.map((report) => {
return `${report.name}\n${report.stack}`;
}).join('\n\n');
document.getElementById('errors').textContent = errors
}
});
wb.register();
})();
</script>
</body>
Expand Down
17 changes: 14 additions & 3 deletions test/workbox-sw/integration/test-all.js
Expand Up @@ -7,22 +7,33 @@
*/

const expect = require('chai').expect;
const {runUnitTests} = require('../../../infra/testing/webdriver/runUnitTests');


// Store local references of these globals.
const {webdriver, server} = global.__workbox;

describe(`[workbox-sw]`, function() {
it(`passes all SW unit tests`, async function() {
await runUnitTests('/test/workbox-sw/sw/');
});
});

describe(`WorkboxSW interface`, function() {
const wasRegistrationSuccessful = (swFile) => {
return global.__workbox.webdriver.executeAsyncScript((swFile, cb) => {
return webdriver.executeAsyncScript((swFile, cb) => {
// Invokes cb() with true when registration succeeds, and false otherwise.
navigator.serviceWorker.register(swFile)
.then(() => cb(true))
.catch(() => cb(false));
}, swFile);
};

const testServerAddress = global.__workbox.server.getAddress();
const testServerAddress = server.getAddress();
const testPageURL = `${testServerAddress}/test/workbox-sw/static/integration/`;

before(async function() {
await global.__workbox.webdriver.get(testPageURL);
await webdriver.get(testPageURL);
});

it(`should fail to activate an invalid SW which loads non-existent modules`, async function() {
Expand Down
61 changes: 25 additions & 36 deletions test/workbox-sw/sw/controllers/test-WorkboxSW.mjs
Expand Up @@ -6,36 +6,16 @@
https://opensource.org/licenses/MIT.
*/

import {expect} from 'chai';
import sinon from 'sinon';
import generateTestVariants from '../../../infra/testing/generate-variant-tests';
import {WorkboxSW} from '../../../packages/workbox-sw/controllers/WorkboxSW.mjs';
import {getPackages} from '../../../gulp-tasks/utils/get-packages';
import {outputFilenameToPkgMap} from '../../../gulp-tasks/utils/output-filename-to-package-map';
import {WorkboxSW} from 'workbox-sw/controllers/WorkboxSW.mjs';
import generateTestVariants from '../../../../infra/testing/generate-variant-tests';


describe(`[workbox-sw] WorkboxSW`, function() {
describe(`WorkboxSW`, function() {
let sandbox = sinon.createSandbox();

beforeEach(function() {
sandbox.restore();
delete self.workbox;

sandbox.stub(self, 'importScripts').callsFake((url) => {
// This auto generates a value for self.workbox.<namespace>
const match = /WORKBOX_CDN_ROOT_URL\/(.*)\.(?:dev|prod)\.js/.exec(url);
if (!match) {
return;
}

const outputFilename = match[1];
const pkg = outputFilenameToPkgMap[outputFilename];

const namespace = pkg.workbox.browserNamespace.split('.')[1];
self.workbox[namespace] = {
injectedMsg: `Injected value for ${pkg.name}.`,
};
});
});

after(function() {
Expand All @@ -45,6 +25,8 @@ describe(`[workbox-sw] WorkboxSW`, function() {

describe(`constructor`, function() {
it(`should construct with expect defaults`, function() {
sandbox.stub(location, 'hostname').value('example.com');

self.workbox = new WorkboxSW();
expect(self.workbox._options).to.deep.equal({
debug: false,
Expand All @@ -54,9 +36,7 @@ describe(`[workbox-sw] WorkboxSW`, function() {
});

it(`should construct debug true when on localhost`, function() {
sandbox.stub(self, 'location').value({
hostname: 'localhost',
});
sandbox.stub(location, 'hostname').value('localhost');

self.workbox = new WorkboxSW();
expect(self.workbox._options.debug).to.deep.equal(true);
Expand All @@ -81,6 +61,8 @@ describe(`[workbox-sw] WorkboxSW`, function() {
});

it(`should throw when invoking config after loading a module`, function() {
sandbox.stub(self, 'importScripts');

self.workbox = new WorkboxSW();

expect(() => {
Expand All @@ -92,11 +74,16 @@ describe(`[workbox-sw] WorkboxSW`, function() {
// Accessing .core loads workbox-core.
self.workbox.core;

expect(importScripts.callCount).to.equal(1);
expect(importScripts.args[0][0]).to.equal(`http://custom-cdn.example.com/workbox-modules/v1.0.0/workbox-core.dev.js`);

expect(() => {
self.workbox.setConfig({
modulePathPrefix: 'http://custom-cdn.example.com/workbox-modules/v2.0.0/',
});
}).to.throw();

expect(importScripts.callCount).to.equal(1);
});

it(`should not throw on no config and environment should stay the same`, function() {
Expand All @@ -113,12 +100,11 @@ describe(`[workbox-sw] WorkboxSW`, function() {
describe(`get`, function() {
it(`should print error message when importScripts fails`, function() {
const errorMessage = 'Injected error.';
self.importScripts.restore();

sandbox.stub(self, 'importScripts').throws(new Error(errorMessage));
sandbox.stub(console, 'error').callsFake((errMsg) => {
expect(errMsg.includes('workbox-core')).to.be.true;
expect(errMsg.includes(
'WORKBOX_CDN_ROOT_URL/workbox-core.prod.js')).to.be.true;
expect(errMsg.includes('WORKBOX_CDN_ROOT_URL/workbox-core')).to.be.true;
});

try {
Expand All @@ -134,6 +120,8 @@ describe(`[workbox-sw] WorkboxSW`, function() {
});

it(`should use modulePathCb to load modules if provided`, function() {
sandbox.stub(self, 'importScripts');

const callbackSpy = sandbox.spy((moduleName, debug) => {
return `/custom-path/${moduleName}/${debug}`;
});
Expand Down Expand Up @@ -180,6 +168,8 @@ describe(`[workbox-sw] WorkboxSW`, function() {
},
];
generateTestVariants(`should import using modulePathPrefix`, modulePathVariations, async function(variant) {
sandbox.stub(self, 'importScripts');

self.workbox = new WorkboxSW();

self.workbox.setConfig({
Expand All @@ -194,16 +184,15 @@ describe(`[workbox-sw] WorkboxSW`, function() {
});
});

getPackages({type: 'browser'}).forEach((pkg) => {
BROWSER_NAMESPACES.forEach((namespace) => {
// Don't test workbox-sw, which exports the `workbox` namespace.
if (pkg.workbox.browserNamespace === 'workbox') return;
if (namespace === 'workbox') return;

describe(`get ${pkg.workbox.browserNamespace}`, function() {
it(`should return ${pkg.workbox.browserNamespace}`, function() {
const namespace = pkg.workbox.browserNamespace.split('.')[1];
describe(`get ${namespace}`, function() {
it(`should return ${namespace}`, function() {
const getter = namespace.split('.')[1];
self.workbox = new WorkboxSW();
expect(self.workbox[namespace]).to.exist;
expect(self.workbox[namespace].injectedMsg).to.exist;
expect(self.workbox[getter]).to.exist;
});
});
});
Expand Down

0 comments on commit b70cd0d

Please sign in to comment.