4.1 BrowserContext 격리
각 test는 다른 test의 cookie, local storage, session storage에 의존하지 않아야 합니다. Playwright Test는 test마다 새 BrowserContext를 만들어 clean slate를 제공합니다.
test('starts signed out', async ({ page }) => {
await page.goto('/account');
await expect(page.getByRole('link', { name: '로그인' })).toBeVisible();
});
beforeAll에서 하나의 page를 만들고 여러 test가 순서대로 공유하면 실패가 다음 test로 전파되고 병렬 실행을 막습니다. 각 test가 필요한 상태를 직접 만들거나 fixture로 제공합니다.
격리 밖의 상태
BrowserContext만 새로 만든다고 모든 상태가 격리되는 것은 아닙니다.
- Database row와 shared account
- Message queue와 email inbox
- File과 object storage
- Third-party sandbox quota
- Application cache와 feature flag
Parallel test는 고유한 user, order ID를 사용합니다.
test('creates an order', async ({ page }, testInfo) => {
const orderId = `order-${testInfo.testId}`;
// 이 test만 사용하는 data를 만듭니다.
});
Test 종료 시 자신이 만든 resource만 정리합니다. Shared environment 전체를 truncate하는 cleanup은 다른 worker와 충돌할 수 있습니다.
Isolation의 세 층
| 층 | 격리 대상 | 구현 예 |
|---|---|---|
| Browser state | cookie, local storage, permission | test별 BrowserContext |
| Server data | user, order, file | test ID/worker namespace |
| External service | sandbox account, quota | account pool, lease |
Context 격리만으로 backend record 충돌은 해결되지 않습니다. Parallel worker가 같은 email이나 order를 수정하면 UI state가 격리되어도 test가 간섭합니다.
Worker namespace
const namespace = `pw-${testInfo.parallelIndex}-${testInfo.testId.slice(0, 8)}`;
Random UUID만 쓰면 collision은 줄지만 failure data를 찾기 어렵습니다. Run ID와 worker/test identity를 포함하면 cleanup과 진단이 쉬워집니다.
실습
- 같은 account를 두 worker가 수정해 collision을 재현합니다.
- Worker별 account 또는 namespace로 해결합니다.
- 실패 뒤 data를 즉시 지우는 경우와 TTL로 남기는 경우의 진단 trade-off를 비교합니다.
- Multi-user scenario에서 context별 storage를 attachment로 비교합니다.