Skip to content

Commit 543b422

Browse files
authored
Revamp smoketest, include offline & SW test
* Replace pythonsimplehttpserver with a configurable node-based server ### offline & sw details * use SW logic from from googlechrome.github.io/samples/service-worker/basic , but adapted * Simpler skipWaiting thanks to GoogleChrome/samples@dbca5f7#commitcomment-18601764 * run smoketests on diff ports so sw isn't shared. * Load offline-ready page twice so we dont have to worry about racing between cache population and lighthouse's gatherer. * make offline page take longer to load to allow enough time for SW to populate cache
1 parent ac70731 commit 543b422

File tree

8 files changed

+236
-20
lines changed

8 files changed

+236
-20
lines changed

lighthouse-cli/scripts/run-smoke-tests.sh

Lines changed: 14 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
#!/usr/bin/env bash
22

3-
cd lighthouse-cli/test/fixtures && python -m SimpleHTTPServer 10200 &
3+
node lighthouse-cli/test/fixtures/static-server.js &
4+
5+
sleep 0.5s
46

57
NODE=$([ $(node -v | grep -E "v4") ] && echo "node --harmony" || echo "node")
6-
#config="$PWD/lighthouse-cli/test/fixtures/smoketest-config.json"
7-
#flags="--config-path=$config"
8+
config="$PWD/lighthouse-cli/test/fixtures/smoketest-offline-config.json"
89

910
offline200result="URL responds with a 200 when offline"
1011

@@ -30,15 +31,13 @@ if ! grep -q "$offline200result: false" results; then
3031
exit 1
3132
fi
3233

33-
# SKIP this test for now until the flakiness is addressed.
34-
# sleep 1s
35-
#
36-
# # test mojibrush which should pass the offline test
37-
# $NODE lighthouse-cli $flags https://www.moji-brush.com > results
38-
#
39-
# if ! grep -q "$offline200result: true" results; then
40-
# echo "Fail! offline ready site did not work while offline"
41-
# cat results
42-
# exit 1
43-
# fi
44-
#
34+
sleep 0.5s
35+
36+
# run minimal lighthouse run against a basic offline-sw page
37+
$NODE lighthouse-cli --config-path=$config --quiet http://localhost:10503/offline-ready.html > results
38+
39+
if ! grep -q "$offline200result: true" results; then
40+
echo "Fail! offline ready site did not work while offline"
41+
cat results
42+
exit 1
43+
fi
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* @license
3+
* Copyright 2016 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
/* eslint-env worker, serviceworker */
19+
20+
// This service-worker courtesy of googlechrome.github.io/samples/service-worker/basic/index.html
21+
22+
// A list of local resources we always want to be cached.
23+
const PRECACHE_URLS = [
24+
'./offline-ready.html',
25+
'./offline-ready-sw.js',
26+
'./smoketest-offline-config.json'
27+
];
28+
29+
// Names of the two caches used in this version of the service worker.
30+
// Change to v2, etc. when you update any of the local resources, which will
31+
// in turn trigger the install event again.
32+
const PRECACHE = 'precache-v1';
33+
const RUNTIME = 'runtime';
34+
35+
// The install handler takes care of precaching the resources we always need.
36+
self.addEventListener('install', event => {
37+
self.skipWaiting();
38+
39+
const populateCaches = caches.open(PRECACHE)
40+
.then(cache => cache.addAll(PRECACHE_URLS));
41+
42+
event.waitUntil(populateCaches);
43+
});
44+
45+
// The activate handler takes care of cleaning up old caches.
46+
self.addEventListener('activate', event => {
47+
const currentCaches = [PRECACHE, RUNTIME];
48+
event.waitUntil(
49+
caches.keys().then(cacheNames => {
50+
return cacheNames.filter(cacheName => !currentCaches.includes(cacheName));
51+
}).then(cachesToDelete => {
52+
return Promise.all(cachesToDelete.map(cacheToDelete => {
53+
return caches.delete(cacheToDelete);
54+
}));
55+
}).then(() => self.clients.claim())
56+
);
57+
});
58+
59+
// The fetch handler serves responses for same-origin resources from a cache.
60+
// If no response is found, it populates the runtime cache with the response
61+
// from the network before returning it to the page.
62+
self.addEventListener('fetch', event => {
63+
// Skip cross-origin requests, like those for Google Analytics.
64+
if (!event.request.url.startsWith(self.location.origin)) {
65+
return;
66+
}
67+
68+
event.respondWith(
69+
caches.match(event.request).then(cachedResponse => {
70+
if (cachedResponse) {
71+
return cachedResponse;
72+
}
73+
74+
return caches.open(RUNTIME).then(cache => {
75+
return fetch(event.request).then(response => {
76+
// Put a copy of the response in the runtime cache.
77+
return cache.put(event.request, response.clone()).then(_ => response);
78+
});
79+
});
80+
})
81+
);
82+
});
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<!doctype html>
2+
<!--
3+
* Copyright 2016 Google Inc. All rights reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
-->
17+
18+
<title>So offline-ready. The most.</title>
19+
<meta charset="utf-8">
20+
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
21+
<!--<link rel="manifest" href="/manifest.json">-->
22+
23+
<h1>
24+
Whenever you call me, I'll be there.
25+
</h1>
26+
<h2>
27+
Whenever you want me, I'll be there.
28+
</h2>
29+
<h3>
30+
Whenever you need me, I'll be there.
31+
</h3>
32+
<h4>
33+
I'll be arounddddd.
34+
</h4>
35+
36+
<script>
37+
if ('serviceWorker' in navigator) {
38+
navigator.serviceWorker.register('/offline-ready-sw.js').then(function(registration) {
39+
console.log('service worker registration complete');
40+
41+
registration.addEventListener('statechange', e => {
42+
console.log('sw registration is now', e.target.state);
43+
});
44+
}).catch(function(e) {
45+
console.error('service worker is not so cool.', e);
46+
throw e;
47+
});
48+
}
49+
</script>
50+
51+
<!--
52+
Lighthouse will move on to the next thing at onload, however this will race with
53+
the cache population in the serviceworker's install phase.
54+
We use an image that takes 2-seconds to load to delay window onload. -->
55+
<img src="icon-128.png?delay">

