12 KiB
Phase 3 Design: Playwright E2E Tests (Modular Workflows)
Date: 2026-04-19
Status: Design Approved
Target Runtime: <30 minutes (parallel execution)
Test Scope: 5 critical user workflows + error handling
1. Executive Summary
Phase 3 extends Phase 2 (284 unit tests) with end-to-end browser automation tests using Playwright. Each of 5 critical workflows runs in its own isolated Docker environment with a dedicated database, LDAP server, and app instance. Tests run in parallel, completing within <30 minutes.
Workflows:
- Login (LDAP + local authentication)
- Scan → Adjust Stock (barcode matching)
- AI Extraction (new item onboarding)
- Admin Settings (configuration & user management)
- Offline Sync (queue → sync idempotency)
2. Test Architecture
2.1 Directory Structure
frontend/e2e/
├── workflows/
│ ├── 1-login.spec.ts (LDAP + local auth flows)
│ ├── 2-scan-adjust.spec.ts (barcode scan, stock adjustment)
│ ├── 3-ai-extraction.spec.ts (photo → AI → validation)
│ ├── 4-admin-settings.spec.ts (admin dashboard, config changes)
│ └── 5-offline-sync.spec.ts (offline ops → sync)
├── fixtures/
│ ├── db.ts (SQLite seeding, cleanup, per-workflow)
│ ├── ldap.ts (OpenLDAP container setup, test users)
│ ├── auth.ts (login helpers, session management)
│ └── test-data.ts (seed definitions, factories)
├── utils/
│ ├── assertions.ts (custom Playwright matchers)
│ ├── docker.ts (container orchestration, lifecycle)
│ └── helpers.ts (navigation, wait conditions)
├── docker-compose.e2e.yml (shared services template)
├── playwright.config.ts (Playwright configuration)
└── README.md (setup & execution guide)
2.2 Per-Workflow Isolation
Each workflow runs independently:
| Workflow | Backend Port | Frontend Port | Database | LDAP | AI Mock |
|---|---|---|---|---|---|
| 1-login | 8906 | 8907 | Fresh | Yes | N/A |
| 2-scan-adjust | 8916 | 8917 | Seeded (10 items) | No | N/A |
| 3-ai-extraction | 8926 | 8927 | Fresh | No | Gemini/Claude mocked |
| 4-admin-settings | 8936 | 8937 | Seeded (users, categories) | Yes | Mocked |
| 5-offline-sync | 8946 | 8947 | Fresh | No | N/A |
Benefits:
- No port conflicts (workflows run in parallel)
- Failed workflow doesn't affect others
- Per-workflow database cleanup (no state leakage)
- Independent LDAP setup for auth workflows
3. Workflow Test Scenarios
3.1 Workflow 1: Login (LDAP + Local)
Setup: LDAP container with test users + app + empty database
Scenarios:
- ✅ LDAP user login (valid credentials → dashboard)
- ✅ Local user login (password → dashboard)
- ✅ Invalid LDAP credentials → error message
- ✅ Invalid local password → error message
- ✅ Missing username/password → validation error
- ✅ Session expiry (token timeout) → redirect to login
- ✅ Logout (clear session) → login screen
- ✅ Concurrent login attempts → proper queueing
Error Cases:
- LDAP server down → fallback to local auth
- Network timeout → retry with backoff
- Invalid token format → re-authenticate
3.2 Workflow 2: Scan → Adjust Stock
Setup: App + seeded database (10 items with barcodes)
Scenarios:
- ✅ Scan valid barcode → match existing item → open adjustment UI
- ✅ Adjust quantity (+5) → confirm → audit log updated
- ✅ Scan unknown barcode → create new item flow
- ✅ Multiple consecutive scans (5+) → batch operations queue
- ✅ Scan while offline → queue operation → sync on reconnect
- ✅ Barcode not found → OCR fallback search
- ✅ Box label scan → multi-item selection UI
- ✅ Concurrent scans → no race conditions
Error Cases:
- Barcode decode failure → retry
- Network timeout during save → offline queue
- Inventory constraint violation (negative qty) → validation error
- Concurrent quantity updates → last-write-wins with audit
3.3 Workflow 3: AI Extraction (New Item Onboarding)
Setup: App + empty database + mocked Gemini/Claude APIs
Scenarios:
- ✅ Capture photo → send to AI → receive extraction
- ✅ AI response (name, part number, category) → validation UI
- ✅ Confirm extracted data → save item
- ✅ Reject extraction → manual entry form
- ✅ AI extraction with multiple items in photo
- ✅ Box discovery mode (AI focuses on container labels)
- ✅ AI timeout → retry with exponential backoff
- ✅ Network failure during extraction → offline queue
Error Cases:
- Image validation (blur, size, format) → error message
- Invalid EXIF data → degrade gracefully
- AI service timeout (>10s) → user can retry or enter manually
- Malformed AI response → fallback to manual entry
- Concurrent extraction requests → queue + process sequentially
3.4 Workflow 4: Admin Settings
Setup: App + seeded database (5 test users, 8 categories) + LDAP
Scenarios:
- ✅ Navigate to Admin Dashboard
- ✅ Identity Manager: list users (LDAP + local)
- ✅ Create new local user → email validation
- ✅ Delete user → confirmation modal → audit log
- ✅ AI Manager: switch provider (Gemini → Claude)
- ✅ Update API key → test connection → success/failure
- ✅ LDAP Manager: update server settings → test connection
- ✅ Database Manager: view backup status → trigger backup
- ✅ Category Manager: add/delete categories
- ✅ Configuration saved → persists across sessions
Error Cases:
- Invalid API key → error toast, no save
- LDAP connection timeout → error state, keep previous config
- Concurrent config updates → optimistic UI + server validation
- Missing required fields → inline validation
- Database backup failure → error state, rollback
3.5 Workflow 5: Offline Sync
Setup: App + empty database + simulated offline mode
Scenarios:
- ✅ Perform operation (scan, create item) → offline detection
- ✅ Queue 5+ operations while offline
- ✅ Go online → automatic sync batch to server
- ✅ UUID idempotency: sync same batch twice → no duplicates
- ✅ Partial sync failure → retry remaining items
- ✅ Sync with network timeout → exponential backoff
- ✅ Concurrent updates (offline + online) → conflict resolution
- ✅ Local state persists (IndexedDB) → reload page → continues sync
Error Cases:
- Sync failure mid-batch → remaining items queued
- Server rejects UUID → log error, mark item as failed
- IndexedDB quota exceeded → error toast
- Corrupted queue entry → skip + continue
- Server version mismatch (audit schema) → graceful degradation
4. Error Handling & Resilience
4.1 Network Failures
Timeout Handling:
- API call timeout > 10s → retry 2x with exponential backoff (1s, 2s)
- Container startup timeout > 30s → fail fast, report health check failure
- Page load > 15s → timeout assertion
Connection Loss:
- Offline detection: monitor navigator.onLine + failed API call
- Offline queue: IndexedDB stores operations with UUID + timestamp
- Sync on reconnect: automatic batch send, retry failed items
4.2 Concurrent Operations
Race Condition Prevention:
- Scanning: queue concurrent scans, process sequentially
- Stock adjustment: last-write-wins with server validation
- Config updates: optimistic UI, server validation, rollback on fail
- AI extraction: single extraction per session (prevent duplicate calls)
4.3 Invalid Input Handling
- Image validation (size, format, blur) → inline error
- Missing required fields → form validation error
- Invalid barcode → OCR fallback + manual entry
- Malformed AI response → user can retry or enter manually
5. Docker & Infrastructure
5.1 Docker Compose Setup
Base Configuration (docker-compose.e2e.yml):
services:
# App backend
backend:
image: ainventory-backend:test
ports:
- "${BACKEND_PORT}:8906"
environment:
DATABASE_URL: sqlite:///test-${WORKFLOW_ID}.db
LDAP_ENABLED: "${LDAP_ENABLED}"
AI_PROVIDER: "${AI_PROVIDER}"
GEMINI_API_KEY: "test-key"
CLAUDE_API_KEY: "test-key"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8906/health"]
interval: 2s
timeout: 5s
retries: 10
# Frontend dev server
frontend:
image: node:20
working_dir: /app
ports:
- "${FRONTEND_PORT}:8907"
environment:
NEXT_PUBLIC_API_URL: "http://localhost:${BACKEND_PORT}"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 2s
retries: 10
# OpenLDAP (for auth workflows)
ldap:
image: osixia/openldap:latest
ports:
- "${LDAP_PORT}:389"
environment:
LDAP_ORGANISATION: "aInventory"
LDAP_BASE_DN: "dc=ainventory,dc=local"
5.2 Container Lifecycle
Per-Workflow:
-
Setup Phase (~15-20s)
- Start Docker Compose for workflow
- Wait for health checks (backend, frontend, LDAP if needed)
- Seed database (SQL migrations)
- Pre-populate LDAP users (if needed)
-
Test Phase (~3-5 min)
- Playwright runs test scenarios
- Browser automation against live app
- Real API calls to backend
-
Teardown Phase (~5-10s)
- Stop all containers
- Clean database volume
- Collect logs for debugging
6. Test Configuration
6.1 Playwright Config
// playwright.config.ts
export default defineConfig({
testDir: './e2e/workflows',
fullyParallel: true,
workers: 5, // Run 5 workflows in parallel
timeout: 30000, // 30s per test
expect: { timeout: 5000 },
webServer: [], // No webServer (Docker manages this)
use: {
baseURL: 'http://localhost', // Dynamic per workflow
trace: 'on-first-retry',
screenshot: 'only-on-failure',
},
});
6.2 Environment Setup
Env Variables per Workflow:
# .env.e2e.workflow-1
BACKEND_PORT=8906
FRONTEND_PORT=8907
LDAP_ENABLED=true
LDAP_PORT=3389
AI_PROVIDER=gemini
# .env.e2e.workflow-2
BACKEND_PORT=8916
FRONTEND_PORT=8917
LDAP_ENABLED=false
AI_PROVIDER=gemini
7. Test Execution & CI/CD
7.1 Local Execution
# Run all workflows in parallel
npm run e2e
# Run specific workflow
npm run e2e -- workflows/1-login.spec.ts
# Debug mode (headed browser)
npm run e2e:debug
7.2 Expected Runtime
- Per Workflow: 3-5 minutes
- Sequential Total: 15-25 minutes
- Parallel Total: 8-10 minutes (5 workers)
- Target: <30 minutes ✅
7.3 CI/CD Integration
# GitHub Actions / Local CI
npm run build
npm run e2e -- --reporter=html
# Report: playwright-report/index.html
8. Success Criteria
✅ All 5 workflows tested
✅ 40+ test cases across workflows
✅ Error scenarios included
✅ Parallel execution <30 min
✅ Zero flaky tests (3x runs stable)
✅ Comprehensive error handling
✅ Docker isolation working
✅ Database cleanup per workflow
✅ HTML report generated
9. Scope & Constraints
In Scope:
- Happy path workflows
- Critical error scenarios (network, auth, validation)
- Concurrent operation handling
- Offline → online sync
- Docker-based isolation
Out of Scope:
- Performance benchmarking
- Load testing
- Mobile-specific gestures (covered by Vitest unit tests)
- Visual regression testing
- Accessibility audits (covered by Phase 2)
10. Dependencies & Prerequisites
Required:
- Docker & Docker Compose
- Node.js 20+
- Playwright (
@playwright/test) - Python 3.12+ (backend venv)
Optional:
docker-composeplugincurl(for health checks)
11. Risk Mitigation
| Risk | Mitigation |
|---|---|
| Docker startup slow | Health checks + parallel workers |
| Flaky network tests | Retry logic + exponential backoff |
| Port conflicts | Offset ports per workflow (8906, 8916, 8926, etc.) |
| Database state leakage | Fresh DB per workflow, cleanup after |
| LDAP timeout | Fallback to local auth, skip LDAP tests if unavailable |
| Concurrent AI calls | Queue extraction requests, single-at-a-time processing |
12. Next Steps
- ✅ Design approved
- → Create implementation plan (writing-plans skill)
- → Install Playwright, set up docker-compose.e2e.yml
- → Build test fixtures (db, ldap, auth)
- → Implement 5 workflow test files
- → Verify parallel execution <30 min
- → Commit & tag
phase-3-complete