Skip to content
Merged
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 67 additions & 0 deletions docs/src/test-parallel-js.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,73 @@ test.describe('runs in parallel with other describes', () => {
});
```

## Avoiding shared state in parallel tests

Playwright runs tests in separate worker processes, each with its own isolated [BrowserContext], so cookies, storage and in-memory globals are already isolated. Flakiness comes from state that lives *outside* a single test. Here are recipes for the common cases.

### Give each test its own backend data

Two tests that create or edit the same record race with each other. Derive a unique identifier from [`property: TestInfo.testId`] so parallel tests never collide:

```js
import { test, expect } from '@playwright/test';

test('creates an order', async ({ page }, testInfo) => {
const orderId = `order-${testInfo.testId}`;
await page.goto(`/orders/new?id=${orderId}`);
await expect(page.getByText(orderId)).toBeVisible();
});
```

If many tests can share one dataset, create it once per worker instead — see [Isolate test data between parallel workers](#isolate-test-data-between-parallel-workers).

### Write to a unique file path

Multiple tests writing the same path clobber each other. [`method: TestInfo.outputPath`] returns a path scoped to the current test:

```js
import { test } from '@playwright/test';
import fs from 'fs';

test('exports a CSV', async ({ page }, testInfo) => {
const file = testInfo.outputPath('export.csv');
await fs.promises.writeFile(file, 'a,b,c', 'utf8');
});
```

### Don't keep test state in module variables

In [fully parallel](#parallelize-tests-in-a-single-file) mode, tests from one file share a worker and run one after another, so a module-level variable leaks from one test into the next:

```js
Comment thread
yury-s marked this conversation as resolved.
Outdated
// ❌ Shared by every test in this worker.
let orderId: string;

test('creates an order', async ({ page }) => {
orderId = await createOrder(page);
});

test('cancels the order', async ({ page }) => {
await cancelOrder(page, orderId); // depends on the previous test
});
```

Give each test its own value with a [fixture](./test-fixtures.md#creating-a-fixture) instead:

```js
import { test as base } from '@playwright/test';

export const test = base.extend<{ orderId: string }>({
orderId: async ({ page }, use) => {
await use(await createOrder(page));
},
});

test('cancels an order', async ({ page, orderId }) => {
await cancelOrder(page, orderId); // isolated per test
});
```

## Shard tests between multiple machines

Playwright Test can shard a test suite, so that it can be executed on multiple machines.
Expand Down