lighthouse-cli/test/fixtures/smoketest-config.json renamed to lighthouse-cli/test/fixtures/smoketest-offline-config.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,14 @@
22
"passes": [{
33
"loadPage": true,
44
"gatherers": [
5-
"service-worker",
6-
"offline",
75
"viewport"
86
]
7+
},{
8+
"loadPage": true,
9+
"gatherers": [
10+
"service-worker",
11+
"offline"
12+
]
913
}],
1014

1115
"audits": [
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* @license
3+
* Copyright 2016 Google Inc. All Rights Reserved.
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
'use strict';
18+
19+
const http = require('http');
20+
const path = require('path');
21+
const fs = require('fs');
22+
const parseURL = require('url').parse;
23+
24+
function requestHandler(request, response) {
25+
const filePath = parseURL(request.url).pathname;
26+
const queryString = parseURL(request.url).search;
27+
const absoluteFilePath = path.join(__dirname, filePath);
28+
29+
fs.exists(absoluteFilePath, fsExistsCallback);
30+
31+
function fsExistsCallback(fileExists) {
32+
if (!fileExists) {
33+
return sendResponse(404, `404 - File not found. ${absoluteFilePath}`);
34+
}
35+
fs.readFile(absoluteFilePath, 'binary', readFileCallback);
36+
}
37+
38+
function readFileCallback(err, file) {
39+
if (err) {
40+
console.error(`Unable to read local file ${absoluteFilePath}:`, err);
41+
return sendResponse(500, '500 - Internal Server Error');
42+
}
43+
sendResponse(200, file);
44+
}
45+
46+
function sendResponse(statusCode, data) {
47+
const headers = filePath.endsWith('.js') ?
48+
{'Content-Type': 'text/javascript'} : undefined;
49+
response.writeHead(statusCode, headers);
50+
51+
if (queryString && queryString.includes('delay')) {
52+
response.write('');
53+
return setTimeout(finishResponse, 2000, data);
54+
}
55+
finishResponse(data);
56+
}
57+
58+
function finishResponse(data) {
59+
response.write(data, 'binary');
60+
response.end();
61+
}
62+
}
63+
64+
const serverForOnline = http.createServer(requestHandler);
65+
const serverForOffline = http.createServer(requestHandler);
66+
67+
serverForOnline.on('error', e => console.error(e.code, e));
68+
serverForOffline.on('error', e => console.error(e.code, e));
69+
70+
// Listen
71+
serverForOnline.listen(10200);
72+
serverForOffline.listen(10503);

lighthouse-core/config/index.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,11 @@ function filterPasses(passes, audits, rootPath) {
118118

119119
freshPass.gatherers = freshPass.gatherers.filter(gatherer => {
120120
const GathererClass = GatherRunner.getGathererClass(gatherer, rootPath);
121-
return requiredGatherers.has(GathererClass.name);
121+
const isGatherRequiredByAudits = requiredGatherers.has(GathererClass.name);
122+
if (isGatherRequiredByAudits === false) {
123+
log.warn('config', `Skipping ${GathererClass.name} gatherer as no audit requires it.`);
124+
}
125+
return isGatherRequiredByAudits;
122126
});
123127

124128
return freshPass;

lighthouse-core/scripts/run-mocha.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
flag=$1
44

55
function _runmocha() {
6-
mocha $2 $__node_harmony $(find $1/test -name '*.js') --timeout 60000;
6+
mocha $2 $__node_harmony $(find $1/test -name '*.js' -not -path '*/fixtures/*') --timeout 60000;
77
}
88

99
if [ "$flag" == '--watch' ]; then

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
"scripts": {
1111
"lint": "[ \"$CI\" = true ] && eslint --quiet . || eslint .",
1212
"smoke": "lighthouse-cli/scripts/run-smoke-tests.sh",
13-
"coverage": "node $__node_harmony $(npm bin)/istanbul cover -x \"**/third_party/**\" _mocha -- $(find */test -name '*.js') --timeout 60000 --reporter progress",
13+
"coverage": "node $__node_harmony $(npm bin)/istanbul cover -x \"**/third_party/**\" _mocha -- $(find */test -name '*.js' -not -path '*/fixtures/*') --timeout 60000 --reporter progress",
1414
"coveralls": "npm run coverage && cat ./coverage/lcov.info | coveralls",
1515
"start": "node ./lighthouse-cli/index.js",
1616
"test": "npm run lint --silent && npm run unit && npm run closure",

0 commit comments

Comments
 (0)