426 lines
12 KiB
Markdown
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`
|