Files
tfm_ainventory/docs/superpowers/specs/2026-04-19-phase-3-e2e-tests-design.md

426 lines
12 KiB
Markdown

# 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:**
1. Login (LDAP + local authentication)
2. Scan → Adjust Stock (barcode matching)
3. AI Extraction (new item onboarding)
4. Admin Settings (configuration & user management)
5. 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:**
1. ✅ LDAP user login (valid credentials → dashboard)
2. ✅ Local user login (password → dashboard)
3. ✅ Invalid LDAP credentials → error message
4. ✅ Invalid local password → error message
5. ✅ Missing username/password → validation error
6. ✅ Session expiry (token timeout) → redirect to login
7. ✅ Logout (clear session) → login screen
8. ✅ 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:**
1. ✅ Scan valid barcode → match existing item → open adjustment UI
2. ✅ Adjust quantity (+5) → confirm → audit log updated
3. ✅ Scan unknown barcode → create new item flow
4. ✅ Multiple consecutive scans (5+) → batch operations queue
5. ✅ Scan while offline → queue operation → sync on reconnect
6. ✅ Barcode not found → OCR fallback search
7. ✅ Box label scan → multi-item selection UI
8. ✅ 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:**
1. ✅ Capture photo → send to AI → receive extraction
2. ✅ AI response (name, part number, category) → validation UI
3. ✅ Confirm extracted data → save item
4. ✅ Reject extraction → manual entry form
5. ✅ AI extraction with multiple items in photo
6. ✅ Box discovery mode (AI focuses on container labels)
7. ✅ AI timeout → retry with exponential backoff
8. ✅ 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:**
1. ✅ Navigate to Admin Dashboard
2. ✅ Identity Manager: list users (LDAP + local)
3. ✅ Create new local user → email validation
4. ✅ Delete user → confirmation modal → audit log
5. ✅ AI Manager: switch provider (Gemini → Claude)
6. ✅ Update API key → test connection → success/failure
7. ✅ LDAP Manager: update server settings → test connection
8. ✅ Database Manager: view backup status → trigger backup
9. ✅ Category Manager: add/delete categories
10. ✅ 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:**
1. ✅ Perform operation (scan, create item) → offline detection
2. ✅ Queue 5+ operations while offline
3. ✅ Go online → automatic sync batch to server
4. ✅ UUID idempotency: sync same batch twice → no duplicates
5. ✅ Partial sync failure → retry remaining items
6. ✅ Sync with network timeout → exponential backoff
7. ✅ Concurrent updates (offline + online) → conflict resolution
8. ✅ 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`):**
```yaml
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:**
1. **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)
2. **Test Phase (~3-5 min)**
- Playwright runs test scenarios
- Browser automation against live app
- Real API calls to backend
3. **Teardown Phase (~5-10s)**
- Stop all containers
- Clean database volume
- Collect logs for debugging
---
## 6. Test Configuration
### 6.1 Playwright Config
```typescript
// 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:**
```bash
# .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
```bash
# 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
```bash
# 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-compose` plugin
- `curl` (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
1. ✅ Design approved
2. → Create implementation plan (writing-plans skill)
3. → Install Playwright, set up docker-compose.e2e.yml
4. → Build test fixtures (db, ldap, auth)
5. → Implement 5 workflow test files
6. → Verify parallel execution <30 min
7. → Commit & tag `phase-3-complete`