9.5 KiB
Common Playwright Errors and Quick Fixes
Timeout Errors
Error: "Timeout 30000ms exceeded waiting for selector"
Cause: Element not found within timeout period
Quick Fixes:
// 1. Add explicit wait
await page.waitForSelector('[data-testid="element"]', { state: 'visible' });
// 2. Verify data-testid is correct
const count = await page.locator('[data-testid="element"]').count();
console.log('Found', count, 'elements');
// 3. Wait for page to load first
await page.waitForLoadState('domcontentloaded');
// 4. Increase timeout if legitimately slow
await page.locator('[data-testid="element"]').waitFor({
state: 'visible',
timeout: 60000
});
Error: "Timeout 30000ms exceeded waiting for navigation"
Cause: Page navigation taking too long or not happening
Quick Fixes:
// 1. Wait for specific URL
await page.waitForURL('/expected-path', { timeout: 45000 });
// 2. Wait for load state
await page.waitForLoadState('networkidle');
// 3. Check if navigation actually occurs
console.log('Current URL:', page.url());
Selector Errors
Error: "strict mode violation: locator resolved to X elements"
Cause: Multiple elements match the selector
Quick Fixes:
// 1. Use .first() or .last()
await page.locator('[data-testid="item"]').first().click();
// 2. Use .nth() for specific element
await page.locator('[data-testid="item"]').nth(2).click();
// 3. Make selector more specific (avoid if possible)
await page.locator('[data-testid="item"][aria-selected="true"]').click();
// 4. Filter locators
await page.locator('[data-testid="item"]').filter({ hasText: 'Active' }).click();
Error: "Element not found"
Cause: Element doesn't exist or wrong selector
Quick Fixes:
// 1. Verify element exists
const exists = await page.locator('[data-testid="element"]').count() > 0;
console.log('Element exists:', exists);
// 2. Check for typos in data-testid
// Verify in HTML: <button data-testid="correct-id">
// 3. Wait for element to be added to DOM
await page.locator('[data-testid="element"]').waitFor({ state: 'attached' });
// 4. Check if in iframe
const frame = page.frameLocator('[data-testid="app-frame"]');
await frame.locator('[data-testid="element"]').click();
Assertion Errors
Error: "expect(received).toBeVisible() - Expected visible but received hidden"
Cause: Element exists but is not visible
Quick Fixes:
// 1. Wait for element to become visible
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
await expect(page.locator('[data-testid="element"]')).toBeVisible();
// 2. Check visibility with timeout
await expect(page.locator('[data-testid="element"]')).toBeVisible({
timeout: 10000
});
// 3. Debug visibility
const isVisible = await page.locator('[data-testid="element"]').isVisible();
console.log('Is visible:', isVisible);
Error: "expect(received).toContainText() - Expected substring not found"
Cause: Element doesn't contain expected text or not loaded yet
Quick Fixes:
// 1. Wait for text to appear
await expect(page.locator('[data-testid="element"]')).toContainText('Expected', {
timeout: 10000
});
// 2. Wait for network before checking
await page.waitForLoadState('networkidle');
await expect(page.locator('[data-testid="element"]')).toContainText('Expected');
// 3. Check actual text content
const text = await page.locator('[data-testid="element"]').textContent();
console.log('Actual text:', text);
Click Errors
Error: "locator.click: Target closed"
Cause: Element or page disappeared before click completed
Quick Fixes:
// 1. Wait for element to be stable
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
await page.waitForTimeout(100); // Allow animations to settle
await page.locator('[data-testid="element"]').click();
// 2. Use force click if element is covered
await page.locator('[data-testid="element"]').click({ force: true });
// 3. Check if element is being removed
const count = await page.locator('[data-testid="element"]').count();
console.log('Element count before click:', count);
Error: "Element is not clickable"
Cause: Element is disabled, covered, or not in viewport
Quick Fixes:
// 1. Check if element is enabled
await expect(page.locator('[data-testid="button"]')).toBeEnabled();
await page.locator('[data-testid="button"]').click();
// 2. Scroll into view
await page.locator('[data-testid="element"]').scrollIntoViewIfNeeded();
await page.locator('[data-testid="element"]').click();
// 3. Wait for element to be clickable
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
await expect(page.locator('[data-testid="element"]')).toBeEnabled();
await page.locator('[data-testid="element"]').click();
Network Errors
Error: "net::ERR_CONNECTION_REFUSED"
Cause: Server is not running or wrong URL
Quick Fixes:
// 1. Verify server is running
// Check if dev server is started: npm run dev
// 2. Check baseURL in playwright.config.ts
use: {
baseURL: 'http://localhost:3000', // Correct port?
}
// 3. Use full URL if baseURL not set
await page.goto('http://localhost:3000/path');
Error: "Navigation failed because page was closed"
Cause: Page closed prematurely during navigation
Quick Fixes:
// 1. Don't close page too early
// Remove premature page.close() calls
// 2. Wait for navigation to complete
await page.goto('/path');
await page.waitForLoadState('domcontentloaded');
// 3. Check for popup blockers or redirects
Fill/Type Errors
Error: "Cannot type into a non-editable element"
Cause: Trying to fill a non-input element
Quick Fixes:
// 1. Verify element is an input/textarea
const tagName = await page.locator('[data-testid="element"]').evaluate(
el => el.tagName
);
console.log('Tag name:', tagName); // Should be INPUT or TEXTAREA
// 2. Check if element is contenteditable
const isEditable = await page.locator('[data-testid="element"]').evaluate(
el => el.contentEditable
);
// 3. Use correct element selector
// Ensure data-testid is on the input, not its container
Error: "Element is disabled"
Cause: Trying to interact with disabled element
Quick Fixes:
// 1. Wait for element to be enabled
await expect(page.locator('[data-testid="input"]')).toBeEnabled();
await page.locator('[data-testid="input"]').fill('value');
// 2. Check why element is disabled
const isDisabled = await page.locator('[data-testid="input"]').isDisabled();
console.log('Is disabled:', isDisabled);
// 3. Ensure prerequisites are met (e.g., terms accepted)
await page.locator('[data-testid="terms-checkbox"]').check();
await page.locator('[data-testid="submit"]').click();
Frame/Iframe Errors
Error: "Frame was detached"
Cause: Interacting with iframe that was removed
Quick Fixes:
// 1. Re-acquire frame reference
const frame = page.frameLocator('[data-testid="app-frame"]');
await frame.locator('[data-testid="element"]').click();
// 2. Wait for frame to be ready
await page.frameLocator('[data-testid="app-frame"]').locator('body').waitFor();
// 3. Check if frame exists
const frameCount = await page.frames().length;
console.log('Frame count:', frameCount);
Race Condition Errors
Error: Test passes sometimes, fails other times
Cause: Race condition / flaky test
Quick Fixes:
// 1. Wait for network to settle
await page.waitForLoadState('networkidle');
// 2. Wait for specific API calls
await page.waitForResponse('**/api/data');
// 3. Add explicit waits
await page.locator('[data-testid="element"]').waitFor({ state: 'visible' });
// 4. Increase timeouts
await expect(page.locator('[data-testid="result"]')).toBeVisible({
timeout: 15000
});
// 5. Enable retries in playwright.config.ts
retries: 2,
Context/State Errors
Error: "localStorage is not defined"
Cause: Accessing localStorage before page is loaded
Quick Fixes:
// 1. Navigate to page first
await page.goto('/');
await page.evaluate(() => localStorage.setItem('key', 'value'));
// 2. Use context.addInitScript for early setup
await context.addInitScript(() => {
localStorage.setItem('key', 'value');
});
Error: "Test passes in isolation but fails in suite"
Cause: Test pollution / shared state
Quick Fixes:
// 1. Clear state in beforeEach
test.beforeEach(async ({ page }) => {
await page.context().clearCookies();
await page.evaluate(() => {
localStorage.clear();
sessionStorage.clear();
});
});
// 2. Use test.describe.serial for dependent tests
test.describe.serial('Login flow', () => {
// Tests run in order
});
// 3. Create fresh context for each test
test.use({ storageState: undefined });
Configuration Errors
Error: "Cannot find module '@playwright/test'"
Cause: Playwright not installed
Quick Fixes:
# Install Playwright
npm install -D @playwright/test
# Install browsers
npx playwright install
Error: "No tests found"
Cause: Test files not matching pattern
Quick Fixes:
// In playwright.config.ts
testDir: './tests',
testMatch: '**/*.spec.ts', // Or *.test.ts
Debugging Commands
# Run with UI mode
npx playwright test --ui
# Run in headed mode
npx playwright test --headed
# Debug specific test
npx playwright test --debug test-file.spec.ts
# Show trace
npx playwright show-trace trace.zip
# Generate code
npx playwright codegen localhost:3000