Test Isolation Requirements
Intermediate
Mandate complete test isolation in Playwright suites — no shared state, independent browser contexts, deterministic data, and no reliance on test execution order.
File Patterns
**/*.spec.ts**/*.test.ts**/tests/****/e2e/****/playwright/**
This rule applies to files matching the patterns above.
Rule Content
rule-content.md
# Test Isolation Requirements
## Rule
Every Playwright test MUST be independently runnable. Tests must not depend on other tests running first, share mutable state, or rely on execution order.
## Requirements
### 1. Independent Browser Contexts
Each test gets its own browser context. Never share contexts between tests.
```typescript
// Good — each test has isolated context
test('test A', async ({ page }) => {
// page has fresh context
});
test('test B', async ({ page }) => {
// completely independent of test A
});
```
### 2. No Shared Mutable State
```typescript
// Bad — shared variable between tests
let userId: string;
test('create user', async ({ page }) => {
userId = await createUser();
});
test('verify user', async ({ page }) => {
await page.goto(`/users/${userId}`); // depends on previous test
});
// Good — use fixtures for shared setup
test('verify user', async ({ page, seedData }) => {
await page.goto(`/users/${seedData.userId}`);
});
```
### 3. Deterministic Test Data
```typescript
// Bad — relies on database state from other tests
test('shows 5 users', async ({ page }) => { /* assumes specific data */ });
// Good — seeds its own data via fixture
test('shows seeded users', async ({ page, seedUsers }) => {
await page.goto('/users');
await expect(page.getByRole('listitem')).toHaveCount(seedUsers.length);
});
```
### 4. No waitForTimeout
```typescript
// Bad — arbitrary wait
await page.waitForTimeout(3000);
// Good — wait for actionable condition
await expect(page.getByRole('alert')).toBeVisible();
await page.getByRole('button', { name: 'Save' }).click(); // auto-waits
```
### 5. Clean Up After Yourself
```typescript
// Good — fixture handles teardown
const test = base.extend({
tempUser: async ({}, use) => {
const user = await createTestUser();
await use(user);
await deleteTestUser(user.id); // cleanup
},
});
```
## Verification
Run any test in isolation to verify:
```bash
npx playwright test tests/specific.spec.ts --grep "test name"
```
If it fails when run alone but passes in the full suite, it has an isolation violation.
## Anti-Patterns
- `test.describe.configure({ mode: 'serial' })` — almost always a design smell
- Global variables shared between test files
- Tests that must run in a specific order
- Using `page.waitForTimeout()` instead of actionability assertionsFAQ
Discussion
Loading comments...