Triple cleanup, landed together because they share the same cleanup branch intent and touch non-overlapping trees. 1. 38× tracked .playwright-mcp/*.yml stage-deleted MCP session recordings that had been inadvertently committed. .gitignore already covers .playwright-mcp/ (post-audit J2 block added ind12b901de). Working tree copies removed separately. 2. 19× disabled CI workflows moved to docs/archive/workflows/ Legacy .yml.disabled files in .github/workflows/ were 1676 LOC of dead config (backend-ci, cd, staging-validation, accessibility, chromatic, visual-regression, storybook-audit, contract-testing, zap-dast, container-scan, semgrep, sast, mutation-testing, rust-mutation, load-test-nightly, flaky-report, openapi-lint, commitlint, performance). Preserved in docs/archive/workflows/ for historical reference; `.github/workflows/` now only lists the 5 actually-running pipelines. 3. Orphan code removed (0 consumers confirmed via grep) - veza-backend-api/internal/repository/user_repository.go In-memory UserRepository mock, never imported anywhere. - proto/chat/chat.proto Chat server Rust deleted 2026-02-22 (commit279a10d31); proto file was orphan spec. Chat lives 100% in Go backend now. - veza-common/src/types/chat.rs (Conversation, Message, MessageType, Attachment, Reaction) - veza-common/src/types/websocket.rs (WebSocketMessage, PresenceStatus, CallType — depended on chat::MessageType) - veza-common/src/types/mod.rs updated: removed `pub mod chat;`, `pub mod websocket;`, and their re-exports. Only `veza_common::logging` is consumed by veza-stream-server (verified with `grep -r "veza_common::"`). `cargo check` on veza-common passes post-removal. Refs: AUDIT_REPORT.md §8.2 "Code mort / orphelin" + §9.1. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
85 lines
2.7 KiB
Markdown
85 lines
2.7 KiB
Markdown
# E2E Test Stability Guide
|
|
|
|
## Architecture
|
|
|
|
```
|
|
tests/e2e/
|
|
├── playwright.config.ts # Main config (sharding, multi-browser)
|
|
├── global-setup.ts # Creates test users via API
|
|
├── global-teardown.ts # Cleanup
|
|
├── helpers.ts # Core helpers (login, navigate, assert)
|
|
├── helpers/
|
|
│ └── selectors.ts # Centralized selectors (SEL object)
|
|
├── fixtures/
|
|
│ ├── auth.fixture.ts # API-driven auth fixtures
|
|
│ ├── factories.ts # Test data factories (user, playlist, etc.)
|
|
│ └── file-helpers.ts # Mock MP3 file generators
|
|
├── *.spec.ts # Test specs
|
|
└── audit/ # Audit-specific specs (a11y, visual, etc.)
|
|
```
|
|
|
|
## Selectors
|
|
|
|
**Always use `data-testid` for E2E selectors.** Import from `helpers/selectors.ts`:
|
|
|
|
```ts
|
|
import { SEL } from './helpers/selectors';
|
|
|
|
// Good
|
|
await page.getByTestId(SEL.toast.success);
|
|
await page.getByTestId(SEL.dialog.confirm);
|
|
|
|
// Bad — fragile, breaks on text changes
|
|
await page.getByText('Create');
|
|
await page.locator('button.submit');
|
|
```
|
|
|
|
Component `data-testid` are defined in `apps/web/src/components/ui/testids.ts` and mirrored in `SEL`.
|
|
|
|
## Authentication
|
|
|
|
**Use API login, not UI login** for tests that don't test the login flow:
|
|
|
|
```ts
|
|
import { test, expect } from '../fixtures/auth.fixture';
|
|
|
|
test('playlist CRUD', async ({ listenerPage }) => {
|
|
// listenerPage is already authenticated via API
|
|
await listenerPage.goto('/playlists');
|
|
});
|
|
```
|
|
|
|
## Data Factories
|
|
|
|
**Create test data via API, not UI clicks:**
|
|
|
|
```ts
|
|
import { createPlaylist, ensureTracksExist } from '../fixtures/factories';
|
|
|
|
test('add track to playlist', async ({ creatorPage }) => {
|
|
const playlist = await createPlaylist(creatorPage, { name: 'Test Playlist' });
|
|
// ...
|
|
});
|
|
```
|
|
|
|
## CI Configuration
|
|
|
|
- **e2e-critical**: `@critical` tag only, Chromium, blocks PR (<3min)
|
|
- **e2e-full**: All tests, 4-way sharded, all browsers, 10-15min
|
|
|
|
## Debugging Flaky Tests
|
|
|
|
1. Run locally with trace: `PLAYWRIGHT_TRACE=on npm run e2e:serial`
|
|
2. Check `tests/e2e/test-results/` for trace files
|
|
3. Open trace: `npx playwright show-trace <trace.zip>`
|
|
4. Check flaky report: `node scripts/flaky-detection.mjs`
|
|
|
|
## Common Pitfalls
|
|
|
|
| Problem | Solution |
|
|
|---------|----------|
|
|
| Toast selector mismatch | Use `data-testid="toast-success"` not text content |
|
|
| Dialog button collision | Use `data-testid="dialog-confirm"` not `getByText('Create')` |
|
|
| Rate limit in tests | Env `DISABLE_RATE_LIMIT_FOR_TESTS=true` |
|
|
| Stale selector after navigation | Wait for `main` element after `navigateTo()` |
|
|
| Login flaky | Use `loginViaAPI()` instead of `loginViaUI()` |
|