E2E Testing Overview
20.5.1. Framework Selection
Playwright is the recommended E2E testing framework.
| Item | Playwright | Cypress |
|---|---|---|
| Browser Support | Chromium, Firefox, WebKit | Chromium, Firefox, WebKit (experimental) |
| Execution Speed | Fast (parallel execution supported by default) | Moderate (paid plan required for parallel execution) |
| Multiple Tabs/Windows | Supported | Not supported |
| iframe Support | Native support | Limited |
| API Testing | Built-in support | Plugin required |
| Debugging Tools | Trace Viewer, Codegen | Cypress Runner |
| Language Support | TypeScript, JavaScript, Python, Java, .NET | TypeScript, JavaScript |
- Playwright natively supports multi-browser testing, parallel execution, and API testing, making it the TQS recommended framework.
- Projects already using Cypress are not required to migrate; however, new projects must adopt Playwright.
20.5.2. Core Scenarios
E2E tests verify the user's critical business workflows. The following scenarios are mandatory test targets.
| Scenario | Verification Items |
|---|---|
| Login/Logout | Successful login, invalid credentials handling, redirect after logout |
| CRUD Flow | Item creation, list retrieval, detail view, update, deletion |
| Error Handling | 404 page, user feedback on server errors, network error recovery |
| Access Control | Blocking unauthenticated user access, menu/feature visibility by permission |
| Form Submission | Validation, duplicate submission prevention, success/failure feedback |
typescript
// e2e/auth.spec.ts
import { test, expect } from '@playwright/test'
test.describe('Authentication Flow', () => {
test('should navigate to dashboard after successful login', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="input-email"]', 'user@example.com')
await page.fill('[data-testid="input-password"]', 'password123')
await page.click('[data-testid="btn-login"]')
await expect(page).toHaveURL('/dashboard')
await expect(page.locator('[data-testid="user-greeting"]')).toBeVisible()
})
test('should display an error message for incorrect password', async ({ page }) => {
await page.goto('/login')
await page.fill('[data-testid="input-email"]', 'user@example.com')
await page.fill('[data-testid="input-password"]', 'wrong')
await page.click('[data-testid="btn-login"]')
await expect(page.locator('[data-testid="error-message"]')).toBeVisible()
})
})- All core scenarios must be tested for both happy paths and error paths.
- Test scenarios must be mapped to user stories or requirements documents for management.
20.5.3. Test Writing Principles
User-Perspective Testing
E2E tests must be written based on elements the user sees and interacts with, not internal implementation details.
- Tests must not depend on CSS class names or internal component state.
- Use
data-testidattributes to select test target elements. data-testidnaming convention:{elementType}-{description}(e.g.,btn-submit,input-email,list-users)
Preventing Flaky Tests
Flaky tests undermine reliability; therefore, the following principles must be observed.
- Use condition-based waiting (
waitForSelector,expect().toBeVisible()) instead of fixed wait times (waitForTimeout). - Test data must be independently created and cleaned up within each test.
- External API dependencies should be replaced with mock servers whenever possible.
- Use
waitForResponse()to explicitly wait for network request completion.
20.5.4. CI Integration
The following configuration is required for automated E2E test execution in CI environments.
typescript
// playwright.config.ts
import { defineConfig } from '@playwright/test'
export default defineConfig({
testDir: './e2e',
fullyParallel: true,
retries: process.env.CI ? 2 : 0,
workers: process.env.CI ? 1 : undefined,
use: {
baseURL: 'http://localhost:3000',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'on-first-retry',
},
webServer: {
command: 'yarn dev',
port: 3000,
reuseExistingServer: !process.env.CI,
},
})| Configuration | CI Value | Description |
|---|---|---|
retries | 2 | Maximum 2 retries on failure |
workers | 1 | Serial execution for stability |
screenshot | only-on-failure | Automatic screenshot capture on failure |
video | on-first-retry | Video recording on first retry |
trace | on-first-retry | Trace file saved on first retry |
- Tests must run in headless mode in CI environments (Playwright default).
- Screenshots, videos, and Trace files generated on failure must be retained as CI artifacts.
- The
webServerconfiguration automatically starts the development server before testing. - Retries are enabled only in CI so that failures are immediately visible during local development.