E2E Testing
End-to-end testing with Playwright
Zeno uses Playwright for reliable end-to-end testing across browsers.
Setup
E2E tests are located in packages/e2e/:
packages/e2e/
├── playwright.config.ts
├── tests/
│ └── docs/
│ └── example.spec.ts
└── test-results/Configuration
// playwright.config.ts
import { defineConfig, devices } from "@playwright/test"
export default defineConfig({
testDir: "./tests",
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 3 : 0,
reporter: process.env.CI ? "html" : "list",
use: {
trace: "on-first-retry",
},
projects: [
{
name: "chromium",
use: { ...devices["Desktop Chrome"] },
},
],
webServer: {
command: "cd ../../apps/docs && npm run start -- -p 5002",
url: "http://localhost:5002",
reuseExistingServer: !process.env.CI,
},
})Writing Tests
import { expect, test } from "@playwright/test"
test("homepage loads successfully", async ({ page }) => {
const response = await page.goto("http://localhost:5002", {
waitUntil: "networkidle",
})
await expect(response?.status()).toBe(200)
})
test("navigation works", async ({ page }) => {
await page.goto("http://localhost:5002")
await page.click('a[href="/docs"]')
await expect(page).toHaveURL(/.*docs/)
})Commands
# Run E2E tests
pnpm e2e
# Watch mode (with dev server)
pnpm e2e:watch
# Run specific test file
pnpm turbo run e2e -- tests/docs/example.spec.tsCI Configuration
In CI, tests run with:
- HTML reporter for artifacts
- 3 retries on failure
- 30-second timeout
- Trace collection on first retry
Page Object Pattern
For larger test suites, use page objects:
// pages/home.ts
import { Page } from "@playwright/test"
export class HomePage {
constructor(private page: Page) {}
async goto() {
await this.page.goto("http://localhost:5002")
}
async clickDocs() {
await this.page.click('a[href="/docs"]')
}
}
// tests/navigation.spec.ts
import { test, expect } from "@playwright/test"
import { HomePage } from "../pages/home"
test("navigate to docs", async ({ page }) => {
const home = new HomePage(page)
await home.goto()
await home.clickDocs()
await expect(page).toHaveURL(/.*docs/)
})Best Practices
- Use
networkidlefor page loads - Prefer role-based selectors (
getByRole,getByText) - Don't use
test.onlyin committed code - Keep tests independent
- Use fixtures for shared setup