diff --git a/lighthouse-cli/test/smokehouse/readme.md b/lighthouse-cli/test/smokehouse/readme.md index 72c7cdf2cf48..0a5875fe5c57 100644 --- a/lighthouse-cli/test/smokehouse/readme.md +++ b/lighthouse-cli/test/smokehouse/readme.md @@ -64,11 +64,15 @@ Individual elements of an array can be asserted by using numeric properties in a However, if an array literal is used as the expectation, an extra condition is enforced that the actual array _must_ have the same length as the provided expected array. +Arrays can be checked against a subset of elements using the special `_includes` property. The value of `_includes` _must_ be an array. Each assertion in `_includes` will remove the matching item from consideration for the rest. + **Examples**: | Actual | Expected | Result | | -- | -- | -- | | `[{url: 'http://badssl.com'}, {url: 'http://example.com'}]` | `{1: {url: 'http://example.com'}}` | ✅ PASS | | `[{timeInMs: 5}, {timeInMs: 15}]` | `{length: 2}` | ✅ PASS | +| `[{timeInMs: 5}, {timeInMs: 15}]` | `{_includes: [{timeInMs: 5}]}` | ✅ PASS | +| `[{timeInMs: 5}, {timeInMs: 15}]` | `{_includes: [{timeInMs: 5}, {timeInMs: 5}]}` | ❌ FAIL | | `[{timeInMs: 5}, {timeInMs: 15}]` | `[{timeInMs: 5}]` | ❌ FAIL | ### Special environment checks diff --git a/lighthouse-cli/test/smokehouse/report-assert.js b/lighthouse-cli/test/smokehouse/report-assert.js index d58b33563faa..88efaf129585 100644 --- a/lighthouse-cli/test/smokehouse/report-assert.js +++ b/lighthouse-cli/test/smokehouse/report-assert.js @@ -111,6 +111,35 @@ function findDifference(path, actual, expected) { const keyPath = path + keyAccessor; const expectedValue = expected[key]; + if (key === '_includes') { + if (!Array.isArray(expectedValue)) throw new Error('Array subset must be array'); + if (!Array.isArray(actual)) { + return { + path, + actual: 'Actual value is not an array', + expected, + }; + } + + const actualCopy = [...actual]; + for (const expectedEntry of expectedValue) { + const matchingIndex = + actualCopy.findIndex(actualEntry => !findDifference(keyPath, actualEntry, expectedEntry)); + if (matchingIndex !== -1) { + actualCopy.splice(matchingIndex, 1); + continue; + } + + return { + path, + actual: 'Item not found in array', + expected: expectedEntry, + }; + } + + continue; + } + const actualValue = actual[key]; const subDifference = findDifference(keyPath, actualValue, expectedValue); @@ -305,6 +334,12 @@ function collateResults(localConsole, actual, expected) { return makeComparison(auditName + ' audit', actualResult, expectedResult); }); + const timingAssertions = []; + if (expected.lhr.timing) { + const comparison = makeComparison('timing', actual.lhr.timing, expected.lhr.timing); + timingAssertions.push(comparison); + } + /** @type {Comparison[]} */ const requestCountAssertion = []; if (expected.networkRequests) { @@ -322,6 +357,7 @@ function collateResults(localConsole, actual, expected) { ...requestCountAssertion, ...artifactAssertions, ...auditAssertions, + ...timingAssertions, ]; } diff --git a/types/smokehouse.d.ts b/types/smokehouse.d.ts index cd02ae67256f..b2bcc364a08f 100644 --- a/types/smokehouse.d.ts +++ b/types/smokehouse.d.ts @@ -20,6 +20,9 @@ declare global { code?: any; message?: any; }; + timing?: { + entries?: any + } } export type ExpectedRunnerResult = {