veza/docs/testing/E2E_STABILITY_GUIDE.md
senke 172581ff02 chore(cleanup): remove orphan code + archive disabled workflows + .playwright-mcp
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 in d12b901de). 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 (commit 279a10d31); 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>
2026-04-20 20:33:40 +02:00

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()` |