Skip to content

Commit

Permalink
feat: add title for before and after hooks (#26523)
Browse files Browse the repository at this point in the history
  • Loading branch information
richard174 authored Aug 21, 2023
1 parent 2f6148b commit bcc30bc
Show file tree
Hide file tree
Showing 10 changed files with 372 additions and 34 deletions.
2 changes: 1 addition & 1 deletion docs/src/puppeteer-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ test.describe('Playwright homepage', () => {
1. Each Playwright Test file has explicit import of the `test` and `expect` functions
1. Test function is marked with `async`
1. Playwright Test is given a `page` as one of its parameters. This is one of the many [useful fixtures](./api/class-fixtures) in Playwright Test.
Playwright Test creates an isolated [Page] object for each test. However, if you'd like to reuse a single [Page] object between multiple tests, you can create your own in [`method: Test.beforeAll`] and close it in [`method: Test.afterAll`].
Playwright Test creates an isolated [Page] object for each test. However, if you'd like to reuse a single [Page] object between multiple tests, you can create your own in [`method: Test.beforeAll#1`] and close it in [`method: Test.afterAll#1`].
1. Locator creation with [`method: Page.locator`] is one of the few methods that is sync.
1. Use [assertions](./test-assertions) to verify the state instead of `page.$eval()`.

Expand Down
149 changes: 138 additions & 11 deletions docs/src/test-api/class-test.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ Test function that takes one or two arguments: an object with fixtures and optio



## method: Test.afterAll
## method: Test.afterAll#1
* since: v1.10

Declares an `afterAll` hook that is executed once per worker after all tests.
Expand All @@ -64,15 +64,42 @@ test.afterAll(async () => {
});
```

### param: Test.afterAll.hookFunction
### param: Test.afterAll#1.hookFunction
* since: v1.10
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with worker fixtures and optional [TestInfo].


## method: Test.afterAll#2
* since: v1.38

## method: Test.afterEach
Declares an `afterAll` hook with a title that is executed once per worker after all tests.

**Usage**

```js
test.afterAll('Teardown', async () => {
console.log('Done with tests');
// ...
});
```

### param: Test.afterAll#2.title
* since: v1.38
- `title` <[string]>

Hook title.

### param: Test.afterAll#2.hookFunction
* since: v1.38
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with worker fixtures and optional [TestInfo].



## method: Test.afterEach#1
* since: v1.10

Declares an `afterEach` hook that is executed after each test.
Expand Down Expand Up @@ -100,14 +127,50 @@ test('my test', async ({ page }) => {
});
```

### param: Test.afterEach.hookFunction
### param: Test.afterEach#1.hookFunction
* since: v1.10
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].


## method: Test.beforeAll
## method: Test.afterEach#2
* since: v1.38

Declares an `afterEach` hook with a title that is executed after each test.

**Usage**

```js title="example.spec.ts"
import { test, expect } from '@playwright/test';

test.afterEach('Status check', async ({ page }, testInfo) => {
console.log(`Finished ${testInfo.title} with status ${testInfo.status}`);

if (testInfo.status !== testInfo.expectedStatus)
console.log(`Did not run as expected, ended up at ${page.url()}`);
});

test('my test', async ({ page }) => {
// ...
});
```

### param: Test.afterEach#2.title
* since: v1.38
- `title` <[string]>

Hook title.

### param: Test.afterEach#2.hookFunction
* since: v1.38
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].



## method: Test.beforeAll#1
* since: v1.10

Declares a `beforeAll` hook that is executed once per worker process before all tests.
Expand All @@ -118,7 +181,7 @@ When called in the scope of a test file, runs before all tests in the file. When

Note that worker process is restarted on test failures, and `beforeAll` hook runs again in the new worker. Learn more about [workers and failures](../test-retries.md).

You can use [`method: Test.afterAll`] to teardown any resources set up in `beforeAll`.
You can use [`method: Test.afterAll#1`] to teardown any resources set up in `beforeAll`.

**Usage**

Expand All @@ -138,15 +201,47 @@ test('my test', async ({ page }) => {
});
```

### param: Test.beforeAll.hookFunction
### param: Test.beforeAll#1.hookFunction
* since: v1.10
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with worker fixtures and optional [TestInfo].


## method: Test.beforeAll#2
* since: v1.38

Declares a `beforeAll` hook with a title that is executed once per worker process before all tests.

## method: Test.beforeEach
**Usage**

```js title="example.spec.ts"
import { test, expect } from '@playwright/test';

test.beforeAll('Setup', async () => {
console.log('Before tests');
});

test('my test', async ({ page }) => {
// ...
});
```

### param: Test.beforeAll#2.title
* since: v1.38
- `title` <[string]>

Hook title.

### param: Test.beforeAll#2.hookFunction
* since: v1.38
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with worker fixtures and optional [TestInfo].



## method: Test.beforeEach#1
* since: v1.10

Declares a `beforeEach` hook that is executed before each test.
Expand All @@ -157,7 +252,7 @@ When called in the scope of a test file, runs before each test in the file. When

You can access all the same [Fixtures] as the test function itself, and also the [TestInfo] object that gives a lot of useful information. For example, you can navigate the page before starting the test.

You can use [`method: Test.afterEach`] to teardown any resources set up in `beforeEach`.
You can use [`method: Test.afterEach#1`] to teardown any resources set up in `beforeEach`.

**Usage**

Expand All @@ -174,13 +269,45 @@ test('my test', async ({ page }) => {
});
```

### param: Test.beforeEach.hookFunction
### param: Test.beforeEach#1.hookFunction
* since: v1.10
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].


## method: Test.beforeEach#2
* since: v1.38

Declares a `beforeEach` hook with a title that is executed before each test.

**Usage**

```js title="example.spec.ts"
import { test, expect } from '@playwright/test';

test.beforeEach('Open start URL', async ({ page }, testInfo) => {
console.log(`Running ${testInfo.title}`);
await page.goto('https://my.start.url/');
});

test('my test', async ({ page }) => {
expect(page.url()).toBe('https://my.start.url/');
});
```

### param: Test.beforeEach#2.title
* since: v1.38
- `title` <[string]>

Hook title.

### param: Test.beforeEach#2.hookFunction
* since: v1.38
- `hookFunction` <[function]\([Fixtures], [TestInfo]\)>

Hook function that takes one or two arguments: an object with fixtures and optional [TestInfo].



## method: Test.describe#1
Expand Down Expand Up @@ -1057,7 +1184,7 @@ test('skip in WebKit', async ({ page, browserName }) => {
});
```
Skip from [`method: Test.beforeEach`] hook:
Skip from [`method: Test.beforeEach#1`] hook:
```js
import { test, expect } from '@playwright/test';
Expand Down
6 changes: 3 additions & 3 deletions docs/src/test-api/class-testinfo.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* since: v1.10
* langs: js

`TestInfo` contains information about currently running test. It is available to test functions, [`method: Test.beforeEach`], [`method: Test.afterEach`], [`method: Test.beforeAll`] and [`method: Test.afterAll`] hooks, and test-scoped fixtures. `TestInfo` provides utilities to control test execution: attach files, update test timeout, determine which test is currently running and whether it was retried, etc.
`TestInfo` contains information about currently running test. It is available to test functions, [`method: Test.beforeEach#1`], [`method: Test.afterEach#1`], [`method: Test.beforeAll#1`] and [`method: Test.afterAll#1`] hooks, and test-scoped fixtures. `TestInfo` provides utilities to control test execution: attach files, update test timeout, determine which test is currently running and whether it was retried, etc.

```js
import { test, expect } from '@playwright/test';
Expand Down Expand Up @@ -115,7 +115,7 @@ Processed configuration from the [configuration file](../test-configuration.md).
* since: v1.10
- type: <[int]>

The number of milliseconds the test took to finish. Always zero before the test finishes, either successfully or not. Can be used in [`method: Test.afterEach`] hook.
The number of milliseconds the test took to finish. Always zero before the test finishes, either successfully or not. Can be used in [`method: Test.afterEach#1`] hook.


## property: TestInfo.error
Expand Down Expand Up @@ -403,7 +403,7 @@ Suffix used to differentiate snapshots between multiple test configurations. For
* since: v1.10
- type: ?<[TestStatus]<"passed"|"failed"|"timedOut"|"skipped"|"interrupted">>

Actual status for the currently running test. Available after the test has finished in [`method: Test.afterEach`] hook and fixtures.
Actual status for the currently running test. Available after the test has finished in [`method: Test.afterEach#1`] hook and fixtures.

Status is usually compared with the [`property: TestInfo.expectedStatus`]:

Expand Down
2 changes: 1 addition & 1 deletion docs/src/test-retries-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ It is usually better to make your tests isolated, so they can be efficiently run

## Reuse single page between tests

Playwright Test creates an isolated [Page] object for each test. However, if you'd like to reuse a single [Page] object between multiple tests, you can create your own in [`method: Test.beforeAll`] and close it in [`method: Test.afterAll`].
Playwright Test creates an isolated [Page] object for each test. However, if you'd like to reuse a single [Page] object between multiple tests, you can create your own in [`method: Test.beforeAll#1`] and close it in [`method: Test.afterAll#1`].

```js tab=js-js title="example.spec.js"
// @ts-check
Expand Down
6 changes: 3 additions & 3 deletions packages/playwright-test/src/common/test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export class Suite extends Base implements SuitePrivate {
parent?: Suite;
_use: FixturesWithLocation[] = [];
_entries: (Suite | TestCase)[] = [];
_hooks: { type: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', fn: Function, location: Location }[] = [];
_hooks: { type: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', fn: Function, title: string, location: Location }[] = [];
_timeout: number | undefined;
_retries: number | undefined;
_staticAnnotations: Annotation[] = [];
Expand Down Expand Up @@ -187,7 +187,7 @@ export class Suite extends Base implements SuitePrivate {
staticAnnotations: this._staticAnnotations.slice(),
modifiers: this._modifiers.slice(),
parallelMode: this._parallelMode,
hooks: this._hooks.map(h => ({ type: h.type, location: h.location })),
hooks: this._hooks.map(h => ({ type: h.type, location: h.location, title: h.title })),
fileId: this._fileId,
};
}
Expand All @@ -202,7 +202,7 @@ export class Suite extends Base implements SuitePrivate {
suite._staticAnnotations = data.staticAnnotations;
suite._modifiers = data.modifiers;
suite._parallelMode = data.parallelMode;
suite._hooks = data.hooks.map((h: any) => ({ type: h.type, location: h.location, fn: () => { } }));
suite._hooks = data.hooks.map((h: any) => ({ type: h.type, location: h.location, title: h.title, fn: () => { } }));
suite._fileId = data.fileId;
return suite;
}
Expand Down
9 changes: 7 additions & 2 deletions packages/playwright-test/src/common/testType.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,11 +134,16 @@ export class TestTypeImpl {
setCurrentlyLoadingFileSuite(suite);
}

private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, fn: Function) {
private _hook(name: 'beforeEach' | 'afterEach' | 'beforeAll' | 'afterAll', location: Location, title: string | Function, fn?: Function) {
const suite = this._currentSuite(location, `test.${name}()`);
if (!suite)
return;
suite._hooks.push({ type: name, fn, location });
if (typeof title === 'function') {
fn = title;
title = `${name} hook`;
}

suite._hooks.push({ type: name, fn: fn!, title, location });
}

private _configure(location: Location, options: { mode?: 'default' | 'parallel' | 'serial', retries?: number, timeout?: number }) {
Expand Down
6 changes: 3 additions & 3 deletions packages/playwright-test/src/worker/workerMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ export class WorkerMain extends ProcessRunner {
testInfo._timeoutManager.setCurrentRunnable({ type: 'beforeAll', location: hook.location, slot: timeSlot });
await testInfo._runAsStep({
category: 'hook',
title: `${hook.type} hook`,
title: `${hook.title}`,
location: hook.location,
}, async () => {
try {
Expand Down Expand Up @@ -564,7 +564,7 @@ export class WorkerMain extends ProcessRunner {
testInfo._timeoutManager.setCurrentRunnable({ type: 'afterAll', location: hook.location, slot: timeSlot });
await testInfo._runAsStep({
category: 'hook',
title: `${hook.type} hook`,
title: `${hook.title}`,
location: hook.location,
}, async () => {
try {
Expand All @@ -590,7 +590,7 @@ export class WorkerMain extends ProcessRunner {
testInfo._timeoutManager.setCurrentRunnable({ type, location: hook.location, slot: timeSlot });
await testInfo._runAsStep({
category: 'hook',
title: `${hook.type} hook`,
title: `${hook.title}`,
location: hook.location,
}, () => this._fixtureRunner.resolveParametersAndRunFunction(hook.fn, testInfo, 'test'));
} catch (e) {
Expand Down
Loading

0 comments on commit bcc30bc

Please sign in to comment.