Files
flyer-crawler.projectium.com/docs/plans/2026-01-18-frontend-test-automation-plan.md
Torben Sorensen c24103d9a0
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 16m42s
frontend direct testing result and fixes
2026-01-18 13:57:47 -08:00

350 lines
12 KiB
Markdown

# 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/<file>.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?