Loading source
Pulling the file list, source metadata, and syntax-aware rendering for this listing.
Source from repo
Comprehensive Playwright testing guide covering E2E, component, API, visual, accessibility, and security tests.
Files
Skill
Size
Entrypoint
Format
Open file
Syntax-highlighted preview of this file as included in the skill package.
core/global-setup.md
1# Global Setup & Teardown23## Table of Contents451. [Global Setup](#global-setup)62. [Global Teardown](#global-teardown)73. [Database Patterns](#database-patterns)84. [Environment Provisioning](#environment-provisioning)95. [Setup Projects vs Global Setup](#setup-projects-vs-global-setup)106. [Parallel Execution Caveats](#parallel-execution-caveats)1112## Global Setup1314### Basic Global Setup1516```typescript17// global-setup.ts18import { FullConfig } from "@playwright/test";1920async function globalSetup(config: FullConfig) {21console.log("Running global setup...");22// Perform one-time setup: start services, run migrations, etc.23}2425export default globalSetup;26```2728### Configure Global Setup2930```typescript31// playwright.config.ts32import { defineConfig } from "@playwright/test";3334export default defineConfig({35globalSetup: require.resolve("./global-setup"),36globalTeardown: require.resolve("./global-teardown"),37});38```3940> **Authentication in Global Setup**: For authentication patterns using storage state in global setup, see [fixtures-hooks.md](fixtures-hooks.md#authentication-patterns). Setup projects are generally preferred for authentication as they provide access to Playwright fixtures.4142### Global Setup with Return Value4344```typescript45// global-setup.ts46async function globalSetup(config: FullConfig): Promise<() => Promise<void>> {47const server = await startTestServer();4849// Return cleanup function (alternative to globalTeardown)50return async () => {51await server.stop();52};53}5455export default globalSetup;56```5758### Access Config in Global Setup5960```typescript61// global-setup.ts62import { FullConfig } from "@playwright/test";6364async function globalSetup(config: FullConfig) {65const { baseURL } = config.projects[0].use;66console.log(`Setting up for ${baseURL}`);6768// Access custom config69const workers = config.workers;70const timeout = config.timeout;7172// Access environment73const isCI = !!process.env.CI;74}7576export default globalSetup;77```7879## Global Teardown8081### Basic Global Teardown8283```typescript84// global-teardown.ts85import { FullConfig } from "@playwright/test";86import fs from "fs";8788async function globalTeardown(config: FullConfig) {89console.log("Running global teardown...");9091// Clean up auth files92if (fs.existsSync(".auth")) {93fs.rmSync(".auth", { recursive: true });94}9596// Clean up test data97await cleanupTestDatabase();9899// Stop services100await stopTestServices();101}102103export default globalTeardown;104```105106### Conditional Teardown107108```typescript109// global-teardown.ts110async function globalTeardown(config: FullConfig) {111// Skip cleanup in CI (containers are discarded anyway)112if (process.env.CI) {113console.log("Skipping teardown in CI");114return;115}116117// Local cleanup118await cleanupLocalTestData();119}120121export default globalTeardown;122```123124## Database Patterns125126This section covers **one-time database setup** (migrations, snapshots, per-worker databases). For related topics:127128- **Per-test database fixtures** (isolation, transaction rollback): See [fixtures-hooks.md](fixtures-hooks.md#database-fixtures)129- **Test data factories** (builders, Faker): See [test-data.md](test-data.md)130131### Database Migration in Setup132133```typescript134// global-setup.ts135import { execSync } from "child_process";136137async function globalSetup() {138console.log("Running database migrations...");139140// Run migrations141execSync("npx prisma migrate deploy", { stdio: "inherit" });142143// Seed test data144execSync("npx prisma db seed", { stdio: "inherit" });145}146147export default globalSetup;148```149150### Database Snapshot Pattern151152```typescript153// global-setup.ts154import { execSync } from "child_process";155import fs from "fs";156157const SNAPSHOT_PATH = "./test-db-snapshot.sql";158159async function globalSetup() {160// Check if snapshot exists161if (fs.existsSync(SNAPSHOT_PATH)) {162console.log("Restoring database from snapshot...");163execSync(`psql $DATABASE_URL < ${SNAPSHOT_PATH}`, { stdio: "inherit" });164return;165}166167// First run: migrate and create snapshot168console.log("Creating database snapshot...");169execSync("npx prisma migrate deploy", { stdio: "inherit" });170execSync("npx prisma db seed", { stdio: "inherit" });171execSync(`pg_dump $DATABASE_URL > ${SNAPSHOT_PATH}`, { stdio: "inherit" });172}173174export default globalSetup;175```176177### Test Database per Worker178179```typescript180// global-setup.ts181async function globalSetup(config: FullConfig) {182const workerCount = config.workers || 1;183184// Create a database for each worker185for (let i = 0; i < workerCount; i++) {186const dbName = `test_db_worker_${i}`;187await createDatabase(dbName);188await runMigrations(dbName);189await seedDatabase(dbName);190}191}192193// global-teardown.ts194async function globalTeardown(config: FullConfig) {195const workerCount = config.workers || 1;196197for (let i = 0; i < workerCount; i++) {198await dropDatabase(`test_db_worker_${i}`);199}200}201```202203## Environment Provisioning204205### Start Services in Setup206207```typescript208// global-setup.ts209import { execSync, spawn } from "child_process";210211let serverProcess: any;212213async function globalSetup() {214// Start backend server215serverProcess = spawn("npm", ["run", "start:test"], {216stdio: "pipe",217detached: true,218});219220// Wait for server to be ready221await waitForServer("http://localhost:3000/health", 30000);222223// Store PID for teardown224process.env.SERVER_PID = serverProcess.pid.toString();225}226227async function waitForServer(url: string, timeout: number) {228const start = Date.now();229230while (Date.now() - start < timeout) {231try {232const response = await fetch(url);233if (response.ok) return;234} catch {235// Server not ready yet236}237await new Promise((r) => setTimeout(r, 1000));238}239240throw new Error(`Server did not start within ${timeout}ms`);241}242243export default globalSetup;244```245246### Docker Compose Setup247248```typescript249// global-setup.ts250import { execSync } from "child_process";251252async function globalSetup() {253console.log("Starting Docker services...");254255execSync("docker-compose -f docker-compose.test.yml up -d", {256stdio: "inherit",257});258259// Wait for services to be healthy260execSync("docker-compose -f docker-compose.test.yml exec -T db pg_isready", {261stdio: "inherit",262});263}264265export default globalSetup;266```267268```typescript269// global-teardown.ts270import { execSync } from "child_process";271272async function globalTeardown() {273console.log("Stopping Docker services...");274275execSync("docker-compose -f docker-compose.test.yml down -v", {276stdio: "inherit",277});278}279280export default globalTeardown;281```282283### Environment Variables Setup284285```typescript286// global-setup.ts287import dotenv from "dotenv";288import path from "path";289290async function globalSetup() {291// Load test-specific environment292const envFile = process.env.CI ? ".env.ci" : ".env.test";293dotenv.config({ path: path.resolve(process.cwd(), envFile) });294295// Validate required variables296const required = ["DATABASE_URL", "API_KEY", "TEST_EMAIL"];297for (const key of required) {298if (!process.env[key]) {299throw new Error(`Missing required environment variable: ${key}`);300}301}302}303304export default globalSetup;305```306307## Setup Projects vs Global Setup308309### When to Use Each310311| Use Global Setup | Use Setup Projects |312| ------------------------------------- | ---------------------------------------- |313| One-time setup (migrations, services) | Per-project setup (auth states) |314| No access to Playwright fixtures | Need page, request fixtures |315| Runs once before all projects | Can run per-project or have dependencies |316| Shared across all workers | Can be parallelized |317318### Setup Project Pattern319320```typescript321// playwright.config.ts322export default defineConfig({323projects: [324// Setup project325{326name: "setup",327testMatch: /.*\.setup\.ts/,328},329// Test projects depend on setup330{331name: "chromium",332use: { ...devices["Desktop Chrome"] },333dependencies: ["setup"],334},335{336name: "firefox",337use: { ...devices["Desktop Firefox"] },338dependencies: ["setup"],339},340],341});342```343344> **For complete authentication setup patterns**, see [fixtures-hooks.md](fixtures-hooks.md#authentication-patterns).345346### Combining Both347348```typescript349// playwright.config.ts350export default defineConfig({351// Global: Start services, run migrations352globalSetup: require.resolve("./global-setup"),353globalTeardown: require.resolve("./global-teardown"),354355projects: [356// Setup project: Create auth states357{ name: "setup", testMatch: /.*\.setup\.ts/ },358{359name: "chromium",360use: {361...devices["Desktop Chrome"],362storageState: ".auth/user.json",363},364dependencies: ["setup"],365},366],367});368```369370## Parallel Execution Caveats371372### Understanding Global Setup Execution373374```375┌─────────────────────────────────────────────────────────────┐376│ globalSetup runs ONCE │377│ ↓ │378│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │379│ │ Worker 1│ │ Worker 2│ │ Worker 3│ │ Worker 4│ │380│ │ tests │ │ tests │ │ tests │ │ tests │ │381│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │382│ ↓ │383│ globalTeardown runs ONCE │384└─────────────────────────────────────────────────────────────┘385```386387**Key implications:**388389- Global setup has **no access** to Playwright fixtures (`page`, `request`, `context`)390- State created in global setup is **shared** across all workers391- If tests **modify** shared state, they may conflict with parallel workers392- Global setup **cannot** react to individual test needs393394### When to Prefer Worker-Scoped Fixtures395396Use **worker-scoped fixtures** instead of globalSetup when:397398| Scenario | Why Fixtures Are Better |399| ------------------------------------ | ---------------------------------------------------- |400| Each worker needs isolated resources | Fixtures can create per-worker databases, servers |401| Setup needs Playwright APIs | Fixtures have access to `page`, `request`, `browser` |402| Setup depends on test configuration | Fixtures receive test context and options |403| Resources need cleanup per worker | Worker fixtures auto-cleanup when worker exits |404405### Common Parallel Pitfall406407```typescript408// ❌ BAD: Global setup creates ONE user, all workers fight over it409async function globalSetup() {410await createUser({ email: "[email protected]" }); // Shared!411}412413// ✅ GOOD: Each worker gets its own user via worker-scoped fixture414// Uses workerInfo.workerIndex to create unique data per worker415```416417> **For worker-scoped fixture patterns** (per-worker databases, unique test data, `workerIndex` isolation), see [fixtures-hooks.md](fixtures-hooks.md#isolate-test-data-between-parallel-workers).418419## Anti-Patterns to Avoid420421| Anti-Pattern | Problem | Solution |422| ------------------------------ | -------------------------------- | ------------------------------------------ |423| Heavy setup in globalSetup | Slow test startup | Use setup projects for parallelizable work |424| Not cleaning up in teardown | Leaks resources, flaky CI | Always clean up or use containers |425| Hardcoded URLs in setup | Breaks in different environments | Use config.projects[0].use.baseURL |426| No timeout on service wait | Hangs forever if service fails | Add timeout with clear error |427| Shared mutable state | Race conditions in parallel | Use worker-scoped fixtures for isolation |428| Global setup for per-test data | Tests conflict | Use test-scoped fixtures |429430## Related References431432- **Fixtures & Auth**: See [fixtures-hooks.md](fixtures-hooks.md) for worker-scoped fixtures and auth patterns433- **CI/CD**: See [ci-cd.md](../infrastructure-ci-cd/ci-cd.md) for CI setup patterns434- **Projects**: See [projects-dependencies.md](projects-dependencies.md) for project configuration435