docs: create phase 2 frontend tests design specification
This commit is contained in:
@@ -0,0 +1,536 @@
|
||||
# Phase 2 Frontend Tests Design Specification
|
||||
|
||||
**Date:** 2026-04-18
|
||||
**Status:** APPROVED
|
||||
**Target:** 80%+ coverage for frontend components, hooks, utilities
|
||||
**Branch:** `refactor/ai-friendly`
|
||||
**Reference:** Phase 1 Backend Tests (TDD pattern, subagent-driven execution)
|
||||
|
||||
---
|
||||
|
||||
## 1. Overview
|
||||
|
||||
Phase 2 creates a comprehensive Vitest test suite for the aInventory frontend, mirroring the TDD approach and execution patterns from Phase 1 (backend tests). The goal is to establish 80%+ coverage across 9 test files: 4 component suites, 3 utility/hook suites, and 2 integration workflows.
|
||||
|
||||
**Key Alignment with Phase 1:**
|
||||
- Test infrastructure first (setup.ts ≈ conftest.py)
|
||||
- Balanced unit + integration testing
|
||||
- Shared fixtures to avoid duplication
|
||||
- Subagent-driven execution (batches of 2-3 files)
|
||||
- Git tags for phase completion & rollback
|
||||
|
||||
---
|
||||
|
||||
## 2. Test Architecture & Setup
|
||||
|
||||
### 2.1 File Structure
|
||||
|
||||
```
|
||||
frontend/tests/
|
||||
├── setup.ts # Vitest config, shared mocks, fixtures
|
||||
├── components/
|
||||
│ ├── Scanner.test.tsx # QR scan + OCR matching
|
||||
│ ├── AIOnboarding.test.tsx # AI extraction wizard
|
||||
│ ├── AdminOverlay.test.tsx # Admin config UI
|
||||
│ └── IdentityCheckOverlay.test.tsx # Login form
|
||||
├── hooks/
|
||||
│ └── useAdmin.test.ts # Admin state hook
|
||||
├── lib/
|
||||
│ ├── api.test.ts # Axios + retry logic
|
||||
│ └── labels.test.ts # SVG/QR generation
|
||||
└── integration/
|
||||
├── scanner-workflow.test.tsx # Scan → match → adjust
|
||||
└── inventory-workflow.test.tsx # View → filter → create → sync
|
||||
```
|
||||
|
||||
### 2.2 Setup.ts (Shared Fixtures & Mocks)
|
||||
|
||||
**Purpose:** Centralized Vitest configuration and reusable mock fixtures (analogous to Phase 1's conftest.py)
|
||||
|
||||
**Contents:**
|
||||
1. **Vitest globals** — enable `describe`, `it`, `expect` without imports
|
||||
2. **vi.mock() calls** for:
|
||||
- `axios` — stub GET/POST/PUT with fixed responses
|
||||
- `dexie` — in-memory IndexedDB replacement
|
||||
- `html5-qrcode` — stub camera access (requestPermission, scan)
|
||||
- `next/router` — stub Next.js routing
|
||||
3. **Shared fixtures:**
|
||||
- Mock user token (valid + invalid variants)
|
||||
- Mock item list response (5 items with various states)
|
||||
- Mock AI extraction response (Gemini + Claude formats)
|
||||
- Mock offline sync queue
|
||||
4. **Cleanup:** Reset mocks before each test
|
||||
|
||||
**Philosophy:**
|
||||
- Same fixtures reused across all 9 test files
|
||||
- Test-specific overrides allowed (e.g., `vi.spyOn(axios, 'post').mockReturnValue(...)`)
|
||||
- Reduces boilerplate, ensures consistency
|
||||
|
||||
### 2.3 Vitest Configuration (vitest.config.ts)
|
||||
|
||||
**Setup:**
|
||||
```typescript
|
||||
import { defineConfig } from 'vitest/config'
|
||||
import react from '@vitejs/plugin-react'
|
||||
|
||||
export default defineConfig({
|
||||
plugins: [react()],
|
||||
test: {
|
||||
globals: true,
|
||||
environment: 'jsdom',
|
||||
setupFiles: ['./tests/setup.ts'],
|
||||
coverage: {
|
||||
provider: 'v8',
|
||||
reporter: ['text', 'html'],
|
||||
all: true,
|
||||
lines: 80,
|
||||
functions: 80,
|
||||
branches: 80,
|
||||
statements: 80,
|
||||
},
|
||||
},
|
||||
})
|
||||
```
|
||||
|
||||
**Key Settings:**
|
||||
- `environment: 'jsdom'` — simulate browser for React components
|
||||
- `setupFiles` — load shared mocks before tests
|
||||
- Coverage thresholds: **80%+ across all metrics** (lines, functions, branches, statements)
|
||||
|
||||
### 2.4 Package.json Updates
|
||||
|
||||
**Add dependencies:**
|
||||
```json
|
||||
{
|
||||
"devDependencies": {
|
||||
"vitest": "^1.0.0",
|
||||
"@vitest/ui": "^1.0.0",
|
||||
"@testing-library/react": "^14.0.0",
|
||||
"@testing-library/user-event": "^14.0.0",
|
||||
"@testing-library/jest-dom": "^6.0.0",
|
||||
"@vitejs/plugin-react": "^4.0.0",
|
||||
"jsdom": "^23.0.0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Test scripts:**
|
||||
```json
|
||||
{
|
||||
"scripts": {
|
||||
"test": "vitest",
|
||||
"test:ui": "vitest --ui",
|
||||
"test:coverage": "vitest run --coverage"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Component Tests (4 Files)
|
||||
|
||||
### 3.1 Scanner.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- Viewport rendering (video element, canvas overlay)
|
||||
- Zoom controls (1x → 2x → max cycle)
|
||||
- OCR matching engine (scoring, threshold logic)
|
||||
- Camera permission flows
|
||||
- State updates on scan result
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** Zoom logic, matching score calculation, error handling
|
||||
- **Integration:** Real component tree, mocked camera, verify state callbacks
|
||||
|
||||
**Coverage Targets:**
|
||||
- Render paths: initial + error states
|
||||
- Zoom cycle: all 4 states (1x, 2x, max/2, max)
|
||||
- Matching: exact match (500pts), partial (200pts), token (50pts), category (20pts), threshold (40pts)
|
||||
- Callbacks: onScanResult, onError
|
||||
|
||||
**Key Mocks:**
|
||||
- `html5-qrcode` — stub camera access, return fixed QR/barcode string
|
||||
- Component props — onScanResult callback verification
|
||||
|
||||
---
|
||||
|
||||
### 3.2 AIOnboarding.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- Step progression (image capture → extraction → confirmation)
|
||||
- Image preprocessing (validation, resize, crop, filter)
|
||||
- AI response formatting (Gemini vs Claude)
|
||||
- User validation of extracted data
|
||||
- Form submission
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** Step validation, data transformation, error messages
|
||||
- **Integration:** Full wizard flow, mocked AI response, verify final submit
|
||||
|
||||
**Coverage Targets:**
|
||||
- Step transitions: capture → extraction → confirm → done
|
||||
- Image validation: size, format, EXIF handling
|
||||
- AI response parsing: field mapping, confidence scores
|
||||
- User override: edited fields on confirmation step
|
||||
- Submit: API call with validated data
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios.post('/ai/extract')` — return mock Gemini/Claude response
|
||||
- Canvas API — image preprocessing simulation
|
||||
|
||||
---
|
||||
|
||||
### 3.3 AdminOverlay.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- Tab rendering (Identity, Database, LDAP, AI, Categories)
|
||||
- Form field validation (required, format, length)
|
||||
- Form submission with mocked API
|
||||
- Error message display
|
||||
- Loading states
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** Field validation, error rendering, tab switching
|
||||
- **Integration:** Full form submission, mock API response, state update
|
||||
|
||||
**Coverage Targets:**
|
||||
- Tab rendering: all 5 tabs present and switchable
|
||||
- Form validation: required fields, format validation, error messages
|
||||
- Submission: API call with payload, success/error handling
|
||||
- Loading state: button disabled, spinner visible during submission
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios.put('/admin/config')` — mock successful + error responses
|
||||
- Form fields — controlled component rendering
|
||||
|
||||
---
|
||||
|
||||
### 3.4 IdentityCheckOverlay.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- Login form rendering (username, password, login button)
|
||||
- Form validation (required fields)
|
||||
- LDAP authentication flow
|
||||
- Local password authentication fallback
|
||||
- Token storage and success callback
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** Form validation, error handling
|
||||
- **Integration:** Login flow, mocked auth endpoint, token storage
|
||||
|
||||
**Coverage Targets:**
|
||||
- Form fields: username + password required
|
||||
- Validation: empty field errors
|
||||
- LDAP login: POST to `/auth/login` with credentials
|
||||
- Success: token stored, onLoginSuccess callback fired
|
||||
- Error: error message displayed, form remains editable
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios.post('/auth/login')` — mock LDAP response with JWT token
|
||||
- localStorage — in-memory token storage
|
||||
|
||||
---
|
||||
|
||||
## 4. Hook & Utility Tests (3 Files)
|
||||
|
||||
### 4.1 useAdmin.test.ts
|
||||
|
||||
**What it tests:**
|
||||
- Hook initialization (load config from API)
|
||||
- State updates (identity, DB, LDAP, AI, categories)
|
||||
- Validation before submission
|
||||
- Error handling and retry logic
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** State mutations, validation logic
|
||||
- **Integration:** API calls (mocked), state persistence
|
||||
|
||||
**Coverage Targets:**
|
||||
- Initialization: load admin config on mount
|
||||
- State updates: each config section (identity, LDAP, AI, etc.)
|
||||
- Validation: required fields, format checks
|
||||
- Submission: API call with validated payload
|
||||
- Error states: network failure, validation error, server error
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios.get('/admin/config')` — return mock config object
|
||||
- `axios.put('/admin/config')` — mock success + error responses
|
||||
|
||||
---
|
||||
|
||||
### 4.2 api.test.ts
|
||||
|
||||
**What it tests:**
|
||||
- Axios instance configuration (base URL, headers, auth)
|
||||
- Request construction (query params, body, headers)
|
||||
- Retry logic for network failures
|
||||
- Response parsing and error mapping
|
||||
- Token refresh on 401
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** Request building, error mapping, retry logic
|
||||
- **Integration:** Mocked axios, verify request/response flow
|
||||
|
||||
**Coverage Targets:**
|
||||
- Auth headers: JWT token in Authorization header
|
||||
- Request types: GET, POST, PUT, DELETE
|
||||
- Query params: proper URL encoding
|
||||
- Retry: exponential backoff on network error
|
||||
- Error mapping: HTTP status → human-readable error message
|
||||
- Token refresh: 401 triggers new login flow
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios` — intercept requests, mock responses
|
||||
|
||||
---
|
||||
|
||||
### 4.3 labels.test.ts
|
||||
|
||||
**What it tests:**
|
||||
- SVG Code 128 barcode generation
|
||||
- SVG QR code generation (no external library)
|
||||
- Canvas-to-PNG rasterization (browser export)
|
||||
- Label dimension validation (62mm x 29mm)
|
||||
|
||||
**Test Types:**
|
||||
- **Unit:** SVG encoding, QR structure validation
|
||||
- **Integration:** Canvas API, image export
|
||||
|
||||
**Coverage Targets:**
|
||||
- Code 128 encoding: valid barcode structure
|
||||
- QR generation: valid QR format
|
||||
- SVG output: valid XML structure, correct dimensions
|
||||
- Canvas export: PNG blob generation
|
||||
- Error handling: invalid input, encoding errors
|
||||
|
||||
**Key Mocks:**
|
||||
- Canvas API — stub createImageData, getContext
|
||||
|
||||
---
|
||||
|
||||
## 5. Integration Tests (2 Files)
|
||||
|
||||
### 5.1 scanner-workflow.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- End-to-end: Scan QR/barcode → OCR match → select item → stock adjustment
|
||||
- Real component tree: Scanner + ItemList + StockAdjustmentForm
|
||||
- Mocked: html5-qrcode, axios (item API, stock update API)
|
||||
|
||||
**User Journey:**
|
||||
1. Scanner displays, user clicks "Scan"
|
||||
2. html5-qrcode stub returns barcode string
|
||||
3. Matching engine finds item (exact or partial match)
|
||||
4. Item details displayed in form
|
||||
5. User adjusts quantity, clicks "Check In"
|
||||
6. API updates stock, success message shown
|
||||
|
||||
**Coverage Targets:**
|
||||
- Scan trigger → match → form population
|
||||
- User interaction: quantity adjustment, submission
|
||||
- API integration: stock update call
|
||||
- Error handling: no match found, network error
|
||||
|
||||
**Key Mocks:**
|
||||
- `html5-qrcode` — return fixed barcode on scan
|
||||
- `axios.get('/items')` — return mock item list
|
||||
- `axios.post('/operations/checkin')` — mock success response
|
||||
|
||||
---
|
||||
|
||||
### 5.2 inventory-workflow.test.tsx
|
||||
|
||||
**What it tests:**
|
||||
- End-to-end: View inventory → filter/sort → create new item → offline sync
|
||||
- Real component tree: Dashboard + ItemTable + CreateItemModal + SyncStatus
|
||||
- Mocked: axios (all API calls), Dexie (IndexedDB for offline queue)
|
||||
|
||||
**User Journey:**
|
||||
1. Dashboard loads, displays item list from API
|
||||
2. User filters by category, sorts by quantity
|
||||
3. User clicks "Create Item", fills form, submits
|
||||
4. Network goes offline (axios fails)
|
||||
5. Item queued in IndexedDB (offline sync)
|
||||
6. Network comes back online
|
||||
7. Sync button triggers, offline items sent to backend
|
||||
8. Item list updates
|
||||
|
||||
**Coverage Targets:**
|
||||
- Data loading: initial list from API
|
||||
- Filter/sort: UI updates, no API call
|
||||
- Create item: form submission, success message
|
||||
- Offline queue: Dexie stores pending items
|
||||
- Sync: batch API call for offline items, success/error handling
|
||||
|
||||
**Key Mocks:**
|
||||
- `axios.get('/items')` — return mock inventory
|
||||
- `axios.post('/items')` — handle create + batch sync
|
||||
- `Dexie.table('pending_operations')` — in-memory queue
|
||||
|
||||
---
|
||||
|
||||
## 6. Execution Plan (Subagent-Driven)
|
||||
|
||||
### 6.1 Batch 1: Scanner Foundation (Tests 1-2)
|
||||
|
||||
**Files:** `setup.ts`, `Scanner.test.tsx`
|
||||
|
||||
**Tasks:**
|
||||
1. Create `frontend/tests/setup.ts` with Vitest config, shared mocks (axios, html5-qrcode, Dexie, next/router)
|
||||
2. Create `frontend/tests/components/Scanner.test.tsx` with unit + integration tests
|
||||
3. Run `npm test -- --coverage` and verify 80%+ on Scanner module
|
||||
|
||||
**Roles:**
|
||||
- Implementer: Write setup + Scanner tests
|
||||
- Reviewer 1: Validate mock fixtures align with Phase 1 patterns
|
||||
- Reviewer 2: Verify test coverage (render, zoom, matching, callbacks)
|
||||
|
||||
**Success Criteria:**
|
||||
- setup.ts exports fixtures and vi.mock() setup
|
||||
- Scanner tests cover all paths (unit + integration)
|
||||
- `npm test -- --coverage` shows 80%+ on Scanner module
|
||||
- All tests passing, no console errors
|
||||
|
||||
**Commit:** `test: setup vitest and create Scanner test suite`
|
||||
|
||||
---
|
||||
|
||||
### 6.2 Batch 2: AIOnboarding & Hooks (Tests 3-5)
|
||||
|
||||
**Files:** `AIOnboarding.test.tsx`, `useAdmin.test.ts`, `api.test.ts`
|
||||
|
||||
**Tasks:**
|
||||
1. Create `frontend/tests/components/AIOnboarding.test.tsx` — step progression, AI response parsing
|
||||
2. Create `frontend/tests/hooks/useAdmin.test.ts` — state management, form submission
|
||||
3. Create `frontend/tests/lib/api.test.ts` — request building, retry logic, error mapping
|
||||
|
||||
**Roles:**
|
||||
- Implementer: Reuse Batch 1 fixtures, write 3 test files
|
||||
- Reviewer 1: Ensure consistent mock usage across files
|
||||
- Reviewer 2: Verify 80%+ coverage on all 3 modules
|
||||
|
||||
**Success Criteria:**
|
||||
- All 3 test files created
|
||||
- Reuse setup.ts fixtures (no duplication)
|
||||
- `npm test -- --coverage` shows 80%+ on AIOnboarding, useAdmin, api
|
||||
- All tests passing
|
||||
|
||||
**Commit:** `test: add AIOnboarding, useAdmin, api test suites`
|
||||
|
||||
---
|
||||
|
||||
### 6.3 Batch 3: Admin & Utilities (Tests 6-7)
|
||||
|
||||
**Files:** `AdminOverlay.test.tsx`, `labels.test.ts`
|
||||
|
||||
**Tasks:**
|
||||
1. Create `frontend/tests/components/AdminOverlay.test.tsx` — tab rendering, form validation, submission
|
||||
2. Create `frontend/tests/lib/labels.test.ts` — barcode/QR generation, canvas export
|
||||
|
||||
**Roles:**
|
||||
- Implementer: Write 2 test files
|
||||
- Reviewer 1: Validate form field coverage (5 tabs, validation logic)
|
||||
- Reviewer 2: Verify SVG/canvas test patterns
|
||||
|
||||
**Success Criteria:**
|
||||
- Both test files created
|
||||
- AdminOverlay covers all 5 tabs + form submission
|
||||
- labels.ts covers Code 128, QR, canvas export
|
||||
- `npm test -- --coverage` shows 80%+ on both modules
|
||||
|
||||
**Commit:** `test: add AdminOverlay and labels test suites`
|
||||
|
||||
---
|
||||
|
||||
### 6.4 Batch 4: Identity & Integration (Tests 8-9)
|
||||
|
||||
**Files:** `IdentityCheckOverlay.test.tsx`, `scanner-workflow.test.tsx`, `inventory-workflow.test.tsx`
|
||||
|
||||
**Tasks:**
|
||||
1. Create `frontend/tests/components/IdentityCheckOverlay.test.tsx` — login form, LDAP flow, token storage
|
||||
2. Create `frontend/tests/integration/scanner-workflow.test.tsx` — scan → match → adjust
|
||||
3. Create `frontend/tests/integration/inventory-workflow.test.tsx` — view → filter → create → sync
|
||||
|
||||
**Roles:**
|
||||
- Implementer: Write 3 test files
|
||||
- Reviewer 1: Validate login flow coverage (LDAP, error states)
|
||||
- Reviewer 2: Verify integration test patterns (real component tree, mocked API)
|
||||
|
||||
**Success Criteria:**
|
||||
- All 3 test files created
|
||||
- IdentityCheckOverlay covers login + error states
|
||||
- scanner-workflow covers end-to-end scan flow
|
||||
- inventory-workflow covers CRUD + offline sync
|
||||
- `npm test -- --coverage` shows 80%+ on all modules
|
||||
|
||||
**Commit:** `test: add IdentityCheckOverlay and integration test suites`
|
||||
|
||||
---
|
||||
|
||||
### 6.5 Phase Completion
|
||||
|
||||
**Tasks:**
|
||||
1. Run full test suite: `npm test -- --coverage`
|
||||
2. Verify 80%+ coverage across all files
|
||||
3. Create git tag: `phase-2-complete`
|
||||
4. Update `SESSION_STATE.md` with Phase 2 status
|
||||
5. Update `REFACTORING_PROGRESS.md` (mark Phase 2 ✅)
|
||||
|
||||
**Success Criteria:**
|
||||
- All 9 test files created and passing
|
||||
- Coverage report: 80%+ on all metrics (lines, functions, branches, statements)
|
||||
- No console errors or warnings
|
||||
- Git tag `phase-2-complete` created
|
||||
|
||||
**Commit:** `docs: mark phase 2 complete - frontend test suite at 80%+ coverage`
|
||||
|
||||
---
|
||||
|
||||
## 7. Success Metrics
|
||||
|
||||
| Metric | Target | Status |
|
||||
|--------|--------|--------|
|
||||
| Test files created | 9 | ⏳ |
|
||||
| Total test cases | 100+ | ⏳ |
|
||||
| Coverage (lines) | 80%+ | ⏳ |
|
||||
| Coverage (functions) | 80%+ | ⏳ |
|
||||
| Coverage (branches) | 80%+ | ⏳ |
|
||||
| All tests passing | Yes | ⏳ |
|
||||
| No console errors | Yes | ⏳ |
|
||||
| Git tag `phase-2-complete` | Yes | ⏳ |
|
||||
|
||||
---
|
||||
|
||||
## 8. Dependencies & Pre-requisites
|
||||
|
||||
- Phase 1 (Backend Tests) ✅ COMPLETE
|
||||
- Vitest installed (v1.0.0+)
|
||||
- @testing-library/react installed
|
||||
- jsdom (React component testing environment)
|
||||
- Git tag `phase-1-complete` available for rollback
|
||||
|
||||
---
|
||||
|
||||
## 9. Rollback Plan
|
||||
|
||||
If Phase 2 encounters critical issues:
|
||||
|
||||
```bash
|
||||
# Rollback to Phase 1 completion
|
||||
git reset --hard phase-1-complete
|
||||
|
||||
# Delete Phase 2 tags
|
||||
git tag -d phase-2-complete
|
||||
|
||||
# Resume when ready
|
||||
git checkout refactor/ai-friendly
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Next Phase (Phase 3)
|
||||
|
||||
After Phase 2 completion:
|
||||
- Create `docs/superpowers/plans/2026-04-18-phase-3-e2e-tests.md`
|
||||
- Add Playwright E2E tests for critical workflows (login, scan, create item, offline sync, admin settings)
|
||||
- Target: 5+ workflows automated, <30 min runtime
|
||||
Reference in New Issue
Block a user