Advanced

2 min read
Rapid overview

Advanced Playwright (Senior-Level)

1. Test isolation + parallel safety

Rules:

  • Each test creates its own data (or uses seeded immutable fixtures).
  • Unique IDs for created entities: include test worker index + timestamp.
  • No implicit reliance on test execution order.

Example pattern:

test('creates a project', async ({ page }) => {
  const name = `proj-${test.info().workerIndex}-${Date.now()}`;
  // create -> assert -> cleanup
});

2. Authentication without re-logging in every test

Use storageState to avoid repeated UI login:

// global-setup.ts creates auth state
await page.goto('/login');
// ...login...
await page.context().storageState({ path: 'storageState.json' });

Then:

use: { storageState: 'storageState.json' }

3. Network control (mocking vs real)

Prefer real API for high-signal E2E, but:

  • mock external services (payments, email, 3rd party)
  • mock unstable endpoints
  • use API seeding for fast deterministic setup

Examples:

await page.route('**/api/feature-flags', (route) =>
  route.fulfill({ json: { newCheckout: true } })
);
const resp = await page.request.post('/api/projects', { data: { name: 'x' } });
expect(resp.ok()).toBe(true);

4. Flake triage playbook

When a test flakes:

  1. Open the trace (actions, DOM snapshots, network).
  2. Identify the missing condition (URL? API? UI state?).
  3. Replace sleeps with one specific wait.
  4. Improve selector stability (role/testid).
  5. Reduce concurrency if the app/test env can’t support it.

5. Timeouts and retries (what “good” looks like)

  • Keep per-assertion timeouts low (defaults).
  • Allow global test timeout to be reasonable (e.g., 30s).
  • Retries: CI only, and always with traces/videos on retry.

6. Projects, workers, and sharding

Use projects for cross-browser/device:

projects: [
  { name: 'chromium' },
  { name: 'firefox' },
  { name: 'webkit' },
]

Sharding in CI to split the suite:

npx playwright test --shard=1/4

Cap workers if tests contend on shared resources (DB, env, rate limits).

7. Page objects (when to use)

Use page objects for:

  • complex flows with reusable actions
  • consistent locator definitions

Avoid page objects that:

  • hide assertions/waits inside (harder to reason about)
  • expose raw locators everywhere (no abstraction benefit)

8. Reporting + artifacts

Useful defaults:

  • HTML report locally
  • JUnit/JSON in CI
  • screenshots/videos on failure
  • traces on first retry