Files
2025-11-30 08:28:25 +08:00

251 lines
6.1 KiB
Markdown

# Playwright Test Debugging Checklist
## Initial Assessment
- [ ] Read the error message carefully
- [ ] Note the failing test name and location
- [ ] Check if test fails consistently or intermittently
- [ ] Identify which browser(s) are failing
- [ ] Check if failure is local only or also in CI
## Error Type Identification
### Timeout Errors
- [ ] Check if element exists with correct data-testid
- [ ] Verify page has loaded completely
- [ ] Add explicit wait before interaction
- [ ] Check if network requests are pending
- [ ] Increase timeout if operation is legitimately slow
### Selector Errors
- [ ] Verify data-testid in HTML matches test code
- [ ] Check if multiple elements have the same testid
- [ ] Ensure element is not in an iframe
- [ ] Confirm element is added to DOM (not removed)
- [ ] Use Playwright Inspector to test selector
### Assertion Errors
- [ ] Verify expected value is correct
- [ ] Check if element exists and is visible
- [ ] Add wait before assertion
- [ ] Check if content is populated asynchronously
- [ ] Increase assertion timeout if needed
### Navigation Errors
- [ ] Check if URL is correct
- [ ] Verify server is running
- [ ] Check for network issues
- [ ] Ensure proper wait after navigation
- [ ] Look for redirects or authentication requirements
## Element Investigation
- [ ] Count elements matching selector (should be 1)
```typescript
const count = await page.locator('[data-testid="element"]').count();
console.log('Element count:', count);
```
- [ ] Check element visibility
```typescript
const isVisible = await page.locator('[data-testid="element"]').isVisible();
console.log('Is visible:', isVisible);
```
- [ ] Check element state
```typescript
const isEnabled = await page.locator('[data-testid="element"]').isEnabled();
console.log('Is enabled:', isEnabled);
```
- [ ] Get element attributes
```typescript
const testId = await page.locator('[data-testid="element"]').getAttribute('data-testid');
console.log('data-testid:', testId);
```
## Timing Investigation
- [ ] Add waits before interactions
```typescript
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
```
- [ ] Wait for page load
```typescript
await page.waitForLoadState('domcontentloaded');
await page.waitForLoadState('networkidle');
```
- [ ] Wait for specific API calls
```typescript
await page.waitForResponse('**/api/endpoint');
```
- [ ] Check if animations/transitions are in progress
```typescript
await page.waitForTimeout(500); // Only for testing, remove later
```
## Interactive Debugging
- [ ] Run test in headed mode
```bash
npx playwright test --headed
```
- [ ] Use debug mode
```bash
npx playwright test --debug
```
- [ ] Add `page.pause()` in test
```typescript
await page.pause(); // Pauses execution for manual inspection
```
- [ ] Enable slow motion
```typescript
// In playwright.config.ts
use: {
launchOptions: {
slowMo: 1000, // Slow down by 1 second
},
}
```
- [ ] Take screenshots for inspection
```typescript
await page.screenshot({ path: 'debug-screenshot.png', fullPage: true });
```
## Trace Analysis
- [ ] Enable trace recording
```typescript
// In playwright.config.ts
use: {
trace: 'on-first-retry',
}
```
- [ ] Open trace viewer
```bash
npx playwright show-trace trace.zip
```
- [ ] Check trace for:
- Network requests
- Console logs
- Screenshots at each step
- DOM snapshots
- Action timeline
## Test Isolation Check
- [ ] Run test in isolation (comment out other tests)
- [ ] Check if test passes when run alone
- [ ] Verify no shared state between tests
- [ ] Ensure proper cleanup in `afterEach`
- [ ] Check for global state mutations
## Environment Differences
### Local vs CI
- [ ] Run test in headless mode locally
```bash
npx playwright test --headed=false
```
- [ ] Check viewport size matches CI
```typescript
await page.setViewportSize({ width: 1920, height: 1080 });
```
- [ ] Compare timeouts (CI may need longer)
- [ ] Check if CI has different environment variables
### Browser Differences
- [ ] Test in all configured browsers
```bash
npx playwright test --project=chromium
npx playwright test --project=firefox
npx playwright test --project=webkit
```
- [ ] Check for browser-specific issues
- [ ] Verify CSS compatibility
- [ ] Test JavaScript feature support
## Common Quick Fixes
### Fix #1: Add Explicit Wait
```typescript
// Before
await page.locator('[data-testid="element"]').click();
// After
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
await page.locator('[data-testid="element"]').click();
```
### Fix #2: Wait for Network
```typescript
// Before
await page.locator('[data-testid="submit"]').click();
await expect(page.locator('[data-testid="result"]')).toBeVisible();
// After
await page.locator('[data-testid="submit"]').click();
await page.waitForLoadState('networkidle');
await expect(page.locator('[data-testid="result"]')).toBeVisible();
```
### Fix #3: Handle Multiple Elements
```typescript
// Before
await page.locator('[data-testid="item"]').click(); // Error if multiple
// After
await page.locator('[data-testid="item"]').first().click();
```
### Fix #4: Increase Timeout
```typescript
// Before
await expect(page.locator('[data-testid="slow-element"]')).toBeVisible();
// After
await expect(page.locator('[data-testid="slow-element"]')).toBeVisible({
timeout: 15000
});
```
### Fix #5: Check Element State
```typescript
// Before
await page.locator('[data-testid="button"]').click();
// After
await expect(page.locator('[data-testid="button"]')).toBeEnabled();
await page.locator('[data-testid="button"]').click();
```
## Verification
- [ ] Run test 5+ times to verify consistency
- [ ] Test in all browsers
- [ ] Run full test suite to check for regressions
- [ ] Test in CI environment
- [ ] Document the fix for future reference
## Prevention
- [ ] Add explicit waits where needed
- [ ] Use only data-testid locators
- [ ] Ensure test isolation
- [ ] Add retry logic in config
- [ ] Review and refactor flaky tests regularly
- [ ] Keep tests simple and focused
- [ ] Maintain good test hygiene (cleanup, fixtures)