chore: fix Mocha test runner suggestion when hooks fail (#9750)
This commit is contained in:
parent
4a365a42b4
commit
232873ae76
@ -25,7 +25,7 @@ The best place to look is an existing test to see how they use the helpers.
|
|||||||
|
|
||||||
## Skipping tests in specific conditions
|
## Skipping tests in specific conditions
|
||||||
|
|
||||||
To skip tests edit the [TestExpecations](https://github.com/puppeteer/puppeteer/blob/main/test/TestExpectations.json) file. See [test runner documentation](https://github.com/puppeteer/puppeteer/tree/main/tools/mochaRunner) for more details.
|
To skip tests edit the [TestExpectations](https://github.com/puppeteer/puppeteer/blob/main/test/TestExpectations.json) file. See [test runner documentation](https://github.com/puppeteer/puppeteer/tree/main/tools/mochaRunner) for more details.
|
||||||
|
|
||||||
## Running tests
|
## Running tests
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@
|
|||||||
"expectedLineCoverage": 56
|
"expectedLineCoverage": 56
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"parameterDefinitons": {
|
"parameterDefinitions": {
|
||||||
"chrome": {
|
"chrome": {
|
||||||
"PUPPETEER_PRODUCT": "chrome"
|
"PUPPETEER_PRODUCT": "chrome"
|
||||||
},
|
},
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
"../packages/testserver:build"
|
"../packages/testserver:build"
|
||||||
],
|
],
|
||||||
"files": [
|
"files": [
|
||||||
|
"../tools/mochaRunner/**",
|
||||||
"src/**"
|
"src/**"
|
||||||
],
|
],
|
||||||
"output": [
|
"output": [
|
||||||
|
@ -24,7 +24,7 @@ npm run build && npm run test -- --test-suite chrome-headless
|
|||||||
## TestSuites.json
|
## TestSuites.json
|
||||||
|
|
||||||
Define test suites via the `testSuites` attribute. `parameters` can be used in the `TestExpectations.json` to disable tests
|
Define test suites via the `testSuites` attribute. `parameters` can be used in the `TestExpectations.json` to disable tests
|
||||||
based on parameters. The meaning for parameters is defined in `parameterDefinitons` which tell what env object corresponds
|
based on parameters. The meaning for parameters is defined in `parameterDefinitions` which tell what env object corresponds
|
||||||
to the given parameter.
|
to the given parameter.
|
||||||
|
|
||||||
## TestExpectations.json
|
## TestExpectations.json
|
||||||
|
@ -31,10 +31,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
extendProcessEnv,
|
extendProcessEnv,
|
||||||
filterByPlatform,
|
filterByPlatform,
|
||||||
prettyPrintJSON,
|
|
||||||
readJSON,
|
readJSON,
|
||||||
filterByParameters,
|
filterByParameters,
|
||||||
getExpectationUpdates,
|
getExpectationUpdates,
|
||||||
|
printSuggestions,
|
||||||
} from './utils.js';
|
} from './utils.js';
|
||||||
|
|
||||||
function getApplicableTestSuites(
|
function getApplicableTestSuites(
|
||||||
@ -109,7 +109,7 @@ async function main() {
|
|||||||
|
|
||||||
const env = extendProcessEnv([
|
const env = extendProcessEnv([
|
||||||
...parameters.map(param => {
|
...parameters.map(param => {
|
||||||
return parsedSuitesFile.parameterDefinitons[param];
|
return parsedSuitesFile.parameterDefinitions[param];
|
||||||
}),
|
}),
|
||||||
{
|
{
|
||||||
PUPPETEER_SKIPPED_TEST_CONFIG: JSON.stringify(
|
PUPPETEER_SKIPPED_TEST_CONFIG: JSON.stringify(
|
||||||
@ -211,45 +211,21 @@ async function main() {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
} finally {
|
} finally {
|
||||||
if (!noSuggestions) {
|
if (!noSuggestions) {
|
||||||
const toAdd = recommendations.filter(item => {
|
printSuggestions(
|
||||||
return item.action === 'add';
|
recommendations,
|
||||||
});
|
'add',
|
||||||
if (toAdd.length) {
|
'Add the following to TestExpectations.json to ignore the error:'
|
||||||
console.log(
|
);
|
||||||
'Add the following to TestExpectations.json to ignore the error:'
|
printSuggestions(
|
||||||
);
|
recommendations,
|
||||||
prettyPrintJSON(
|
'remove',
|
||||||
toAdd.map(item => {
|
'Remove the following from the TestExpectations.json to ignore the error:'
|
||||||
return item.expectation;
|
);
|
||||||
})
|
printSuggestions(
|
||||||
);
|
recommendations,
|
||||||
}
|
'update',
|
||||||
const toRemove = recommendations.filter(item => {
|
'Update the following expectations in the TestExpectations.json to ignore the error:'
|
||||||
return item.action === 'remove';
|
);
|
||||||
});
|
|
||||||
if (toRemove.length) {
|
|
||||||
console.log(
|
|
||||||
'Remove the following from the TestExpectations.json to ignore the error:'
|
|
||||||
);
|
|
||||||
prettyPrintJSON(
|
|
||||||
toRemove.map(item => {
|
|
||||||
return item.expectation;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const toUpdate = recommendations.filter(item => {
|
|
||||||
return item.action === 'update';
|
|
||||||
});
|
|
||||||
if (toUpdate.length) {
|
|
||||||
console.log(
|
|
||||||
'Update the following expectations in the TestExpecations.json to ignore the error:'
|
|
||||||
);
|
|
||||||
prettyPrintJSON(
|
|
||||||
toUpdate.map(item => {
|
|
||||||
return item.expectation;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
process.exit(fail ? 1 : 0);
|
process.exit(fail ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ export type TestSuite = z.infer<typeof zTestSuite>;
|
|||||||
|
|
||||||
export const zTestSuiteFile = z.object({
|
export const zTestSuiteFile = z.object({
|
||||||
testSuites: z.array(zTestSuite),
|
testSuites: z.array(zTestSuite),
|
||||||
parameterDefinitons: z.record(z.any()),
|
parameterDefinitions: z.record(z.any()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TestSuiteFile = z.infer<typeof zTestSuiteFile>;
|
export type TestSuiteFile = z.infer<typeof zTestSuiteFile>;
|
||||||
|
@ -57,6 +57,24 @@ export function prettyPrintJSON(json: unknown): void {
|
|||||||
console.log(JSON.stringify(json, null, 2));
|
console.log(JSON.stringify(json, null, 2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function printSuggestions(
|
||||||
|
recommendations: RecommendedExpectation[],
|
||||||
|
action: RecommendedExpectation['action'],
|
||||||
|
message: string
|
||||||
|
): void {
|
||||||
|
const toPrint = recommendations.filter(item => {
|
||||||
|
return item.action === action;
|
||||||
|
});
|
||||||
|
if (toPrint.length) {
|
||||||
|
console.log(message);
|
||||||
|
prettyPrintJSON(
|
||||||
|
toPrint.map(item => {
|
||||||
|
return item.expectation;
|
||||||
|
})
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function filterByParameters(
|
export function filterByParameters(
|
||||||
expectations: TestExpectation[],
|
expectations: TestExpectation[],
|
||||||
parameters: string[]
|
parameters: string[]
|
||||||
@ -88,9 +106,8 @@ export function findEffectiveExpectationForTest(
|
|||||||
.pop();
|
.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
type RecommendedExpecation = {
|
type RecommendedExpectation = {
|
||||||
expectation: TestExpectation;
|
expectation: TestExpectation;
|
||||||
test: MochaTestResult;
|
|
||||||
action: 'remove' | 'add' | 'update';
|
action: 'remove' | 'add' | 'update';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -104,28 +121,42 @@ export function isWildCardPattern(testIdPattern: string): boolean {
|
|||||||
|
|
||||||
export function getExpectationUpdates(
|
export function getExpectationUpdates(
|
||||||
results: MochaResults,
|
results: MochaResults,
|
||||||
expecations: TestExpectation[],
|
expectations: TestExpectation[],
|
||||||
context: {
|
context: {
|
||||||
platforms: NodeJS.Platform[];
|
platforms: NodeJS.Platform[];
|
||||||
parameters: string[];
|
parameters: string[];
|
||||||
}
|
}
|
||||||
): RecommendedExpecation[] {
|
): RecommendedExpectation[] {
|
||||||
const output: RecommendedExpecation[] = [];
|
const output: Map<string, RecommendedExpectation> = new Map();
|
||||||
|
|
||||||
for (const pass of results.passes) {
|
for (const pass of results.passes) {
|
||||||
const expectationEntry = findEffectiveExpectationForTest(expecations, pass);
|
// If an error occurs during a hook
|
||||||
|
// the error not have a file associated with it
|
||||||
|
if (!pass.file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const expectationEntry = findEffectiveExpectationForTest(
|
||||||
|
expectations,
|
||||||
|
pass
|
||||||
|
);
|
||||||
if (expectationEntry && !expectationEntry.expectations.includes('PASS')) {
|
if (expectationEntry && !expectationEntry.expectations.includes('PASS')) {
|
||||||
output.push({
|
addEntry({
|
||||||
expectation: expectationEntry,
|
expectation: expectationEntry,
|
||||||
test: pass,
|
|
||||||
action: 'remove',
|
action: 'remove',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const failure of results.failures) {
|
for (const failure of results.failures) {
|
||||||
|
// If an error occurs during a hook
|
||||||
|
// the error not have a file associated with it
|
||||||
|
if (!failure.file) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const expectationEntry = findEffectiveExpectationForTest(
|
const expectationEntry = findEffectiveExpectationForTest(
|
||||||
expecations,
|
expectations,
|
||||||
failure
|
failure
|
||||||
);
|
);
|
||||||
// If the effective explanation is a wildcard, we recommend adding a new
|
// If the effective explanation is a wildcard, we recommend adding a new
|
||||||
@ -140,7 +171,7 @@ export function getExpectationUpdates(
|
|||||||
getTestResultForFailure(failure)
|
getTestResultForFailure(failure)
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
output.push({
|
addEntry({
|
||||||
expectation: {
|
expectation: {
|
||||||
...expectationEntry,
|
...expectationEntry,
|
||||||
expectations: [
|
expectations: [
|
||||||
@ -148,24 +179,30 @@ export function getExpectationUpdates(
|
|||||||
getTestResultForFailure(failure),
|
getTestResultForFailure(failure),
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
test: failure,
|
|
||||||
action: 'update',
|
action: 'update',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
output.push({
|
addEntry({
|
||||||
expectation: {
|
expectation: {
|
||||||
testIdPattern: getTestId(failure.file, failure.fullTitle),
|
testIdPattern: getTestId(failure.file, failure.fullTitle),
|
||||||
platforms: context.platforms,
|
platforms: context.platforms,
|
||||||
parameters: context.parameters,
|
parameters: context.parameters,
|
||||||
expectations: [getTestResultForFailure(failure)],
|
expectations: [getTestResultForFailure(failure)],
|
||||||
},
|
},
|
||||||
test: failure,
|
|
||||||
action: 'add',
|
action: 'add',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return output;
|
|
||||||
|
function addEntry(value: RecommendedExpectation) {
|
||||||
|
const key = JSON.stringify(value);
|
||||||
|
if (!output.has(key)) {
|
||||||
|
output.set(key, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [...output.values()];
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getTestResultForFailure(
|
export function getTestResultForFailure(
|
||||||
|
Loading…
Reference in New Issue
Block a user