This document provides essential information for AI coding agents working in this Playwright TypeScript test automation repository.
- Framework: Playwright v1.59.1 with TypeScript
- Package Manager: pnpm (v10.28.2)
- Target Application: https://music-tech-shop.vercel.app
- Test Directory:
./tests
# Run all tests (headless)
npx playwright test
# Run a single test file
npx playwright test tests/e2e/auth/login.spec.ts
# Run tests matching a pattern
npx playwright test --grep "login"
# Run tests by tag
npx playwright test --grep @smoke
npx playwright test --grep @regression
# Run with visible browser (headed mode)
npx playwright test --headed
# Debug mode (opens Playwright Inspector)
npx playwright test --debug
# View HTML report
npx playwright show-report- Target: ESNext with NodeNext module resolution
- Strict mode: Enabled
- No explicit linting: Follow Playwright best practices and TypeScript strict mode
// Tests: Import from custom test base
import { test, expect } from '../fixtures/test-base';
// Page Objects: Import type-only for Locator/Page
import { type Locator, type Page } from '@playwright/test';
// Data: Use named imports
import { CUSTOMER_USER, ADMIN_USER } from '../../data/users.data';- Role-based (preferred):
page.getByRole('button', { name: 'Submit' }) - Label/Text:
page.getByLabel('Email'),page.getByText('Welcome') - Test IDs:
page.getByTestId('submit-button') - AVOID: CSS selectors (
.btn-primary) and XPath
- Test files:
<feature>.spec.ts(e.g.,login.spec.ts) - Page Objects:
<page>.page.tswith PascalCase class names - Fixtures:
<name>.fixture.ts - Data files:
<name>.data.ts - Constants: UPPER_SNAKE_CASE (e.g.,
ADMIN_USER) - Methods: camelCase with descriptive verbs (e.g.,
goto(),login())
export class LoginPage extends BasePage {
// Use getters for locators
get emailInput(): Locator {
return this.page.getByRole('textbox', { name: 'Email' });
}
// Fluent interface - return this for chaining
async goto(): Promise<this> {
return this.navigateTo('/login');
}
// Actions are async methods
async login(email: string, password: string): Promise<void> {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.signInButton.click();
}
}test.describe('Feature Name @smoke', () => {
test.beforeEach(async ({ loginPage }) => {
await loginPage.goto();
});
test('Descriptive test name', async ({ loginPage, page }) => {
await test.step('Action description', async () => {
await loginPage.login(CUSTOMER_USER.email, CUSTOMER_USER.password);
});
await test.step('Verification', async () => {
await expect(page).toHaveURL('/');
});
});
});- Use web-first assertions with
await:await expect(locator).toHaveText() - Prefer
toHaveText()overtoContainText()for exact matches - Use
toMatchAriaSnapshot()for accessibility tree verification - Use
toHaveCount()for element counts - Use
toHaveURL()for navigation verification
@smoke- Critical path tests (20 tests)@regression- Full test suite (121 tests)@a11y- Accessibility tests (14 tests)
- Rely on Playwright's auto-waiting; avoid hard-coded waits
- Use
expect().toPass()for flaky assertions with retries - Let assertions fail naturally; don't catch errors unless testing error scenarios
- Use JSDoc for public methods in Page Objects
- Add section dividers in Page Objects:
// ── Section Name ─── - Comments should explain WHY, not WHAT
- Keep test titles descriptive enough to minimize inline comments
tests/
├── e2e/ # Test specs organized by feature
│ ├── auth/
│ ├── cart/
│ ├── products/
│ └── ...
├── pages/ # Page Object Model classes
├── fixtures/ # Custom Playwright fixtures
├── data/ # Test data (users, products, etc.)
└── helpers/ # Utility functions
The project has MCP server configuration for Playwright tools in .vscode/mcp.json.
playwright.config.ts- Test configurationtests/fixtures/test-base.ts- Central test fixture exporttests/pages/base.page.ts- Base Page Object class.github/instructions/playwright-typescript.instructions.md- Detailed test writing guidelines