playwright-fixtures
Playwright fixtures and test setup patterns
What this skill does
# Playwright Fixtures Skill
Patterns for using fixtures and test setup in Playwright.
## Built-in Fixtures
### Page and Context
```typescript
import { test, expect } from '@playwright/test'
test('basic test', async ({ page }) => {
// page is auto-created and cleaned up
await page.goto('/')
await expect(page).toHaveTitle(/Welcome/)
})
test('with context', async ({ context }) => {
// Full browser context (cookies, storage)
const page1 = await context.newPage()
const page2 = await context.newPage()
await page1.goto('/page1')
await page2.goto('/page2')
})
test('with browser', async ({ browser }) => {
// Create isolated context
const context = await browser.newContext()
const page = await context.newPage()
await page.goto('/')
await context.close()
})
```
### Request Fixture
```typescript
test('API test', async ({ request }) => {
// Make API requests
const response = await request.get('/api/users')
expect(response.ok()).toBeTruthy()
const users = await response.json()
expect(users).toHaveLength(10)
})
test('create then verify', async ({ request, page }) => {
// Create via API
await request.post('/api/users', {
data: { name: 'John', email: '[email protected]' },
})
// Verify in UI
await page.goto('/users')
await expect(page.getByText('John')).toBeVisible()
})
```
## Custom Fixtures
### Basic Custom Fixture
```typescript
// fixtures.ts
import { test as base } from '@playwright/test'
type MyFixtures = {
adminPage: Page
userEmail: string
}
export const test = base.extend<MyFixtures>({
// Simple fixture
userEmail: async ({}, use) => {
await use(`user-${Date.now()}@test.com`)
},
// Fixture with setup/teardown
adminPage: async ({ browser }, use) => {
// Setup
const context = await browser.newContext()
const page = await context.newPage()
await page.goto('/admin/login')
await page.fill('[name="email"]', '[email protected]')
await page.fill('[name="password"]', 'admin123')
await page.click('button[type="submit"]')
await page.waitForURL('/admin/dashboard')
// Provide to test
await use(page)
// Cleanup
await context.close()
},
})
export { expect } from '@playwright/test'
// In tests
import { test, expect } from './fixtures'
test('admin dashboard', async ({ adminPage }) => {
await expect(adminPage.getByRole('heading')).toHaveText('Admin Dashboard')
})
```
### Fixtures with Dependencies
```typescript
type Fixtures = {
dbConnection: Database
testUser: User
authenticatedPage: Page
}
export const test = base.extend<Fixtures>({
// Database fixture
dbConnection: async ({}, use) => {
const db = await Database.connect()
await use(db)
await db.disconnect()
},
// Depends on dbConnection
testUser: async ({ dbConnection }, use) => {
const user = await dbConnection.createUser({
email: `test-${Date.now()}@example.com`,
password: 'password123',
})
await use(user)
await dbConnection.deleteUser(user.id)
},
// Depends on testUser
authenticatedPage: async ({ page, testUser }, use) => {
await page.goto('/login')
await page.fill('[name="email"]', testUser.email)
await page.fill('[name="password"]', 'password123')
await page.click('button[type="submit"]')
await page.waitForURL('/dashboard')
await use(page)
},
})
```
### Worker Fixtures
```typescript
// Shared across all tests in worker
type WorkerFixtures = {
apiServer: Server
sharedData: SharedData
}
export const test = base.extend<{}, WorkerFixtures>({
// Worker-scoped (shared)
apiServer: [async ({}, use) => {
const server = await startMockServer()
await use(server)
await server.close()
}, { scope: 'worker' }],
// Test-scoped (per test)
sharedData: [async ({ apiServer }, use) => {
const data = await apiServer.getData()
await use(data)
}, { scope: 'worker' }],
})
```
### Auto Fixtures
```typescript
export const test = base.extend<{
setupComplete: void
}>({
// Auto-run for every test
setupComplete: [async ({ page }, use) => {
// Clear local storage before each test
await page.addInitScript(() => {
localStorage.clear()
sessionStorage.clear()
})
await use()
}, { auto: true }],
})
```
## Authentication Fixtures
### Storage State
```typescript
// global-setup.ts
import { chromium } from '@playwright/test'
async function globalSetup() {
const browser = await chromium.launch()
const context = await browser.newContext()
const page = await context.newPage()
// Login
await page.goto('/login')
await page.fill('[name="email"]', '[email protected]')
await page.fill('[name="password"]', 'password')
await page.click('button[type="submit"]')
await page.waitForURL('/dashboard')
// Save state
await context.storageState({ path: './auth/user.json' })
await browser.close()
}
export default globalSetup
// playwright.config.ts
export default defineConfig({
globalSetup: require.resolve('./global-setup'),
projects: [
{
name: 'authenticated',
use: { storageState: './auth/user.json' },
},
],
})
```
### Multiple Auth States
```typescript
// fixtures.ts
type AuthFixtures = {
adminContext: BrowserContext
userContext: BrowserContext
}
export const test = base.extend<AuthFixtures>({
adminContext: async ({ browser }, use) => {
const context = await browser.newContext({
storageState: './auth/admin.json',
})
await use(context)
await context.close()
},
userContext: async ({ browser }, use) => {
const context = await browser.newContext({
storageState: './auth/user.json',
})
await use(context)
await context.close()
},
})
// In tests
test('admin and user interaction', async ({ adminContext, userContext }) => {
const adminPage = await adminContext.newPage()
const userPage = await userContext.newPage()
await adminPage.goto('/admin/users')
await userPage.goto('/dashboard')
})
```
## Page Object Model
### Page Objects
```typescript
// pages/LoginPage.ts
import { Page, Locator } from '@playwright/test'
export class LoginPage {
readonly page: Page
readonly emailInput: Locator
readonly passwordInput: Locator
readonly submitButton: Locator
constructor(page: Page) {
this.page = page
this.emailInput = page.getByLabel('Email')
this.passwordInput = page.getByLabel('Password')
this.submitButton = page.getByRole('button', { name: 'Sign in' })
}
async goto() {
await this.page.goto('/login')
}
async login(email: string, password: string) {
await this.emailInput.fill(email)
await this.passwordInput.fill(password)
await this.submitButton.click()
}
}
// pages/DashboardPage.ts
export class DashboardPage {
readonly page: Page
constructor(page: Page) {
this.page = page
}
async expectWelcome(name: string) {
await expect(this.page.getByRole('heading')).toContainText(`Welcome, ${name}`)
}
}
```
### POMs as Fixtures
```typescript
// fixtures.ts
import { test as base } from '@playwright/test'
import { LoginPage } from './pages/LoginPage'
import { DashboardPage } from './pages/DashboardPage'
type PageObjects = {
loginPage: LoginPage
dashboardPage: DashboardPage
}
export const test = base.extend<PageObjects>({
loginPage: async ({ page }, use) => {
await use(new LoginPage(page))
},
dashboardPage: async ({ page }, use) => {
await use(new DashboardPage(page))
},
})
// In tests
import { test, expect } from './fixtures'
test('login flow', async ({ loginPage, dashboardPage }) => {
await loginPage.goto()
await loginPage.login('[email protected]', 'password')
await dashboardPage.expectWelcome('User')
})
```
## Test Data Fixtures
### Factory Fixtures
```typescript
type Fixtures = {
createUser: (overrides?: Partial<User>) => Promise<User>
createPost: (user: User, overrides?: Partial<Post>) => Promise<Post>
}
export const test = base.extend<Fixtures>({
createUseRelated in Code Review
gstack
IncludedFast headless browser for QA testing and site dogfooding. Navigate pages, interact with elements, verify state, diff before/after, take annotated screenshots, test responsive layouts, forms, uploads, dialogs, and capture bug evidence. Use when asked to open or test a site, verify a deployment, dogfood a user flow, or file a bug with screenshots. (gstack)
startup-due-diligence
IncludedLegal due diligence review for seed-stage and Series A startups (US, Delaware C-Corp focus). Supports both investor and founder perspectives. Capabilities include: (1) Interactive document review and issue spotting; (2) Document request list generation; (3) Cap table and SAFE/convertible note analysis; (4) Red flag identification with severity ratings; (5) Diligence report generation. TRIGGERS: due diligence, DD, startup investment, cap table review, Series A, seed round, investor diligence, legal review startup, SAFE analysis, convertible note, 409A, founder vesting.
interview-master
IncludedThis skill should be used when the user asks to "generate interview questions", "prepare for interview", "optimize resume", "conduct mock interview", "analyze git commits for resume", "generate resume from code", "review my resume", or mentions interview preparation, career assistance, or extracting project experience from git history. Provides comprehensive interview and career development guidance for both job seekers and interviewers.
fix-issue
IncludedFixes GitHub issues using parallel analysis agents for root cause investigation, code exploration, and regression detection. Reads issue context from gh CLI, searches codebase and memory for related patterns, generates a fix with tests, and links the resolution back to the issue via PR. Includes prevention analysis to avoid recurrence. Use when debugging errors, resolving regressions, fixing bugs, or triaging issues.
sf-apex
IncludedGenerates and reviews Salesforce Apex code with 150-point scoring. TRIGGER when: user writes, reviews, or fixes Apex classes, triggers, test classes, batch/queueable/schedulable jobs, or touches .cls/.trigger files. DO NOT TRIGGER when: LWC JavaScript (use sf-lwc), Flow XML (use sf-flow), SOQL-only queries (use sf-soql), or non-Salesforce code.
swift-development
IncludedComprehensive Swift development for building, testing, and deploying iOS/macOS applications. Use when Claude needs to: (1) Build Swift packages or Xcode projects from command line, (2) Run tests with XCTest or Swift Testing framework, (3) Manage iOS simulators with simctl, (4) Handle code signing, provisioning profiles, and app distribution, (5) Format or lint Swift code with SwiftFormat/SwiftLint, (6) Work with Swift Package Manager (SPM), (7) Implement Swift 6 concurrency patterns (async/await, actors, Sendable), (8) Create SwiftUI views with MVVM architecture, (9) Set up Core Data or SwiftData persistence, or any other Swift/iOS/macOS development tasks.