diff --git a/lighthouse-cli/scripts/run-smoke-tests.sh b/lighthouse-cli/scripts/run-smoke-tests.sh index 000fde9273d6..25bfb0dffa81 100755 --- a/lighthouse-cli/scripts/run-smoke-tests.sh +++ b/lighthouse-cli/scripts/run-smoke-tests.sh @@ -1,10 +1,11 @@ #!/usr/bin/env bash -cd lighthouse-cli/test/fixtures && python -m SimpleHTTPServer 10200 & +node lighthouse-cli/test/fixtures/static-server.js & + +sleep 0.5s NODE=$([ $(node -v | grep -E "v4") ] && echo "node --harmony" || echo "node") -#config="$PWD/lighthouse-cli/test/fixtures/smoketest-config.json" -#flags="--config-path=$config" +config="$PWD/lighthouse-cli/test/fixtures/smoketest-offline-config.json" offline200result="URL responds with a 200 when offline" @@ -30,15 +31,13 @@ if ! grep -q "$offline200result: false" results; then exit 1 fi -# SKIP this test for now until the flakiness is addressed. -# sleep 1s -# -# # test mojibrush which should pass the offline test -# $NODE lighthouse-cli $flags https://www.moji-brush.com > results -# -# if ! grep -q "$offline200result: true" results; then -# echo "Fail! offline ready site did not work while offline" -# cat results -# exit 1 -# fi -# +sleep 0.5s + +# run minimal lighthouse run against a basic offline-sw page +$NODE lighthouse-cli --config-path=$config --quiet http://localhost:10503/offline-ready.html > results + +if ! grep -q "$offline200result: true" results; then + echo "Fail! offline ready site did not work while offline" + cat results + exit 1 +fi diff --git a/lighthouse-cli/test/fixtures/offline-ready-sw.js b/lighthouse-cli/test/fixtures/offline-ready-sw.js new file mode 100644 index 000000000000..5b3a75347faa --- /dev/null +++ b/lighthouse-cli/test/fixtures/offline-ready-sw.js @@ -0,0 +1,82 @@ +/** + * @license + * 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. + */ + +/* eslint-env worker, serviceworker */ + +// This service-worker courtesy of googlechrome.github.io/samples/service-worker/basic/index.html + +// A list of local resources we always want to be cached. +const PRECACHE_URLS = [ + './offline-ready.html', + './offline-ready-sw.js', + './smoketest-offline-config.json' +]; + +// Names of the two caches used in this version of the service worker. +// Change to v2, etc. when you update any of the local resources, which will +// in turn trigger the install event again. +const PRECACHE = 'precache-v1'; +const RUNTIME = 'runtime'; + +// The install handler takes care of precaching the resources we always need. +self.addEventListener('install', event => { + self.skipWaiting(); + + const populateCaches = caches.open(PRECACHE) + .then(cache => cache.addAll(PRECACHE_URLS)); + + event.waitUntil(populateCaches); +}); + +// The activate handler takes care of cleaning up old caches. +self.addEventListener('activate', event => { + const currentCaches = [PRECACHE, RUNTIME]; + event.waitUntil( + caches.keys().then(cacheNames => { + return cacheNames.filter(cacheName => !currentCaches.includes(cacheName)); + }).then(cachesToDelete => { + return Promise.all(cachesToDelete.map(cacheToDelete => { + return caches.delete(cacheToDelete); + })); + }).then(() => self.clients.claim()) + ); +}); + +// The fetch handler serves responses for same-origin resources from a cache. +// If no response is found, it populates the runtime cache with the response +// from the network before returning it to the page. +self.addEventListener('fetch', event => { + // Skip cross-origin requests, like those for Google Analytics. + if (!event.request.url.startsWith(self.location.origin)) { + return; + } + + event.respondWith( + caches.match(event.request).then(cachedResponse => { + if (cachedResponse) { + return cachedResponse; + } + + return caches.open(RUNTIME).then(cache => { + return fetch(event.request).then(response => { + // Put a copy of the response in the runtime cache. + return cache.put(event.request, response.clone()).then(_ => response); + }); + }); + }) + ); +}); diff --git a/lighthouse-cli/test/fixtures/offline-ready.html b/lighthouse-cli/test/fixtures/offline-ready.html new file mode 100644 index 000000000000..aadfcd8c179a --- /dev/null +++ b/lighthouse-cli/test/fixtures/offline-ready.html @@ -0,0 +1,55 @@ + + + +So offline-ready. The most. + + + + +

+ Whenever you call me, I'll be there. +

+

+ Whenever you want me, I'll be there. +

+

+ Whenever you need me, I'll be there. +

+

+ I'll be arounddddd. +

