505 lines
10 KiB
Markdown
505 lines
10 KiB
Markdown
# E2E Test Troubleshooting
|
|
|
|
Quick reference for common E2E test issues and solutions.
|
|
|
|
## Table of Contents
|
|
|
|
- [Test Failures](#test-failures)
|
|
- [Environment Issues](#environment-issues)
|
|
- [Browser Issues](#browser-issues)
|
|
- [Network Issues](#network-issues)
|
|
- [Database Issues](#database-issues)
|
|
- [Performance Issues](#performance-issues)
|
|
- [CI/CD Issues](#cicd-issues)
|
|
|
|
## Test Failures
|
|
|
|
### "Element not found" or "Timeout"
|
|
|
|
**Symptoms**: Test fails with timeout waiting for element
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Increase timeout
|
|
await page.locator("#element").isVisible({ timeout: 10000 });
|
|
|
|
// 2. Use conditional check
|
|
if (await page.locator("#element").isVisible({ timeout: 5000 })) {
|
|
await expect(page.locator("#element")).toBeVisible();
|
|
}
|
|
|
|
// 3. Wait for specific condition
|
|
await page.waitForURL("**/dashboard");
|
|
await page.waitForSelector("#element", { state: "visible" });
|
|
|
|
// 4. Wait for navigation
|
|
await Promise.all([
|
|
page.waitForURL("**/success"),
|
|
page.click("button[type='submit']"),
|
|
]);
|
|
```
|
|
|
|
**Common Causes**:
|
|
|
|
- Element hasn't loaded yet
|
|
- Page is still redirecting
|
|
- Animation in progress
|
|
- Element is conditionally rendered
|
|
|
|
### "Assertion failed"
|
|
|
|
**Symptoms**: Expect statement fails
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Add more context
|
|
await expect(page.locator("#element"), "Element should be visible")
|
|
.toBeVisible();
|
|
|
|
// 2. Use retry with timeout
|
|
await expect(async () => {
|
|
const isVisible = await page.locator("#element").isVisible();
|
|
expect(isVisible).toBe(true);
|
|
}).toPass({ timeout: 10000 });
|
|
|
|
// 3. Check actual value
|
|
const text = await page.locator("#element").textContent();
|
|
console.log("Actual text:", text);
|
|
```
|
|
|
|
### "Test is flaky" (passes sometimes, fails sometimes)
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Run test multiple times
|
|
npx playwright test --repeat-each=5
|
|
|
|
# 2. Increase retries in playwright.config.ts
|
|
retries: 3
|
|
|
|
# 3. Disable parallel execution
|
|
fullyParallel: false
|
|
workers: 1
|
|
```
|
|
|
|
**Common Causes**:
|
|
|
|
- Race conditions
|
|
- Network timing variations
|
|
- Database state not reset
|
|
- Previous test state leaking
|
|
|
|
### "Console errors in test"
|
|
|
|
**Symptoms**: Test reports console errors
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Filter expected errors
|
|
const errors: string[] = [];
|
|
page.on("console", (msg) => {
|
|
if (msg.type() === "error") {
|
|
errors.push(msg.text());
|
|
}
|
|
});
|
|
|
|
// After test
|
|
const filteredErrors = errors.filter(
|
|
(err) => !err.includes("net::ERR_BLOCKED_BY_CLIENT"),
|
|
);
|
|
expect(filteredErrors.length).toBe(0);
|
|
|
|
// 2. Fix the actual error in the application
|
|
```
|
|
|
|
## Environment Issues
|
|
|
|
### "Port 8080 already in use"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Kill process using port
|
|
lsof -ti:8080 | xargs kill -9
|
|
|
|
# 2. Use different port
|
|
PORT=8081 npx playwright test
|
|
|
|
# 3. Find and kill manually
|
|
ps aux | grep "deno task dev"
|
|
kill <PID>
|
|
```
|
|
|
|
### "E2E_TEST not recognized"
|
|
|
|
**Symptoms**: Tests don't bypass OAuth
|
|
|
|
**Solution**:
|
|
|
|
```typescript
|
|
// Ensure E2E mode is set in beforeEach
|
|
test.beforeEach(async ({ page }) => {
|
|
await page.addInitScript(() => {
|
|
globalThis.localStorage.setItem("E2E_TEST", "true");
|
|
});
|
|
});
|
|
```
|
|
|
|
### "Environment variables not set"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Set in shell
|
|
export E2E_TEST=true
|
|
export PORT=8080
|
|
|
|
# 2. Set in command
|
|
E2E_TEST=true PORT=8081 npx playwright test
|
|
|
|
# 3. Set in .env file (loaded by deno)
|
|
echo "E2E_TEST=true" > .env
|
|
echo "PORT=8080" >> .env
|
|
```
|
|
|
|
## Browser Issues
|
|
|
|
### "Browser not installed"
|
|
|
|
**Symptoms**: Error about chromium not installed
|
|
|
|
**Solution**:
|
|
|
|
```bash
|
|
npx playwright install --with-deps chromium
|
|
```
|
|
|
|
### "Browser crashes during test"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Update browsers
|
|
npx playwright install --force --with-deps chromium
|
|
|
|
# 2. Clear cache
|
|
rm -rf ~/.cache/ms-playwright
|
|
|
|
# 3. Run in headed mode to see crash
|
|
npx playwright test --headed
|
|
|
|
# 4. Check system resources
|
|
free -h # Memory
|
|
df -h # Disk space
|
|
```
|
|
|
|
### "Browser window too small"
|
|
|
|
**Solution**:
|
|
|
|
```typescript
|
|
// In playwright.config.ts
|
|
use: {
|
|
viewport: { width: 1920, height: 1080 },
|
|
}
|
|
|
|
// Or per test
|
|
test.use({ viewport: { width: 1920, height: 1080 } });
|
|
```
|
|
|
|
## Network Issues
|
|
|
|
### "Network request failed"
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Wait for network idle
|
|
await page.waitForLoadState("networkidle");
|
|
|
|
// 2. Wait for specific response
|
|
await page.waitForResponse("**/api/endpoint");
|
|
|
|
// 3. Handle timeout
|
|
try {
|
|
await page.goto("/slow-page", { timeout: 60000 });
|
|
} catch (error) {
|
|
console.log("Page load timeout, continuing...");
|
|
}
|
|
```
|
|
|
|
### "CORS errors"
|
|
|
|
**Symptoms**: Browser blocks requests due to CORS
|
|
|
|
**Solution**: This is an application issue, not a test issue. Fix CORS in
|
|
backend:
|
|
|
|
```typescript
|
|
// Add CORS headers
|
|
response.headers.set("Access-Control-Allow-Origin", "*");
|
|
```
|
|
|
|
### "API returns 401/403"
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Ensure E2E headers are set
|
|
await page.goto("/api/endpoint", {
|
|
headers: {
|
|
"x-e2e-user": "landlord",
|
|
},
|
|
});
|
|
|
|
// 2. Check user has permission
|
|
const response = await page.request.get("/api/protected", {
|
|
headers: {
|
|
"x-e2e-user": "admin", // Use admin if landlord lacks permission
|
|
},
|
|
});
|
|
```
|
|
|
|
## Database Issues
|
|
|
|
### "Database connection failed"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Check database is running
|
|
docker ps | grep postgres
|
|
# or
|
|
psql -h localhost -U postgres -c "SELECT 1;"
|
|
|
|
# 2. Check connection string
|
|
echo $POSTGRES_OPTIONS
|
|
|
|
# 3. Restart database
|
|
docker-compose restart postgres
|
|
|
|
# 4. Check database exists
|
|
psql -h localhost -U postgres -l | grep cyberhybridhub
|
|
```
|
|
|
|
### "Test data conflicts"
|
|
|
|
**Symptoms**: Tests interfere with each other's data
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Use unique data (add timestamp)
|
|
const timestamp = Date.now();
|
|
await page.locator('input[name="title"]').fill(`Test ${timestamp}`);
|
|
|
|
// 2. Clean up after test
|
|
test.afterEach(async ({ page }) => {
|
|
await page.request.delete("/api/test-data/cleanup", {
|
|
headers: { "x-e2e-user": "admin" },
|
|
});
|
|
});
|
|
|
|
// 3. Run tests serially
|
|
fullyParallel: false;
|
|
workers: 1;
|
|
```
|
|
|
|
### "Migration errors"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Run migrations
|
|
deno task db:push
|
|
|
|
# 2. Reset database (destructive!)
|
|
deno task db:reset
|
|
|
|
# 3. Check migration status
|
|
deno task db:status
|
|
```
|
|
|
|
## Performance Issues
|
|
|
|
### "Tests are too slow"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Run tests in parallel
|
|
npx playwright test --workers=4
|
|
|
|
# 2. Run only changed tests
|
|
npx playwright test --grep="pattern"
|
|
|
|
# 3. Skip slow tests
|
|
test.skip(process.env.CI, "Skipped in CI");
|
|
|
|
# 4. Use API tests instead of UI
|
|
const response = await page.request.get("/api/data");
|
|
```
|
|
|
|
### "Browser uses too much memory"
|
|
|
|
**Solutions**:
|
|
|
|
```bash
|
|
# 1. Reduce workers
|
|
npx playwright test --workers=1
|
|
|
|
# 2. Close pages after use
|
|
await page.close();
|
|
|
|
# 3. Restart between test runs
|
|
npx playwright test --worker=1
|
|
```
|
|
|
|
### "Test startup is slow"
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Reuse browser context
|
|
test.beforeAll(async ({ browser }) => {
|
|
context = await browser.newContext();
|
|
});
|
|
|
|
// 2. Use storage state (save/load cookies)
|
|
await context.storageState({ path: "state.json" });
|
|
|
|
// 3. Reduce timeout in config
|
|
timeout: 30000, // reduce from 60000
|
|
```
|
|
|
|
## CI/CD Issues
|
|
|
|
### "Tests pass locally but fail in CI"
|
|
|
|
**Solutions**:
|
|
|
|
```typescript
|
|
// 1. Increase retries in CI
|
|
retries: process.env.CI ? 2 : 0;
|
|
|
|
// 2. Increase timeouts in CI
|
|
timeout: process.env.CI ? 120000 : 60000;
|
|
|
|
// 3. Disable parallel in CI
|
|
fullyParallel: !process.env.CI;
|
|
|
|
// 4. Wait longer in tests
|
|
await page.waitForTimeout(process.env.CI ? 2000 : 1000);
|
|
```
|
|
|
|
### "CI runner out of disk space"
|
|
|
|
**Solutions**:
|
|
|
|
```yaml
|
|
# .github/workflows/e2e-tests.yml
|
|
- name: Clean up disk space
|
|
run: |
|
|
sudo rm -rf /usr/local/lib/android
|
|
sudo rm -rf /usr/share/dotnet
|
|
df -h
|
|
```
|
|
|
|
### "Artifacts not uploaded"
|
|
|
|
**Solutions**:
|
|
|
|
```yaml
|
|
# Ensure artifact upload step runs even on failure
|
|
- name: Upload artifacts
|
|
if: always() # Important!
|
|
uses: actions/upload-artifact@v4
|
|
```
|
|
|
|
### "Tests timeout in CI"
|
|
|
|
**Solutions**:
|
|
|
|
```yaml
|
|
# Increase job timeout
|
|
- name: Run tests
|
|
timeout-minutes: 60 # Increase from default 35
|
|
run: npx playwright test
|
|
```
|
|
|
|
## Debugging Tips
|
|
|
|
### Enable verbose logging
|
|
|
|
```bash
|
|
# Playwright verbose mode
|
|
DEBUG=pw:* npx playwright test
|
|
|
|
# Deno verbose mode
|
|
DENO_LOG=INFO npx playwright test
|
|
```
|
|
|
|
### Take screenshots manually
|
|
|
|
```typescript
|
|
await page.screenshot({
|
|
path: "debug-screenshot.png",
|
|
fullPage: true,
|
|
});
|
|
```
|
|
|
|
### Pause test execution
|
|
|
|
```typescript
|
|
// Add pause to inspect state
|
|
await page.pause();
|
|
```
|
|
|
|
### Log page state
|
|
|
|
```typescript
|
|
console.log("URL:", page.url());
|
|
console.log("Title:", await page.title());
|
|
console.log("Content:", await page.content());
|
|
```
|
|
|
|
### Check network requests
|
|
|
|
```typescript
|
|
page.on("request", (request) => {
|
|
console.log("Request:", request.url());
|
|
});
|
|
|
|
page.on("response", (response) => {
|
|
console.log("Response:", response.url(), response.status());
|
|
});
|
|
```
|
|
|
|
## Getting Help
|
|
|
|
If none of these solutions work:
|
|
|
|
1. Check [Playwright documentation](https://playwright.dev/docs/debug)
|
|
2. Review test output in `test-results/`
|
|
3. Open trace file: `npx playwright show-trace test-results/trace.zip`
|
|
4. Run in debug mode: `npx playwright test --debug`
|
|
5. Check GitHub issues for similar problems
|
|
6. Consult [E2E_TEST_GUIDE.md](./E2E_TEST_GUIDE.md)
|
|
|
|
## Common Error Messages
|
|
|
|
| Error | Cause | Solution |
|
|
| ---------------------------------- | ----------------------- | --------------------------------------- |
|
|
| `Test timeout of 60000ms exceeded` | Test took too long | Increase timeout or optimize test |
|
|
| `Target closed` | Browser crashed | Check system resources, restart browser |
|
|
| `Failed to find element` | Element not in DOM | Use waitForSelector, check selector |
|
|
| `Strict mode violation` | Multiple elements match | Use `first()` or more specific selector |
|
|
| `net::ERR_CONNECTION_REFUSED` | Server not running | Start dev server, check port |
|
|
| `401 Unauthorized` | Not authenticated | Set E2E headers properly |
|
|
| `404 Not Found` | Route doesn't exist | Check URL, verify route exists |
|
|
| `500 Internal Server Error` | Server error | Check server logs, fix bug |
|