init
This commit is contained in:
@@ -0,0 +1,115 @@
|
||||
# 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
|
||||
```
|
||||
Reference in New Issue
Block a user