Files
english/.opencode/skills/web-testing/references/playwright-component-testing.md
2026-04-12 01:06:31 +07:00

116 lines
2.8 KiB
Markdown

# Playwright Component Testing
## Status
**Production-ready** as of 2024. No longer experimental.
## Setup
```bash
npm init playwright@latest -- --ct
```
## Configuration
```typescript
// playwright-ct.config.ts
import { defineConfig, devices } from '@playwright/experimental-ct-react';
export default defineConfig({
testDir: './src',
use: {
ctPort: 3100,
},
projects: [
{ name: 'chromium', use: { ...devices['Desktop Chrome'] } },
{ name: 'firefox', use: { ...devices['Desktop Firefox'] } },
{ name: 'webkit', use: { ...devices['Desktop Safari'] } },
],
});
```
## Basic Test
```typescript
import { test, expect } from '@playwright/experimental-ct-react';
import { Button } from './Button';
test('renders button with text', async ({ mount }) => {
const component = await mount(<Button>Click me</Button>);
await expect(component).toContainText('Click me');
});
test('handles click event', async ({ mount }) => {
let clicked = false;
const component = await mount(
<Button onClick={() => clicked = true}>Click</Button>
);
await component.click();
expect(clicked).toBe(true);
});
```
## With Props and State
```typescript
test('counter increments', async ({ mount }) => {
const component = await mount(<Counter initial={0} />);
await expect(component.getByTestId('count')).toHaveText('0');
await component.getByRole('button', { name: 'Increment' }).click();
await expect(component.getByTestId('count')).toHaveText('1');
});
```
## Visual Regression
```typescript
test('button styles', async ({ mount }) => {
const component = await mount(<Button variant="primary">Submit</Button>);
await expect(component).toHaveScreenshot('button-primary.png');
});
```
## Mocking
```typescript
test('with mocked data', async ({ mount }) => {
const component = await mount(
<UserContext.Provider value={{ user: { name: 'Test' } }}>
<Profile />
</UserContext.Provider>
);
await expect(component).toContainText('Test');
});
```
## When to Use CT vs E2E
| Use CT When | Use E2E When |
|-------------|--------------|
| Testing isolated components | Testing user flows |
| Visual regression on components | Navigation, routing |
| Component interactions | Full page behavior |
| Fast feedback during dev | Integration with backend |
## When to Use CT vs Vitest
| Use CT When | Use Vitest When |
|-------------|-----------------|
| Real browser needed | Speed is priority |
| Cross-browser testing | Unit testing logic |
| CSS/layout verification | Mocking is simpler |
| Complex DOM interactions | jsdom is sufficient |
## Limitations
- Complex object passing requires serialization
- Slower than jsdom-based tests
- Watch mode less efficient than Vitest
## Commands
```bash
npx playwright test -c playwright-ct.config.ts
npx playwright test -c playwright-ct.config.ts --ui
```