Monorepos and Shared Test Utilities

In larger organisations, Playwright tests often live in monorepos with multiple apps and packages. Designing shared utilities carefully prevents duplication while keeping boundaries clear between projects.

Sharing Playwright Utilities in a Monorepo

A common approach is to create a dedicated test utilities package that exports page models, service helpers, fixtures and configuration helpers. Individual apps then depend on this package.

monorepo/
  packages/
    test-utils/
      src/
        models/
        services/
        fixtures/
      package.json
  apps/
    shop-frontend/
      tests/
      playwright.config.ts
    admin-frontend/
      tests/
      playwright.config.ts
// apps/shop-frontend/playwright.config.ts
import { defineConfig } from '@playwright/test';
import { shopProjectDefaults } from '@org/test-utils/config';

export default defineConfig({
  ...shopProjectDefaults,
});
Note: Publishing test utilities as internal packages enforces versioning and makes dependencies explicit, even inside a monorepo.
Tip: Keep the shared package focused on generic patterns; app-specific details should live with the app itself.
Warning: Over-centralising everything in one package can create tight coupling and slow down refactors.

Good boundaries let teams share high-value utilities without turning the monorepo into a single tangled codebase.

Common Mistakes

Mistake 1 โ€” Copy-pasting utilities between apps

This leads to divergence.

โŒ Wrong: Duplicating page models or fixtures into each app folder.

โœ… Correct: Move shared logic into a common package and version it.

Mistake 2 โ€” Putting app-specific logic into shared packages

This reduces reusability.

โŒ Wrong: Hard-coding URLs or features for a single app inside the utilities package.

โœ… Correct: Keep shared packages generic and pass app-specific details via configuration.

🧠 Test Yourself

How should Playwright test utilities be structured in a monorepo?