feat: add option to fail dependent tests
This commit is contained in:
parent
92e2d01329
commit
7004464433
|
|
@ -94,6 +94,7 @@ export class FullConfigInternal {
|
||||||
reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
|
reporter: takeFirst(configCLIOverrides.reporter, resolveReporters(userConfig.reporter, configDir), [[defaultReporter]]),
|
||||||
reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 15000 }),
|
reportSlowTests: takeFirst(userConfig.reportSlowTests, { max: 5, threshold: 15000 }),
|
||||||
quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
|
quiet: takeFirst(configCLIOverrides.quiet, userConfig.quiet, false),
|
||||||
|
failDependentTests: takeFirst(configCLIOverrides.failDependentTests, userConfig.failDependentTests, false),
|
||||||
projects: [],
|
projects: [],
|
||||||
shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
|
shard: takeFirst(configCLIOverrides.shard, userConfig.shard, null),
|
||||||
updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, 'missing'),
|
updateSnapshots: takeFirst(configCLIOverrides.updateSnapshots, userConfig.updateSnapshots, 'missing'),
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,7 @@ export type ConfigCLIOverrides = {
|
||||||
outputDir?: string;
|
outputDir?: string;
|
||||||
preserveOutputDir?: boolean;
|
preserveOutputDir?: boolean;
|
||||||
quiet?: boolean;
|
quiet?: boolean;
|
||||||
|
failDependentTests?: boolean;
|
||||||
repeatEach?: number;
|
repeatEach?: number;
|
||||||
retries?: number;
|
retries?: number;
|
||||||
reporter?: ReporterDescription[];
|
reporter?: ReporterDescription[];
|
||||||
|
|
|
||||||
|
|
@ -354,6 +354,24 @@ export class TestCase extends Base implements reporterTypes.TestCase {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_appendFailedTestResult(): reporterTypes.TestResult {
|
||||||
|
const result: reporterTypes.TestResult = {
|
||||||
|
retry: this.results.length,
|
||||||
|
parallelIndex: -1,
|
||||||
|
workerIndex: -1,
|
||||||
|
duration: 0,
|
||||||
|
startTime: new Date(),
|
||||||
|
stdout: [],
|
||||||
|
stderr: [],
|
||||||
|
attachments: [],
|
||||||
|
status: 'failed',
|
||||||
|
steps: [],
|
||||||
|
errors: [{ message: 'dependency test failed' }]
|
||||||
|
};
|
||||||
|
this.results.push(result);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
_grepTitle() {
|
_grepTitle() {
|
||||||
const path: string[] = [];
|
const path: string[] = [];
|
||||||
this.parent._collectGrepTitlePath(path);
|
this.parent._collectGrepTitlePath(path);
|
||||||
|
|
|
||||||
|
|
@ -592,6 +592,7 @@ export const baseFullConfig: reporterTypes.FullConfig = {
|
||||||
configFile: '',
|
configFile: '',
|
||||||
rootDir: '',
|
rootDir: '',
|
||||||
quiet: false,
|
quiet: false,
|
||||||
|
failDependentTests: false,
|
||||||
shard: null,
|
shard: null,
|
||||||
updateSnapshots: 'missing',
|
updateSnapshots: 'missing',
|
||||||
updateSourceMethod: 'patch',
|
updateSourceMethod: 'patch',
|
||||||
|
|
|
||||||
|
|
@ -295,6 +295,7 @@ function overridesFromOptions(options: { [key: string]: any }): ConfigCLIOverrid
|
||||||
maxFailures: options.x ? 1 : (options.maxFailures ? parseInt(options.maxFailures, 10) : undefined),
|
maxFailures: options.x ? 1 : (options.maxFailures ? parseInt(options.maxFailures, 10) : undefined),
|
||||||
outputDir: options.output ? path.resolve(process.cwd(), options.output) : undefined,
|
outputDir: options.output ? path.resolve(process.cwd(), options.output) : undefined,
|
||||||
quiet: options.quiet ? options.quiet : undefined,
|
quiet: options.quiet ? options.quiet : undefined,
|
||||||
|
failDependentTests: options.failDependentTests ? options.failDependentTests : undefined,
|
||||||
repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined,
|
repeatEach: options.repeatEach ? parseInt(options.repeatEach, 10) : undefined,
|
||||||
retries: options.retries ? parseInt(options.retries, 10) : undefined,
|
retries: options.retries ? parseInt(options.retries, 10) : undefined,
|
||||||
reporter: resolveReporterOption(options.reporter),
|
reporter: resolveReporterOption(options.reporter),
|
||||||
|
|
@ -375,6 +376,7 @@ const testOptions: [string, string][] = [
|
||||||
['--pass-with-no-tests', `Makes test run succeed even if no tests were found`],
|
['--pass-with-no-tests', `Makes test run succeed even if no tests were found`],
|
||||||
['--project <project-name...>', `Only run tests from the specified list of projects, supports '*' wildcard (default: run all projects)`],
|
['--project <project-name...>', `Only run tests from the specified list of projects, supports '*' wildcard (default: run all projects)`],
|
||||||
['--quiet', `Suppress stdio`],
|
['--quiet', `Suppress stdio`],
|
||||||
|
['--failDependentTests', `fail all `],
|
||||||
['--repeat-each <N>', `Run each test N times (default: 1)`],
|
['--repeat-each <N>', `Run each test N times (default: 1)`],
|
||||||
['--reporter <reporter>', `Reporter to use, comma-separated, can be ${builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${defaultReporter}")`],
|
['--reporter <reporter>', `Reporter to use, comma-separated, can be ${builtInReporters.map(name => `"${name}"`).join(', ')} (default: "${defaultReporter}")`],
|
||||||
['--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`],
|
['--retries <retries>', `Maximum retry count for flaky tests, zero for no retries (default: no retries)`],
|
||||||
|
|
|
||||||
|
|
@ -355,7 +355,7 @@ function createRunTestsTask(): Task<TestRun> {
|
||||||
// We don't want to run the test groups belonging to the projects
|
// We don't want to run the test groups belonging to the projects
|
||||||
// that depend on the projects that failed previously.
|
// that depend on the projects that failed previously.
|
||||||
const phaseTestGroups: TestGroup[] = [];
|
const phaseTestGroups: TestGroup[] = [];
|
||||||
for (const { project, testGroups } of projects) {
|
for (const { project, testGroups, projectSuite } of projects) {
|
||||||
// Inherit extra environment variables from dependencies.
|
// Inherit extra environment variables from dependencies.
|
||||||
let extraEnv: Record<string, string | undefined> = {};
|
let extraEnv: Record<string, string | undefined> = {};
|
||||||
for (const dep of project.deps)
|
for (const dep of project.deps)
|
||||||
|
|
@ -367,8 +367,9 @@ function createRunTestsTask(): Task<TestRun> {
|
||||||
const hasFailedDeps = project.deps.some(p => !successfulProjects.has(p));
|
const hasFailedDeps = project.deps.some(p => !successfulProjects.has(p));
|
||||||
if (!hasFailedDeps)
|
if (!hasFailedDeps)
|
||||||
phaseTestGroups.push(...testGroups);
|
phaseTestGroups.push(...testGroups);
|
||||||
|
else if (project.fullConfig.config.failDependentTests)
|
||||||
|
projectSuite.allTests().forEach(test => test._appendFailedTestResult());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (phaseTestGroups.length) {
|
if (phaseTestGroups.length) {
|
||||||
await dispatcher!.run(phaseTestGroups, extraEnvByProjectId);
|
await dispatcher!.run(phaseTestGroups, extraEnvByProjectId);
|
||||||
await dispatcher.stop();
|
await dispatcher.stop();
|
||||||
|
|
|
||||||
19
packages/playwright/types/test.d.ts
vendored
19
packages/playwright/types/test.d.ts
vendored
|
|
@ -1332,6 +1332,23 @@ interface TestConfig<TestArgs = {}, WorkerArgs = {}> {
|
||||||
*/
|
*/
|
||||||
quiet?: boolean;
|
quiet?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether to automatically fail dependency tests after parent test fails
|
||||||
|
*
|
||||||
|
* **Usage**
|
||||||
|
*
|
||||||
|
* ```js
|
||||||
|
* // playwright.config.ts
|
||||||
|
* import { defineConfig } from '@playwright/test';
|
||||||
|
*
|
||||||
|
* export default defineConfig({
|
||||||
|
* failDependentTests: true
|
||||||
|
* });
|
||||||
|
* ```
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
failDependentTests?: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The number of times to repeat each test, useful for debugging flaky tests.
|
* The number of times to repeat each test, useful for debugging flaky tests.
|
||||||
*
|
*
|
||||||
|
|
@ -1805,6 +1822,8 @@ export interface FullConfig<TestArgs = {}, WorkerArgs = {}> {
|
||||||
*/
|
*/
|
||||||
quiet: boolean;
|
quiet: boolean;
|
||||||
|
|
||||||
|
failDependentTests: boolean;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See [testConfig.reportSlowTests](https://playwright.dev/docs/api/class-testconfig#test-config-report-slow-tests).
|
* See [testConfig.reportSlowTests](https://playwright.dev/docs/api/class-testconfig#test-config-report-slow-tests).
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -894,3 +894,30 @@ test('page.pause() should disable test timeout', async ({ runInlineTest }) => {
|
||||||
expect(result.passed).toBe(1);
|
expect(result.passed).toBe(1);
|
||||||
expect(result.output).toContain('success!');
|
expect(result.output).toContain('success!');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should automatically fail tests when their dependency tests fail', async ({ runInlineTest }) => {
|
||||||
|
const result = await runInlineTest({
|
||||||
|
'playwright.config.js': `
|
||||||
|
module.exports = {
|
||||||
|
failDependentTests: true,
|
||||||
|
projects: [ { testMatch: /dependent\.test\.ts/, dependencies: ['a'] }, { name: 'a', testMatch: /setup\.test\.ts/ } ]
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
'setup.test.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('fail', async ({ page }) => {
|
||||||
|
test.expect(1).toBeFalsy();
|
||||||
|
});
|
||||||
|
`,
|
||||||
|
'dependent.test.ts': `
|
||||||
|
import { test, expect } from '@playwright/test';
|
||||||
|
test('pass', async ({ page }) => {
|
||||||
|
test.expect(0).toBeFalsy();
|
||||||
|
});
|
||||||
|
`
|
||||||
|
}, { workers: 1 });
|
||||||
|
expect(result.exitCode).toBe(1);
|
||||||
|
expect(result.passed).toBe(0);
|
||||||
|
expect(result.failed).toBe(2);
|
||||||
|
expect(result.skipped).toBe(0);
|
||||||
|
});
|
||||||
Loading…
Reference in a new issue