mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: remove TestProject.projectSetup (#16321)
There are better ideas to address this issue in more general manner.
This commit is contained in:
parent
706c00d242
commit
7a86e140f5
@ -359,8 +359,6 @@ test('test', async ({ page }) => {
|
||||
});
|
||||
```
|
||||
|
||||
You can also have project-specific setup with [`property: TestProject.projectSetup`]. It will only be executed if at least one test from a specific project should be run, while global setup is always executed at the start of the test session.
|
||||
|
||||
### Capturing trace of failures during global setup
|
||||
|
||||
In some instances, it may be useful to capture a trace of failures encountered during the global setup. In order to do this, you must [start tracing](./api/class-tracing.md#tracing-start) in your setup, and you must ensure that you [stop tracing](./api/class-tracing.md#tracing-stop) if an error occurs before that error is thrown. This can be achieved by wrapping your setup in a `try...catch` block. Here is an example that expands the global setup example to capture a trace.
|
||||
|
||||
@ -163,63 +163,6 @@ Metadata that will be put directly to the test report serialized as JSON.
|
||||
Project name is visible in the report and during test execution.
|
||||
|
||||
|
||||
## property: TestProject.projectSetup
|
||||
* since: v1.25
|
||||
- type: ?<[string]>
|
||||
|
||||
Path to the project-specifc setup file. This file will be required and run before all the tests from this project. It must export a single function that takes a [`TestConfig`] argument.
|
||||
|
||||
Project setup is similar to [`property: TestConfig.globalSetup`], but it is only executed if at least one test from this particular project should be run. Learn more about [global setup and teardown](../test-advanced.md#global-setup-and-teardown).
|
||||
|
||||
```js tab=js-js
|
||||
// playwright.config.js
|
||||
// @ts-check
|
||||
|
||||
/** @type {import('@playwright/test').PlaywrightTestConfig} */
|
||||
const config = {
|
||||
projects: [
|
||||
{
|
||||
name: 'Admin Portal',
|
||||
projectSetup: './setup-admin',
|
||||
},
|
||||
{
|
||||
name: 'Customer Portal',
|
||||
projectSetup: './setup-customer',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
module.exports = config;
|
||||
```
|
||||
|
||||
```js tab=js-ts
|
||||
// playwright.config.ts
|
||||
import { type PlaywrightTestConfig } from '@playwright/test';
|
||||
|
||||
const config: PlaywrightTestConfig = {
|
||||
projects: [
|
||||
{
|
||||
name: 'Admin Portal',
|
||||
projectSetup: './setup-admin',
|
||||
},
|
||||
{
|
||||
name: 'Customer Portal',
|
||||
projectSetup: './setup-customer',
|
||||
},
|
||||
],
|
||||
};
|
||||
export default config;
|
||||
```
|
||||
|
||||
## property: TestProject.projectTeardown
|
||||
* since: v1.25
|
||||
- type: ?<[string]>
|
||||
|
||||
Path to the project-specifc teardown file. This file will be required and run after all the tests from this project. It must export a single function. See also [`property: TestProject.projectSetup`].
|
||||
|
||||
Project teardown is similar to [`property: TestConfig.globalTeardown`], but it is only executed if at least one test from this particular project did run. Learn more about [global setup and teardown](../test-advanced.md#global-setup-and-teardown).
|
||||
|
||||
|
||||
## property: TestProject.screenshotsDir
|
||||
* since: v1.10
|
||||
* experimental
|
||||
|
||||
@ -257,10 +257,6 @@ export class Loader {
|
||||
projectConfig.testDir = path.resolve(this._configDir, projectConfig.testDir);
|
||||
if (projectConfig.outputDir !== undefined)
|
||||
projectConfig.outputDir = path.resolve(this._configDir, projectConfig.outputDir);
|
||||
if (projectConfig.projectSetup)
|
||||
projectConfig.projectSetup = resolveScript(projectConfig.projectSetup, this._configDir);
|
||||
if (projectConfig.projectTeardown)
|
||||
projectConfig.projectTeardown = resolveScript(projectConfig.projectTeardown, this._configDir);
|
||||
if ((projectConfig as any).screenshotsDir !== undefined)
|
||||
(projectConfig as any).screenshotsDir = path.resolve(this._configDir, (projectConfig as any).screenshotsDir);
|
||||
if (projectConfig.snapshotDir !== undefined)
|
||||
@ -285,8 +281,6 @@ export class Loader {
|
||||
retries: takeFirst(projectConfig.retries, config.retries, 0),
|
||||
metadata: takeFirst(projectConfig.metadata, config.metadata, undefined),
|
||||
name,
|
||||
_projectSetup: projectConfig.projectSetup,
|
||||
_projectTeardown: projectConfig.projectTeardown,
|
||||
testDir,
|
||||
_respectGitIgnore: respectGitIgnore,
|
||||
snapshotDir,
|
||||
|
||||
@ -394,7 +394,7 @@ export class Runner {
|
||||
|
||||
// 13. Run Global setup.
|
||||
const result: FullResult = { status: 'passed' };
|
||||
const globalTearDown = await this._performGlobalAndProjectSetup(config, rootSuite, [...filesByProject.keys()], result);
|
||||
const globalTearDown = await this._performGlobalSetup(config, rootSuite, [...filesByProject.keys()], result);
|
||||
if (result.status !== 'passed')
|
||||
return result;
|
||||
|
||||
@ -443,7 +443,7 @@ export class Runner {
|
||||
|
||||
// 4. Run Global setup.
|
||||
const result: FullResult = { status: 'passed' };
|
||||
const globalTearDown = await this._performGlobalAndProjectSetup(config, rootSuite, config.projects.filter(p => !options.projectFilter || options.projectFilter.includes(p.name)), result);
|
||||
const globalTearDown = await this._performGlobalSetup(config, rootSuite, config.projects.filter(p => !options.projectFilter || options.projectFilter.includes(p.name)), result);
|
||||
if (result.status !== 'passed')
|
||||
return result;
|
||||
|
||||
@ -576,43 +576,22 @@ export class Runner {
|
||||
return true;
|
||||
}
|
||||
|
||||
private async _performGlobalAndProjectSetup(config: FullConfigInternal, rootSuite: Suite, projects: FullProjectInternal[], result: FullResult): Promise<(() => Promise<void>) | undefined> {
|
||||
type SetupData = {
|
||||
setupFile?: string | null;
|
||||
teardownFile?: string | null;
|
||||
setupResult?: any;
|
||||
};
|
||||
|
||||
const setups: SetupData[] = [];
|
||||
setups.push({
|
||||
setupFile: config.globalSetup,
|
||||
teardownFile: config.globalTeardown,
|
||||
setupResult: undefined,
|
||||
});
|
||||
for (const project of projects) {
|
||||
setups.push({
|
||||
setupFile: project._projectSetup,
|
||||
teardownFile: project._projectTeardown,
|
||||
setupResult: undefined,
|
||||
});
|
||||
}
|
||||
private async _performGlobalSetup(config: FullConfigInternal, rootSuite: Suite, projects: FullProjectInternal[], result: FullResult): Promise<(() => Promise<void>) | undefined> {
|
||||
let globalSetupResult: any = undefined;
|
||||
|
||||
const pluginsThatWereSetUp: TestRunnerPlugin[] = [];
|
||||
const sigintWatcher = new SigIntWatcher();
|
||||
|
||||
const tearDown = async () => {
|
||||
setups.reverse();
|
||||
for (const setup of setups) {
|
||||
await this._runAndReportError(async () => {
|
||||
if (setup.setupResult && typeof setup.setupResult === 'function')
|
||||
await setup.setupResult(this._loader.fullConfig());
|
||||
}, result);
|
||||
await this._runAndReportError(async () => {
|
||||
if (globalSetupResult && typeof globalSetupResult === 'function')
|
||||
await globalSetupResult(this._loader.fullConfig());
|
||||
}, result);
|
||||
|
||||
await this._runAndReportError(async () => {
|
||||
if (setup.setupResult && setup.teardownFile)
|
||||
await (await this._loader.loadGlobalHook(setup.teardownFile))(this._loader.fullConfig());
|
||||
}, result);
|
||||
}
|
||||
await this._runAndReportError(async () => {
|
||||
if (globalSetupResult && config.globalTeardown)
|
||||
await (await this._loader.loadGlobalHook(config.globalTeardown))(this._loader.fullConfig());
|
||||
}, result);
|
||||
|
||||
for (const plugin of pluginsThatWereSetUp.reverse()) {
|
||||
await this._runAndReportError(async () => {
|
||||
@ -637,19 +616,17 @@ export class Runner {
|
||||
pluginsThatWereSetUp.push(plugin);
|
||||
}
|
||||
|
||||
// Then do global setup and project setups.
|
||||
for (const setup of setups) {
|
||||
if (!sigintWatcher.hadSignal()) {
|
||||
if (setup.setupFile) {
|
||||
const hook = await this._loader.loadGlobalHook(setup.setupFile);
|
||||
await Promise.race([
|
||||
Promise.resolve().then(() => hook(this._loader.fullConfig())).then((r: any) => setup.setupResult = r || '<noop>'),
|
||||
sigintWatcher.promise(),
|
||||
]);
|
||||
} else {
|
||||
// Make sure we run the teardown.
|
||||
setup.setupResult = '<noop>';
|
||||
}
|
||||
// Then do global setup.
|
||||
if (!sigintWatcher.hadSignal()) {
|
||||
if (config.globalSetup) {
|
||||
const hook = await this._loader.loadGlobalHook(config.globalSetup);
|
||||
await Promise.race([
|
||||
Promise.resolve().then(() => hook(this._loader.fullConfig())).then((r: any) => globalSetupResult = r || '<noop>'),
|
||||
sigintWatcher.promise(),
|
||||
]);
|
||||
} else {
|
||||
// Make sure we run the teardown.
|
||||
globalSetupResult = '<noop>';
|
||||
}
|
||||
}
|
||||
}, result);
|
||||
|
||||
@ -68,8 +68,6 @@ export interface FullProjectInternal extends FullProjectPublic {
|
||||
_expect: Project['expect'];
|
||||
_screenshotsDir: string;
|
||||
_respectGitIgnore: boolean;
|
||||
_projectSetup?: string;
|
||||
_projectTeardown?: string;
|
||||
}
|
||||
|
||||
export interface ReporterInternal extends Reporter {
|
||||
|
||||
43
packages/playwright-test/types/test.d.ts
vendored
43
packages/playwright-test/types/test.d.ts
vendored
@ -4363,49 +4363,6 @@ interface TestProject {
|
||||
*/
|
||||
name?: string;
|
||||
|
||||
/**
|
||||
* Path to the project-specifc setup file. This file will be required and run before all the tests from this project. It
|
||||
* must export a single function that takes a [`TestConfig`] argument.
|
||||
*
|
||||
* Project setup is similar to
|
||||
* [testConfig.globalSetup](https://playwright.dev/docs/api/class-testconfig#test-config-global-setup), but it is only
|
||||
* executed if at least one test from this particular project should be run. Learn more about
|
||||
* [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
||||
*
|
||||
* ```js
|
||||
* // playwright.config.ts
|
||||
* import { type PlaywrightTestConfig } from '@playwright/test';
|
||||
*
|
||||
* const config: PlaywrightTestConfig = {
|
||||
* projects: [
|
||||
* {
|
||||
* name: 'Admin Portal',
|
||||
* projectSetup: './setup-admin',
|
||||
* },
|
||||
* {
|
||||
* name: 'Customer Portal',
|
||||
* projectSetup: './setup-customer',
|
||||
* },
|
||||
* ],
|
||||
* };
|
||||
* export default config;
|
||||
* ```
|
||||
*
|
||||
*/
|
||||
projectSetup?: string;
|
||||
|
||||
/**
|
||||
* Path to the project-specifc teardown file. This file will be required and run after all the tests from this project. It
|
||||
* must export a single function. See also
|
||||
* [testProject.projectSetup](https://playwright.dev/docs/api/class-testproject#test-project-project-setup).
|
||||
*
|
||||
* Project teardown is similar to
|
||||
* [testConfig.globalTeardown](https://playwright.dev/docs/api/class-testconfig#test-config-global-teardown), but it is
|
||||
* only executed if at least one test from this particular project did run. Learn more about
|
||||
* [global setup and teardown](https://playwright.dev/docs/test-advanced#global-setup-and-teardown).
|
||||
*/
|
||||
projectTeardown?: string;
|
||||
|
||||
/**
|
||||
* The base directory, relative to the config file, for snapshot files created with `toMatchSnapshot`. Defaults to
|
||||
* [testProject.testDir](https://playwright.dev/docs/api/class-testproject#test-project-test-dir).
|
||||
|
||||
@ -416,8 +416,6 @@ test('should have correct types for the config', async ({ runTSC }) => {
|
||||
projects: [
|
||||
{
|
||||
name: 'project name',
|
||||
projectSetup: './projectSetup',
|
||||
projectTeardown: './projectTeardown',
|
||||
}
|
||||
],
|
||||
};
|
||||
|
||||
@ -25,8 +25,8 @@ test('globalSetup and globalTeardown should work', async ({ runInlineTest }) =>
|
||||
globalSetup: './globalSetup',
|
||||
globalTeardown: path.join(__dirname, 'globalTeardown.ts'),
|
||||
projects: [
|
||||
{ name: 'p1', projectSetup: './projectSetup1', projectTeardown: './projectTeardown1' },
|
||||
{ name: 'p2', projectSetup: './projectSetup2', projectTeardown: './projectTeardown2' },
|
||||
{ name: 'p1' },
|
||||
{ name: 'p2' },
|
||||
]
|
||||
};
|
||||
`,
|
||||
@ -40,26 +40,6 @@ test('globalSetup and globalTeardown should work', async ({ runInlineTest }) =>
|
||||
console.log('\\n%%from-global-teardown');
|
||||
};
|
||||
`,
|
||||
'dir/projectSetup1.ts': `
|
||||
module.exports = async () => {
|
||||
console.log('\\n%%from-project-setup-1');
|
||||
};
|
||||
`,
|
||||
'dir/projectTeardown1.ts': `
|
||||
module.exports = async () => {
|
||||
console.log('\\n%%from-project-teardown-1');
|
||||
};
|
||||
`,
|
||||
'dir/projectSetup2.ts': `
|
||||
module.exports = async () => {
|
||||
console.log('\\n%%from-project-setup-2');
|
||||
};
|
||||
`,
|
||||
'dir/projectTeardown2.ts': `
|
||||
module.exports = async () => {
|
||||
console.log('\\n%%from-project-teardown-2');
|
||||
};
|
||||
`,
|
||||
'a.test.js': `
|
||||
const { test } = pwt;
|
||||
test('should work', async ({}, testInfo) => {
|
||||
@ -71,9 +51,7 @@ test('globalSetup and globalTeardown should work', async ({ runInlineTest }) =>
|
||||
expect(result.failed).toBe(0);
|
||||
expect(stripAnsi(result.output).split('\n').filter(line => line.startsWith('%%'))).toEqual([
|
||||
'%%from-global-setup',
|
||||
'%%from-project-setup-2',
|
||||
'%%from-test',
|
||||
'%%from-project-teardown-2',
|
||||
'%%from-global-teardown',
|
||||
]);
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user