+ + + + + diff --git a/lighthouse-cli/test/fixtures/smoketest-config.json b/lighthouse-cli/test/fixtures/smoketest-offline-config.json similarity index 94% rename from lighthouse-cli/test/fixtures/smoketest-config.json rename to lighthouse-cli/test/fixtures/smoketest-offline-config.json index 47cc2f9cdeb1..2381769a838a 100644 --- a/lighthouse-cli/test/fixtures/smoketest-config.json +++ b/lighthouse-cli/test/fixtures/smoketest-offline-config.json @@ -2,10 +2,14 @@ "passes": [{ "loadPage": true, "gatherers": [ - "service-worker", - "offline", "viewport" ] + },{ + "loadPage": true, + "gatherers": [ + "service-worker", + "offline" + ] }], "audits": [ diff --git a/lighthouse-cli/test/fixtures/static-server.js b/lighthouse-cli/test/fixtures/static-server.js new file mode 100644 index 000000000000..e9eee0c2cacf --- /dev/null +++ b/lighthouse-cli/test/fixtures/static-server.js @@ -0,0 +1,72 @@ +/** + * @license + * 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'; + +const http = require('http'); +const path = require('path'); +const fs = require('fs'); +const parseURL = require('url').parse; + +function requestHandler(request, response) { + const filePath = parseURL(request.url).pathname; + const queryString = parseURL(request.url).search; + const absoluteFilePath = path.join(__dirname, filePath); + + fs.exists(absoluteFilePath, fsExistsCallback); + + function fsExistsCallback(fileExists) { + if (!fileExists) { + return sendResponse(404, `404 - File not found. ${absoluteFilePath}`); + } + fs.readFile(absoluteFilePath, 'binary', readFileCallback); + } + + function readFileCallback(err, file) { + if (err) { + console.error(`Unable to read local file ${absoluteFilePath}:`, err); + return sendResponse(500, '500 - Internal Server Error'); + } + sendResponse(200, file); + } + + function sendResponse(statusCode, data) { + const headers = filePath.endsWith('.js') ? + {'Content-Type': 'text/javascript'} : undefined; + response.writeHead(statusCode, headers); + + if (queryString && queryString.includes('delay')) { + response.write(''); + return setTimeout(finishResponse, 2000, data); + } + finishResponse(data); + } + + function finishResponse(data) { + response.write(data, 'binary'); + response.end(); + } +} + +const serverForOnline = http.createServer(requestHandler); +const serverForOffline = http.createServer(requestHandler); + +serverForOnline.on('error', e => console.error(e.code, e)); +serverForOffline.on('error', e => console.error(e.code, e)); + +// Listen +serverForOnline.listen(10200); +serverForOffline.listen(10503); diff --git a/lighthouse-core/config/index.js b/lighthouse-core/config/index.js index 49b864ef018a..a08417218775 100644 --- a/lighthouse-core/config/index.js +++ b/lighthouse-core/config/index.js @@ -118,7 +118,11 @@ function filterPasses(passes, audits, rootPath) { freshPass.gatherers = freshPass.gatherers.filter(gatherer => { const GathererClass = GatherRunner.getGathererClass(gatherer, rootPath); - return requiredGatherers.has(GathererClass.name); + const isGatherRequiredByAudits = requiredGatherers.has(GathererClass.name); + if (isGatherRequiredByAudits === false) { + log.warn('config', `Skipping ${GathererClass.name} gatherer as no audit requires it.`); + } + return isGatherRequiredByAudits; }); return freshPass; diff --git a/lighthouse-core/scripts/run-mocha.sh b/lighthouse-core/scripts/run-mocha.sh index 968ddf0a4e95..52ec2946e25c 100755 --- a/lighthouse-core/scripts/run-mocha.sh +++ b/lighthouse-core/scripts/run-mocha.sh @@ -3,7 +3,7 @@ flag=$1 function _runmocha() { - mocha $2 $__node_harmony $(find $1/test -name '*.js') --timeout 60000; + mocha $2 $__node_harmony $(find $1/test -name '*.js' -not -path '*/fixtures/*') --timeout 60000; } if [ "$flag" == '--watch' ]; then diff --git a/package.json b/package.json index 3cb4a71889a3..0b73f3a64cfc 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "scripts": { "lint": "[ \"$CI\" = true ] && eslint --quiet . || eslint .", "smoke": "lighthouse-cli/scripts/run-smoke-tests.sh", - "coverage": "node $__node_harmony $(npm bin)/istanbul cover -x \"**/third_party/**\" _mocha -- $(find */test -name '*.js') --timeout 60000 --reporter progress", + "coverage": "node $__node_harmony $(npm bin)/istanbul cover -x \"**/third_party/**\" _mocha -- $(find */test -name '*.js' -not -path '*/fixtures/*') --timeout 60000 --reporter progress", "coveralls": "npm run coverage && cat ./coverage/lcov.info | coveralls", "start": "node ./lighthouse-cli/index.js", "test": "npm run lint --silent && npm run unit && npm run closure",