End-to-end testing expert for Playwright, Cypress, visual regression (Percy, Chromatic), and UI testing. Use for E2E tests, browser automation, visual diffs, or debugging flaky tests.
View on GitHubanton-abyzov/specweave
sw-testing
February 4, 2026
Select agents to install to:
npx add-skill https://github.com/anton-abyzov/specweave/blob/main/plugins/specweave-testing/skills/e2e-testing/SKILL.md -a claude-code --skill e2e-testingInstallation paths:
.claude/skills/e2e-testing/# E2E Testing Expert - Playwright, Visual Regression, UI Testing
## Core Expertise
- **Playwright/Cypress** for browser automation
- **Visual regression** with Percy, Chromatic, BackstopJS
- **UI testing** with Testing Library patterns
- **Accessibility testing** with axe-core
- **Mobile emulation** and device testing
## Playwright Fundamentals
### Test Structure
```typescript
import { test, expect } from '@playwright/test';
test.describe('Authentication', () => {
test('should login successfully', async ({ page }) => {
await page.goto('/login');
await page.getByLabel('Email').fill('user@example.com');
await page.getByLabel('Password').fill('password123');
await page.getByRole('button', { name: 'Login' }).click();
await expect(page).toHaveURL('/dashboard');
await expect(page.getByText('Welcome')).toBeVisible();
});
});
```
### Page Object Model
```typescript
// pages/LoginPage.ts
export class LoginPage {
constructor(private page: Page) {}
readonly emailInput = this.page.getByLabel('Email');
readonly passwordInput = this.page.getByLabel('Password');
readonly loginButton = this.page.getByRole('button', { name: 'Login' });
async login(email: string, password: string) {
await this.emailInput.fill(email);
await this.passwordInput.fill(password);
await this.loginButton.click();
}
}
```
### Fixtures
```typescript
import { test as base } from '@playwright/test';
import { LoginPage } from './pages/LoginPage';
export const test = base.extend<{ loginPage: LoginPage }>({
loginPage: async ({ page }, use) => {
const loginPage = new LoginPage(page);
await loginPage.goto();
await use(loginPage);
},
});
```
## Visual Regression
### Playwright Screenshots
```typescript
test('homepage matches baseline', async ({ page }) => {
await page.goto('/');
await expect(page).toHaveScreenshot('homepage.png', {
fullPage: true,
animations: 'disabled',
});
});
// Responsive screenshots
await page.setV