# Frontend Test Automation Plan **Date**: 2026-01-18 **Status**: Awaiting Approval **Related**: [2026-01-18-frontend-tests.md](../tests/2026-01-18-frontend-tests.md) ## Executive Summary This plan formalizes the automated testing of 35+ API endpoints manually tested on 2026-01-18. The testing covered 7 major areas including end-to-end user flows, edge cases, queue behavior, authentication, performance, real-time features, and data integrity. **Recommendation**: Most tests should be added as **integration tests** (Supertest-based), with select critical flows as **E2E tests**. This aligns with ADR-010 and ADR-040's guidance on testing economics. --- ## Analysis of Manual Tests vs Existing Coverage ### Current Test Coverage | Test Type | Existing Files | Existing Tests | | ----------- | -------------- | -------------- | | Integration | 21 files | ~150+ tests | | E2E | 9 files | ~40+ tests | ### Gap Analysis | Manual Test Area | Existing Coverage | Gap | Priority | | -------------------------- | ------------------------- | --------------------------- | -------- | | Budget API | budget.integration.test | Partial - add validation | Medium | | Deals API | None | **New file needed** | Low | | Reactions API | None | **New file needed** | Low | | Gamification API | gamification.integration | Good coverage | None | | Recipe API | recipe.integration.test | Add fork error, comment | Medium | | Receipt API | receipt.integration.test | Good coverage | None | | UPC API | upc.integration.test | Good coverage | None | | Price History API | price.integration.test | Good coverage | None | | Personalization API | public.routes.integration | Good coverage | None | | Admin Routes | admin.integration.test | Add queue/trigger endpoints | Medium | | Edge Cases (Area 2) | Scattered | **Consolidate/add** | High | | Queue/Worker (Area 3) | Partial | Add admin trigger tests | Medium | | Auth Edge Cases (Area 4) | auth.integration.test | Add token malformation | Medium | | Performance (Area 5) | None | **Not recommended** | Skip | | Real-time/Polling (Area 6) | notification.integration | Add job status polling | Low | | Data Integrity (Area 7) | Scattered | **Consolidate** | High | --- ## Implementation Plan ### Phase 1: New Integration Test Files (Priority: High) #### 1.1 Create `deals.integration.test.ts` **Rationale**: Routes were unmounted until this testing session; no tests exist. ```typescript // Tests to add: describe('Deals API', () => { it('GET /api/deals/best-watched-prices requires auth'); it('GET /api/deals/best-watched-prices returns watched items for user'); it('Returns empty array when no watched items'); }); ``` **Estimated effort**: 30 minutes #### 1.2 Create `reactions.integration.test.ts` **Rationale**: Routes were unmounted until this testing session; no tests exist. ```typescript // Tests to add: describe('Reactions API', () => { it('GET /api/reactions/summary/:targetType/:targetId returns counts'); it('POST /api/reactions/toggle requires auth'); it('POST /api/reactions/toggle toggles reaction on/off'); it('Returns validation error for invalid target_type'); it('Returns validation error for non-string entity_id'); }); ``` **Estimated effort**: 45 minutes #### 1.3 Create `edge-cases.integration.test.ts` **Rationale**: Consolidate edge case tests discovered during manual testing. ```typescript // Tests to add: describe('Edge Cases', () => { describe('File Upload Validation', () => { it('Accepts small files'); it('Processes corrupt file with IMAGE_CONVERSION_FAILED'); it('Rejects wrong checksum format'); it('Rejects short checksum'); }); describe('Input Sanitization', () => { it('Handles XSS payloads in shopping list names (stores as-is)'); it('Handles unicode/emoji in text fields'); it('Rejects null bytes in JSON'); it('Handles very long input strings'); }); describe('Authorization Boundaries', () => { it('Cross-user access returns 404 (not 403)'); it('SQL injection in query params is safely handled'); }); }); ``` **Estimated effort**: 1.5 hours #### 1.4 Create `data-integrity.integration.test.ts` **Rationale**: Consolidate FK/cascade/constraint tests. ```typescript // Tests to add: describe('Data Integrity', () => { describe('Cascade Deletes', () => { it('User deletion cascades to shopping lists, budgets, notifications'); it('Shopping list deletion cascades to items'); it('Admin cannot delete own account'); }); describe('FK Constraints', () => { it('Rejects invalid FK references via API'); it('Rejects invalid FK references via direct DB'); }); describe('Unique Constraints', () => { it('Duplicate email returns CONFLICT'); it('Duplicate flyer checksum is handled'); }); describe('CHECK Constraints', () => { it('Budget period rejects invalid values'); it('Budget amount rejects negative values'); }); }); ``` **Estimated effort**: 2 hours --- ### Phase 2: Extend Existing Integration Tests (Priority: Medium) #### 2.1 Extend `budget.integration.test.ts` Add validation edge cases discovered during manual testing: ```typescript // Tests to add: it('Rejects period="yearly" (only weekly/monthly allowed)'); it('Rejects negative amount_cents'); it('Rejects invalid date format'); it('Returns 404 for update on non-existent budget'); it('Returns 404 for delete on non-existent budget'); ``` **Estimated effort**: 30 minutes #### 2.2 Extend `admin.integration.test.ts` Add queue and trigger endpoint tests: ```typescript // Tests to add: describe('Queue Management', () => { it('GET /api/admin/queues/status returns all queue counts'); it('POST /api/admin/trigger/analytics-report enqueues job'); it('POST /api/admin/trigger/weekly-analytics enqueues job'); it('POST /api/admin/trigger/daily-deal-check enqueues job'); it('POST /api/admin/jobs/:queue/:id/retry retries failed job'); it('POST /api/admin/system/clear-cache clears Redis cache'); it('Returns validation error for invalid queue name'); it('Returns 404 for retry on non-existent job'); }); ``` **Estimated effort**: 1 hour #### 2.3 Extend `auth.integration.test.ts` Add token malformation edge cases: ```typescript // Tests to add: describe('Token Edge Cases', () => { it('Empty Bearer token returns Unauthorized'); it('Token without dots returns Unauthorized'); it('Token with 2 parts returns Unauthorized'); it('Token with invalid signature returns Unauthorized'); it('Lowercase "bearer" scheme is accepted'); it('Basic auth scheme returns Unauthorized'); it('Tampered token payload returns Unauthorized'); }); describe('Login Security', () => { it('Wrong password and non-existent user return same error'); it('Forgot password returns same response for existing/non-existing'); }); ``` **Estimated effort**: 45 minutes #### 2.4 Extend `recipe.integration.test.ts` Add fork error case and comment tests: ```typescript // Tests to add: it('Fork fails for seed recipes (null user_id)'); it('POST /api/recipes/:id/comments adds comment'); it('GET /api/recipes/:id/comments returns comments'); ``` **Estimated effort**: 30 minutes #### 2.5 Extend `notification.integration.test.ts` Add job status polling tests: ```typescript // Tests to add: describe('Job Status Polling', () => { it('GET /api/ai/jobs/:id/status returns completed job'); it('GET /api/ai/jobs/:id/status returns failed job with error'); it('GET /api/ai/jobs/:id/status returns 404 for non-existent'); it('Job status endpoint works without auth (public)'); }); ``` **Estimated effort**: 30 minutes --- ### Phase 3: E2E Tests (Priority: Low-Medium) Per ADR-040, E2E tests should be limited to critical user flows. The existing E2E tests cover the main flows well. However, we should consider: #### 3.1 Do NOT Add - Performance tests (handle via monitoring, not E2E) - Pagination tests (integration level is sufficient) - Cache behavior tests (integration level is sufficient) #### 3.2 Consider Adding (Optional) **Budget flow E2E** - If budget management becomes a critical feature: ```typescript // budget-journey.e2e.test.ts describe('Budget Journey', () => { it('User creates budget → tracks spending → sees analysis'); }); ``` **Recommendation**: Defer unless budget becomes a core value proposition. --- ### Phase 4: Documentation Updates #### 4.1 Update ADR-010 Add the newly discovered API gotchas to the testing documentation: - `entity_id` must be STRING in reactions - `customItemName` (camelCase) in shopping list items - `scan_source` must be `manual_entry`, not `manual` #### 4.2 Update CLAUDE.md Add API reference section for correct endpoint calls (already captured in test doc). --- ## Tests NOT Recommended Per ADR-040 (Testing Economics), the following tests from the manual session should NOT be automated: | Test Area | Reason | | --------------------------- | ------------------------------------------------- | | Performance benchmarks | Use APM/monitoring tools instead (see ADR-015) | | Concurrent request handling | Connection pool behavior is framework-level | | Cache hit/miss timing | Observable via Redis metrics, not test assertions | | Response time consistency | Better suited for production monitoring | | WebSocket/SSE | Not implemented - polling is the architecture | --- ## Implementation Timeline | Phase | Description | Effort | Priority | | --------- | ------------------------------ | ------------ | -------- | | 1.1 | deals.integration.test.ts | 30 min | High | | 1.2 | reactions.integration.test.ts | 45 min | High | | 1.3 | edge-cases.integration.test.ts | 1.5 hours | High | | 1.4 | data-integrity.integration.ts | 2 hours | High | | 2.1 | Extend budget tests | 30 min | Medium | | 2.2 | Extend admin tests | 1 hour | Medium | | 2.3 | Extend auth tests | 45 min | Medium | | 2.4 | Extend recipe tests | 30 min | Medium | | 2.5 | Extend notification tests | 30 min | Medium | | 4.x | Documentation updates | 30 min | Low | | **Total** | | **~8 hours** | | --- ## Verification Strategy For each new test file, verify by running: ```bash # In dev container npm run test:integration -- --run src/tests/integration/.test.ts ``` All tests should: 1. Pass consistently (no flaky tests) 2. Run in isolation (no shared state) 3. Clean up test data (use `cleanupDb()`) 4. Follow existing patterns in the codebase --- ## Risks and Mitigations | Risk | Mitigation | | ------------------------------------ | --------------------------------------------------- | | Test flakiness from async operations | Use proper waitFor/polling utilities | | Database state leakage between tests | Strict cleanup in afterEach/afterAll | | Queue state affecting test isolation | Drain/pause queues in tests that interact with them | | Port conflicts | Use dedicated test port (3099) | --- ## Approval Request Please review and approve this plan. Upon approval, implementation will proceed in priority order (Phase 1 first). **Questions for clarification**: 1. Should the deals/reactions routes remain mounted, or was that a temporary fix? 2. Is the recipe fork failure for seed recipes expected behavior or a bug to fix? 3. Any preference on splitting Phase 1 into multiple PRs vs one large PR?