From ec02d31a3f44b8198961382fe898947192af0e62 Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Wed, 17 Apr 2019 09:36:49 +0300 Subject: [PATCH 1/2] refactor(docs-infra): switch `test-pwa-score.js` to async/await --- aio/scripts/test-pwa-score.js | 79 +++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/aio/scripts/test-pwa-score.js b/aio/scripts/test-pwa-score.js index abc466d888d25..b95d4eba6ae86 100644 --- a/aio/scripts/test-pwa-score.js +++ b/aio/scripts/test-pwa-score.js @@ -2,7 +2,9 @@ /** * Usage: - * node scripts/test-pwa-score [] + * ```sh + * node scripts/test-pwa-score [] + * ``` * * Fails if the score is below ``. * If `` is defined, the full results will be logged there. @@ -32,7 +34,7 @@ if (process.env.CI) { _main(process.argv.slice(2)); // Functions - Definitions -function _main(args) { +async function _main(args) { const {url, minScore, logFile} = parseInput(args); const isOnHttp = /^http:/.test(url); @@ -44,10 +46,13 @@ function _main(args) { logger.setLevel(LIGHTHOUSE_FLAGS.logLevel); - launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config). - then(results => processResults(results, logFile)). - then(score => evaluateScore(minScore, score)). - catch(onError); + try { + const results = await launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config); + const score = await processResults(results, logFile); + evaluateScore(minScore, score); + } catch (err) { + onError(err); + } } function evaluateScore(expectedScore, actualScore) { @@ -60,13 +65,15 @@ function evaluateScore(expectedScore, actualScore) { } } -function launchChromeAndRunLighthouse(url, flags, config) { - return chromeLauncher.launch(CHROME_LAUNCH_OPTS).then(chrome => { - flags.port = chrome.port; - return lighthouse(url, flags, config). - then(results => chrome.kill().then(() => results)). - catch(err => chrome.kill().then(() => { throw err; }, () => { throw err; })); - }); +async function launchChromeAndRunLighthouse(url, flags, config) { + const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS); + flags.port = chrome.port; + + try { + return await lighthouse(url, flags, config); + } finally { + await chrome.kill(); + } } function onError(err) { @@ -88,33 +95,31 @@ function parseInput(args) { return {url, minScore, logFile}; } -function processResults(results, logFile) { +async function processResults(results, logFile) { + const lhVersion = results.lhr.lighthouseVersion; const categories = results.lhr.categories; const report = results.report; - return Promise.resolve(). - then(() => { - if (logFile) { - console.log(`Saving results in '${logFile}'...`); - console.log(`(LightHouse viewer: ${VIEWER_URL})`); - - return printer.write(report, printer.OutputMode.json, logFile); - } - }). - then(() => { - const categoryData = Object.keys(categories).map(name => categories[name]); - const maxTitleLen = Math.max(...categoryData.map(({title}) => title.length)); - - console.log('\nLighthouse version:', results.lhr.lighthouseVersion); - - console.log('\nAudit scores:'); - categoryData.forEach(({title, score}) => { - const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1); - const paddedScore = (score * 100).toFixed(0).padStart(3); - console.log(` - ${paddedTitle} ${paddedScore} / 100`); - }); - }). - then(() => categories.pwa.score * 100); + if (logFile) { + console.log(`\nSaving results in '${logFile}'...`); + console.log(`(LightHouse viewer: ${VIEWER_URL})`); + + await printer.write(report, printer.OutputMode.json, logFile); + } + + const categoryData = Object.keys(categories).map(name => categories[name]); + const maxTitleLen = Math.max(...categoryData.map(({title}) => title.length)); + + console.log(`\nLighthouse version: ${lhVersion}`); + + console.log('\nAudit scores:'); + categoryData.forEach(({title, score}) => { + const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1); + const paddedScore = (score * 100).toFixed(0).padStart(3); + console.log(` - ${paddedTitle} ${paddedScore} / 100`); + }); + + return categories.pwa.score * 100; } function skipHttpsAudits(config) { From 17ea00068e4c80db896caf2e36ad50916b37dece Mon Sep 17 00:00:00 2001 From: George Kalpakas Date: Wed, 17 Apr 2019 09:36:50 +0300 Subject: [PATCH 2/2] ci(docs-infra): increase wait for SW on localhost to avoid CI flakes The server used for testing on localhost has less optimizations (e.g. serves uncompressed files), so we need to wait longer the ServiceWorker to be loaded and registered to allow Lighthouse to reliably detect it, especially on slower environments (e.g. CI). Related: https://github.com/GoogleChrome/lighthouse/issues/5527#issuecomment-483710849 Fixes #29910 --- .circleci/config.yml | 10 ++-------- aio/scripts/test-pwa-score.js | 23 ++++++++++++++++++----- 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 68d7ca043c3eb..dc1097322c495 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -249,10 +249,7 @@ jobs: - run: yarn --cwd aio lint # Run PWA-score tests # (Run before unit and e2e tests, which destroy the `dist/` directory.) - # Temporarily lowering the min required PWA score to avoid flakes on CI. - # TODO(gkalpak): Re-enable once https://github.com/angular/angular/issues/29910 is resolved. - # - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE - - run: yarn --cwd aio test-pwa-score-localhost 70 + - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE # Check the bundle sizes. # (Run before unit and e2e tests, which destroy the `dist/` directory.) - run: yarn --cwd aio payload-size @@ -287,10 +284,7 @@ jobs: - run: yarn --cwd aio build-local --progress=false # Run PWA-score tests # (Run before unit and e2e tests, which destroy the `dist/` directory.) - # Temporarily lowering the min required PWA score to avoid flakes on CI. - # TODO(gkalpak): Re-enable once https://github.com/angular/angular/issues/29910 is resolved. - # - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE - - run: yarn --cwd aio test-pwa-score-localhost 70 + - run: yarn --cwd aio test-pwa-score-localhost $CI_AIO_MIN_PWA_SCORE # Run unit tests - run: yarn --cwd aio test --progress=false --watch=false # Run e2e tests diff --git a/aio/scripts/test-pwa-score.js b/aio/scripts/test-pwa-score.js index b95d4eba6ae86..2b1bff2bfdd8c 100644 --- a/aio/scripts/test-pwa-score.js +++ b/aio/scripts/test-pwa-score.js @@ -16,12 +16,12 @@ const chromeLauncher = require('chrome-launcher'); const lighthouse = require('lighthouse'); const printer = require('lighthouse/lighthouse-cli/printer'); -const config = require('lighthouse/lighthouse-core/config/default-config.js'); const logger = require('lighthouse-logger'); // Constants const CHROME_LAUNCH_OPTS = {}; const LIGHTHOUSE_FLAGS = {logLevel: 'info'}; +const LONG_WAIT_FOR_SW_DELAY = 5000; const SKIPPED_HTTPS_AUDITS = ['redirects-http']; const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/'; @@ -37,12 +37,18 @@ _main(process.argv.slice(2)); async function _main(args) { const {url, minScore, logFile} = parseInput(args); const isOnHttp = /^http:/.test(url); + const isOnLocalhost = /\/\/localhost\b/.test(url); + const config = {extends: 'lighthouse:default'}; console.log(`Running PWA audit for '${url}'...`); - if (isOnHttp) { - skipHttpsAudits(config); - } + // If testing on HTTP, skip HTTPS-specific tests. + // (Note: Browsers special-case localhost and run ServiceWorker even on HTTP.) + if (isOnHttp) skipHttpsAudits(config); + + // If testing on localhost, where the server has less optimizations (e.g. no file compression), + // wait longer for the ServiceWorker to be registered, so Lighthouse can reliably detect it. + if (isOnLocalhost) waitLongerForSw(config); logger.setLevel(LIGHTHOUSE_FLAGS.logLevel); @@ -124,5 +130,12 @@ async function processResults(results, logFile) { function skipHttpsAudits(config) { console.info(`Skipping HTTPS-related audits (${SKIPPED_HTTPS_AUDITS.join(', ')})...`); - config.settings.skipAudits = SKIPPED_HTTPS_AUDITS; + const settings = config.settings || (config.settings = {}); + settings.skipAudits = SKIPPED_HTTPS_AUDITS; +} + +function waitLongerForSw(config) { + console.info(`Will wait longer for ServiceWorker (${LONG_WAIT_FOR_SW_DELAY}ms)...`); + const passes = config.passes || (config.passes = []); + passes.push({passName: 'defaultPass', pauseAfterLoadMs: LONG_WAIT_FOR_SW_DELAY}); }