diff --git a/aio/scripts/test-pwa-score.js b/aio/scripts/test-pwa-score.js index fcdec2e344..d8a48ecafa 100644 --- a/aio/scripts/test-pwa-score.js +++ b/aio/scripts/test-pwa-score.js @@ -1,4 +1,5 @@ #!/bin/env node +'use strict'; /** * Usage: @@ -9,7 +10,7 @@ * Fails if the score is below ``. * If `` is defined, the full results will be logged there. * - * (Skips HTTPS-related audits, when run for HTTP URL.) + * (Skips HTTPS-related audits, when run for an HTTP URL.) */ // Imports @@ -20,16 +21,11 @@ const logger = require('lighthouse-logger'); // Constants const CHROME_LAUNCH_OPTS = {chromeFlags: ['--headless']}; -const LIGHTHOUSE_FLAGS = {logLevel: 'info'}; +const LIGHTHOUSE_FLAGS = {logLevel: process.env.CI ? 'error' : 'info'}; // Be less verbose on CI. const SKIPPED_HTTPS_AUDITS = ['redirects-http', 'uses-http2']; -const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer/'; +const VIEWER_URL = 'https://googlechrome.github.io/lighthouse/viewer'; const WAIT_FOR_SW_DELAY = 5000; -// Be less verbose on CI. -if (process.env.CI) { - LIGHTHOUSE_FLAGS.logLevel = 'error'; -} - // Run _main(process.argv.slice(2)); @@ -42,7 +38,7 @@ async function _main(args) { // Since the Angular ServiceWorker waits for the app to stabilize before registering, // wait a few seconds after load to allow Lighthouse to reliably detect it. passes: [{passName: 'defaultPass', pauseAfterLoadMs: WAIT_FOR_SW_DELAY}], - } + }; console.log(`Running PWA audit for '${url}'...`); @@ -53,9 +49,12 @@ async function _main(args) { logger.setLevel(LIGHTHOUSE_FLAGS.logLevel); try { + console.log(''); + const startTime = Date.now(); const results = await launchChromeAndRunLighthouse(url, LIGHTHOUSE_FLAGS, config); const score = await processResults(results, logFile); evaluateScore(minScore, score); + console.log(`\n(Completed in ${((Date.now() - startTime) / 1000).toFixed(1)}s.)\n`); } catch (err) { onError(err); } @@ -63,14 +62,18 @@ async function _main(args) { function evaluateScore(expectedScore, actualScore) { console.log('\nLighthouse PWA score:'); - console.log(` - Expected: ${expectedScore.toFixed(0).padStart(3)} / 100 (or higher)`); - console.log(` - Actual: ${actualScore.toFixed(0).padStart(3)} / 100\n`); + console.log(` - Expected: ${formatScore(expectedScore)} (or higher)`); + console.log(` - Actual: ${formatScore(actualScore)}`); if (isNaN(actualScore) || (actualScore < expectedScore)) { throw new Error(`PWA score is too low. (${actualScore} < ${expectedScore})`); } } +function formatScore(score) { + return `${(score * 100).toFixed(0).padStart(3)}`; +} + async function launchChromeAndRunLighthouse(url, flags, config) { const chrome = await chromeLauncher.launch(CHROME_LAUNCH_OPTS); flags.port = chrome.port; @@ -84,18 +87,24 @@ async function launchChromeAndRunLighthouse(url, flags, config) { function onError(err) { console.error(err); + console.error(''); process.exit(1); } function parseInput(args) { - const url = args[0]; - const minScore = Number(args[1]); - const logFile = args[2]; + const [url, minScoreRaw, logFile] = args; if (!url) { - onError('Invalid arguments: not specified.'); - } else if (isNaN(minScore)) { - onError('Invalid arguments: not specified or not a number.'); + onError('Invalid arguments: not specified.'); + } else if (!minScoreRaw) { + onError('Invalid arguments: not specified.'); + } + + const minScore = Number(minScoreRaw) / 100; + const isValid = (0 <= minScore) && (minScore <= 1); + + if (!isValid) { + onError(`Invalid arguments: has non-numeric or out-of-range values: ${minScoreRaw}`); } return {url, minScore, logFile}; @@ -108,28 +117,26 @@ async function processResults(results, logFile) { if (logFile) { console.log(`\nSaving results in '${logFile}'...`); - console.log(`(LightHouse viewer: ${VIEWER_URL})`); + 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 maxTitleLen = Math.max(...Object.values(categories).map(({title}) => title.length)); + Object.keys(categories).sort().forEach(cat => { + const {title, score} = categories[cat]; const paddedTitle = `${title}:`.padEnd(maxTitleLen + 1); - const paddedScore = (score * 100).toFixed(0).padStart(3); - console.log(` - ${paddedTitle} ${paddedScore} / 100`); + + console.log(` - ${paddedTitle} ${formatScore(score)}`); }); - return categories.pwa.score * 100; + return categories.pwa.score; } function skipHttpsAudits(config) { - console.info(`Skipping HTTPS-related audits (${SKIPPED_HTTPS_AUDITS.join(', ')})...`); - const settings = config.settings || (config.settings = {}); - settings.skipAudits = SKIPPED_HTTPS_AUDITS; + console.log(` Skipping HTTPS-related audits: ${SKIPPED_HTTPS_AUDITS.join(', ')}`); + config.settings = {...config.settings, skipAudits: SKIPPED_HTTPS_AUDITS}; }