Skip to content

Commit

Permalink
tests: add type checking to cli/tests (#6874)
Browse files Browse the repository at this point in the history
  • Loading branch information
connorjclark authored and brendankenny committed Jan 8, 2019
1 parent 809da7b commit bb3fcdd
Show file tree
Hide file tree
Showing 12 changed files with 80 additions and 114 deletions.
3 changes: 3 additions & 0 deletions lighthouse-cli/test/cli/cli-flags-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,14 @@ describe('CLI bin', function() {
getFlags('chrome://version');
const yargs = require('yargs');

// @ts-ignore - getGroups is private
const optionGroups = yargs.getGroups();
/** @type {string[]} */
const allOptions = [];
Object.keys(optionGroups).forEach(key => {
allOptions.push(...optionGroups[key]);
});
// @ts-ignore - getUsageInstance is private
const optionsWithDescriptions = Object.keys(yargs.getUsageInstance().getDescriptions());

allOptions.forEach(opt => {
Expand Down
2 changes: 1 addition & 1 deletion lighthouse-cli/test/cli/printer-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('Printer', () => {
});

it('rejects invalid output paths', () => {
const path = undefined;
const path = /** @type {any} */ (undefined);
assert.notEqual(Printer.checkOutputPath(path), path);
});

Expand Down
13 changes: 11 additions & 2 deletions lighthouse-cli/test/cli/run-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,21 @@ describe('CLI run', function() {
const timeoutFlag = `--max-wait-for-load=${9000}`;
const flags = getFlags(`--output=json --output-path=${filename} ${timeoutFlag} ${url}`);
return run.runLighthouse(url, flags, fastConfig).then(passedResults => {
if (!passedResults) {
assert.fail('no results');
return;
}

const {lhr} = passedResults;
assert.ok(fs.existsSync(filename));
/** @type {LH.Result} */
const results = JSON.parse(fs.readFileSync(filename, 'utf-8'));
assert.equal(results.audits.viewport.rawValue, false);

// passed results match saved results
assert.strictEqual(results.fetchTime, lhr.fetchTime);
assert.strictEqual(results.url, lhr.url);
assert.strictEqual(results.requestedUrl, lhr.requestedUrl);
assert.strictEqual(results.finalUrl, lhr.finalUrl);
assert.strictEqual(results.audits.viewport.rawValue, lhr.audits.viewport.rawValue);
assert.strictEqual(
Object.keys(results.audits).length,
Expand All @@ -57,7 +64,9 @@ describe('flag coercing', () => {

describe('saveResults', () => {
it('will quit early if we\'re in gather mode', async () => {
const result = await run.saveResults(undefined, {gatherMode: true});
const result = await run.saveResults(
/** @type {LH.RunnerResult} */ ({}),
/** @type {LH.CliFlags} */ ({gatherMode: true}));
assert.equal(result, undefined);
});
});
Expand Down
39 changes: 0 additions & 39 deletions lighthouse-cli/test/global-mocha-hooks.js

This file was deleted.

15 changes: 7 additions & 8 deletions lighthouse-cli/test/smokehouse/run-smoke.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const execAsync = promisify(require('child_process').exec);
const {server, serverForOffline} = require('../fixtures/static-server');
const log = require('lighthouse-logger');

/** @param {string} str */
const purpleify = str => `${log.purple}${str}${log.reset}`;
const smokehouseDir = 'lighthouse-cli/test/smokehouse/';

Expand Down Expand Up @@ -88,18 +89,15 @@ const SMOKETESTS = [{

/**
* Display smokehouse output from child process
* @param {{id: string, process: NodeJS.Process} || {id: string, error: Error & {stdout : NodeJS.WriteStream, stderr: NodeJS.WriteStream}}} result
* @param {{id: string, stdout: string, stderr: string, error?: Error}} result
*/
function displaySmokehouseOutput(result) {
console.log(`\n${purpleify(result.id)} smoketest results:`);
if (result.error) {
console.log(result.error.message);
process.stdout.write(result.error.stdout);
process.stderr.write(result.error.stderr);
} else {
process.stdout.write(result.process.stdout);
process.stderr.write(result.process.stderr);
}
process.stdout.write(result.stdout);
process.stderr.write(result.stderr);
console.timeEnd(`smoketest-${result.id}`);
console.log(`${purpleify(result.id)} smoketest complete. \n`);
return result;
Expand All @@ -124,8 +122,8 @@ async function runSmokehouse(smokes) {

// The promise ensures we output immediately, even if the process errors
const p = execAsync(cmd, {timeout: 6 * 60 * 1000, encoding: 'utf8'})
.then(cp => ({id: id, process: cp}))
.catch(err => ({id: id, error: err}))
.then(cp => ({id, ...cp}))
.catch(err => ({id, stdout: err.stdout, stderr: err.stderr, error: err}))
.then(result => displaySmokehouseOutput(result));

// If the machine is terribly slow, we'll run all smoketests in succession, not parallel
Expand Down Expand Up @@ -200,6 +198,7 @@ async function cli() {
if (failingTests.length && (process.env.RETRY_SMOKES || process.env.CI)) {
console.log('Retrying failed tests...');
for (const failedResult of failingTests) {
/** @type {number} */
const resultIndex = smokeResults.indexOf(failedResult);
const smokeDefn = smokeDefns.get(failedResult.id);
smokeResults[resultIndex] = (await runSmokehouse([smokeDefn]))[0];
Expand Down
4 changes: 4 additions & 0 deletions lighthouse-cli/test/smokehouse/seo/expectations.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,10 @@
const BASE_URL = 'http://localhost:10200/seo/';
const URLSearchParams = require('url').URLSearchParams;

/**
* @param {[string, string][]} headers
* @return {string}
*/
function headersParam(headers) {
const headerString = new URLSearchParams(headers).toString();
return new URLSearchParams([['extra_header', headerString]]).toString();
Expand Down
55 changes: 38 additions & 17 deletions lighthouse-cli/test/smokehouse/smokehouse.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,22 @@
*/
'use strict';

/**
* @typedef {{path: string, actual: *, expected: *}} Difference
*/

/**
* @typedef {{category: string, actual: *, expected: *, equal: boolean, diff?: Difference | null}} Comparison
*/

/**
* @typedef {Pick<LH.Result, 'audits' | 'finalUrl' | 'requestedUrl'> & {errorCode?: string}} ExpectedLHR
*/

/**
* @typedef {{audits: Comparison[], errorCode: Comparison, finalUrl: Comparison}} LHRComparison
*/

/* eslint-disable no-console */

const fs = require('fs');
Expand All @@ -19,7 +35,6 @@ const PAGE_HUNG_EXIT_CODE = 68;
const RETRIES = 3;
const NUMERICAL_EXPECTATION_REGEXP = /^(<=?|>=?)((\d|\.)+)$/;


/**
* Attempt to resolve a path locally. If this fails, attempts to locate the path
* relative to the current working directory.
Expand All @@ -43,10 +58,10 @@ function resolveLocalOrCwd(payloadPath) {
* @param {string} url
* @param {string} configPath
* @param {boolean=} isDebug
* @return {!LighthouseResults}
* @return {ExpectedLHR}
*/
function runLighthouse(url, configPath, isDebug) {
isDebug = isDebug || process.env.SMOKEHOUSE_DEBUG;
isDebug = isDebug || Boolean(process.env.SMOKEHOUSE_DEBUG);

const command = 'node';
const outputPath = `smokehouse-${Math.round(Math.random() * 100000)}.report.json`;
Expand Down Expand Up @@ -137,6 +152,8 @@ function matchesExpectation(actual, expected) {
return actual < number;
case '<=':
return actual <= number;
default:
throw new Error(`unexpected operator ${operator}`);
}
} else if (typeof actual === 'string' && expected instanceof RegExp && expected.test(actual)) {
return true;
Expand All @@ -157,7 +174,7 @@ function matchesExpectation(actual, expected) {
* @param {string} path
* @param {*} actual
* @param {*} expected
* @return {({path: string, actual: *, expected: *}|null)}
* @return {(Difference|null)}
*/
function findDifference(path, actual, expected) {
if (matchesExpectation(actual, expected)) {
Expand Down Expand Up @@ -199,9 +216,9 @@ function findDifference(path, actual, expected) {

/**
* Collate results into comparisons of actual and expected scores on each audit.
* @param {{finalUrl: string, audits: !Array, errorCode: string}} actual
* @param {{finalUrl: string, audits: !Array, errorCode: string}} expected
* @return {{finalUrl: !Object, audits: !Array<!Object>}}
* @param {ExpectedLHR} actual
* @param {ExpectedLHR} expected
* @return {LHRComparison}
*/
function collateResults(actual, expected) {
const auditNames = Object.keys(expected.audits);
Expand All @@ -224,28 +241,30 @@ function collateResults(actual, expected) {
});

return {
finalUrl: {
category: 'final url',
actual: actual.finalUrl,
expected: expected.finalUrl,
equal: actual.finalUrl === expected.finalUrl,
},
audits: collatedAudits,
errorCode: {
category: 'error code',
actual: actual.errorCode,
expected: expected.errorCode,
equal: actual.errorCode === expected.errorCode,
},
finalUrl: {
category: 'final url',
actual: actual.finalUrl,
expected: expected.finalUrl,
equal: actual.finalUrl === expected.finalUrl,
},
};
}

/**
* Log the result of an assertion of actual and expected results.
* @param {{category: string, equal: boolean, diff: ?Object, actual: boolean, expected: boolean}} assertion
* @param {Comparison} assertion
*/
function reportAssertion(assertion) {
// @ts-ignore - this doesn't exist now but could one day, so try not to break the future
const _toJSON = RegExp.prototype.toJSON;
// @ts-ignore
// eslint-disable-next-line no-extend-native
RegExp.prototype.toJSON = RegExp.prototype.toString;

Expand Down Expand Up @@ -273,14 +292,15 @@ function reportAssertion(assertion) {
}
}

// @ts-ignore
// eslint-disable-next-line no-extend-native
RegExp.prototype.toJSON = _toJSON;
}

/**
* Log all the comparisons between actual and expected test results, then print
* summary. Returns count of passed and failed tests.
* @param {{finalUrl: !Object, audits: !Array<!Object>, errorCode: !Object}} results
* @param {LHRComparison} results
* @return {{passed: number, failed: number}}
*/
function report(results) {
Expand Down Expand Up @@ -316,11 +336,12 @@ const cli = yargs
'expectations-path': 'The path to the expected audit results file',
'debug': 'Save the artifacts along with the output',
})
.require('config-path')
.require('expectations-path')
.require('config-path', true)
.require('expectations-path', true)
.argv;

const configPath = resolveLocalOrCwd(cli['config-path']);
/** @type {ExpectedLHR[]} */
const expectations = require(resolveLocalOrCwd(cli['expectations-path']));

// Loop sequentially over expectations, comparing against Lighthouse run, and
Expand Down
40 changes: 0 additions & 40 deletions lighthouse-core/test/global-mocha-hooks.js

This file was deleted.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@
"@types/google.analytics": "0.0.39",
"@types/inquirer": "^0.0.35",
"@types/intl-messageformat": "^1.3.0",
"@types/jest": "^23.3.10",
"@types/jpeg-js": "^0.3.0",
"@types/lodash.isequal": "^4.5.2",
"@types/make-dir": "^1.0.3",
Expand Down
8 changes: 2 additions & 6 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,6 @@
"strict": true,
// "listFiles": true,
// "noErrorTruncation": true,
"typeRoots": [
"@types",
"./types"
],

"resolveJsonModule": true,
"diagnostics": true
Expand All @@ -21,11 +17,11 @@
"lighthouse-core/**/*.js",
"clients/**/*.js",
"build/**/*.js",
"./types/*.d.ts",
"./types/**/*.d.ts",
],
"exclude": [
"lighthouse-cli/test/**/*.js",
"lighthouse-core/test/**/*.js",
"clients/test/**/*.js",
"lighthouse-cli/test/fixtures/**/*.js",
]
}
9 changes: 8 additions & 1 deletion types/lighthouse-logger/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,15 @@ declare module 'lighthouse-logger' {
export function time(status: Status, level?: string): void;
export function timeEnd(status: Status, level?: string): void;
export function reset(): string;
export const cross: string;
export const dim: string;
export const tick: string;
export const bold: string;
export const purple: string;
export function redify(message: any): string;
export function greenify(message: any): string;
/** Retrieves and clears all stored time entries */
export function takeTimeEntries(): PerformanceEntry[];
export function getTimeEntries(): PerformanceEntry[];
export var events: import('events').EventEmitter;
export const events: import('events').EventEmitter;
}
Loading

0 comments on commit bb3fcdd

Please sign in to comment.