Files
flyer-crawler.projectium.com/docs/development/test-path-migration.md
Torben Sorensen f10c6c0cd6
All checks were successful
Deploy to Test Environment / deploy-to-test (push) Successful in 17m56s
Complete ADR-008 Phase 2
2026-01-27 11:06:09 -08:00

273 lines
9.3 KiB
Markdown

# Test Path Migration: Unversioned to Versioned API Paths
**Status**: Complete
**Created**: 2026-01-27
**Completed**: 2026-01-27
**Related**: ADR-008 (API Versioning Strategy)
## Summary
All integration test files have been successfully migrated to use versioned API paths (`/api/v1/`). This resolves the redirect-related test failures introduced by ADR-008 Phase 1.
### Results
| Metric | Value |
| ------------------------- | ---------------------------------------- |
| Test files updated | 23 |
| Path occurrences changed | ~70 |
| Tests before migration | 274/348 passing |
| Tests after migration | 345/348 passing |
| Test failures resolved | 71 |
| Remaining todo/skipped | 3 (known issues, not versioning-related) |
| Type check | Passing |
| Versioning-specific tests | 82/82 passing |
### Key Outcomes
- No `301 Moved Permanently` responses in test output
- All redirect-related failures resolved
- No regressions introduced
- Unit tests unaffected (3,375/3,391 passing, pre-existing failures)
---
## Original Problem Statement
Integration tests failed due to redirect middleware (ADR-008 Phase 1). Server returned `301 Moved Permanently` for unversioned paths (`/api/resource`) instead of expected `200 OK`. Redirect targets versioned paths (`/api/v1/resource`).
**Root Cause**: Backwards-compatibility redirect in `server.ts`:
```typescript
app.use('/api', (req, res, next) => {
const versionPattern = /^\/v\d+/;
if (!versionPattern.test(req.path)) {
return res.redirect(301, `/api/v1${req.path}`);
}
next();
});
```
**Impact**: ~70 test path occurrences across 23 files returning 301 instead of expected status codes.
## Solution
Update all test API paths from `/api/{resource}` to `/api/v1/{resource}`.
## Files Requiring Updates
### Integration Tests (16 files)
| File | Occurrences | Domains |
| ------------------------------------------------------------ | ----------- | ---------------------- |
| `src/tests/integration/inventory.integration.test.ts` | 14 | inventory |
| `src/tests/integration/receipt.integration.test.ts` | 17 | receipts |
| `src/tests/integration/recipe.integration.test.ts` | 17 | recipes, users/recipes |
| `src/tests/integration/user.routes.integration.test.ts` | 10 | users/shopping-lists |
| `src/tests/integration/admin.integration.test.ts` | 7 | admin |
| `src/tests/integration/flyer-processing.integration.test.ts` | 6 | ai/jobs |
| `src/tests/integration/budget.integration.test.ts` | 5 | budgets |
| `src/tests/integration/notification.integration.test.ts` | 3 | users/notifications |
| `src/tests/integration/data-integrity.integration.test.ts` | 3 | users, admin |
| `src/tests/integration/upc.integration.test.ts` | 3 | upc |
| `src/tests/integration/edge-cases.integration.test.ts` | 3 | users/shopping-lists |
| `src/tests/integration/user.integration.test.ts` | 2 | users |
| `src/tests/integration/public.routes.integration.test.ts` | 2 | flyers, recipes |
| `src/tests/integration/flyer.integration.test.ts` | 1 | flyers |
| `src/tests/integration/category.routes.test.ts` | 1 | categories |
| `src/tests/integration/gamification.integration.test.ts` | 1 | ai/jobs |
### E2E Tests (7 files)
| File | Occurrences | Domains |
| --------------------------------------------- | ----------- | -------------------- |
| `src/tests/e2e/inventory-journey.e2e.test.ts` | 9 | inventory |
| `src/tests/e2e/receipt-journey.e2e.test.ts` | 9 | receipts |
| `src/tests/e2e/budget-journey.e2e.test.ts` | 6 | budgets |
| `src/tests/e2e/upc-journey.e2e.test.ts` | 3 | upc |
| `src/tests/e2e/deals-journey.e2e.test.ts` | 2 | categories, users |
| `src/tests/e2e/user-journey.e2e.test.ts` | 1 | users/shopping-lists |
| `src/tests/e2e/flyer-upload.e2e.test.ts` | 1 | jobs |
## Update Pattern
### Find/Replace Rules
**Template literals** (most common):
```
OLD: .get(`/api/resource/${id}`)
NEW: .get(`/api/v1/resource/${id}`)
```
**String literals**:
```
OLD: .get('/api/resource')
NEW: .get('/api/v1/resource')
```
### Regex Pattern for Batch Updates
```regex
Find: (\.(get|post|put|delete|patch)\([`'"])/api/([a-z])
Replace: $1/api/v1/$3
```
**Explanation**: Captures HTTP method call, inserts `/v1/` after `/api/`.
## Files to EXCLUDE
These files intentionally test unversioned path behavior:
| File | Reason |
| ---------------------------------------------------- | ------------------------------------ |
| `src/routes/versioning.integration.test.ts` | Tests redirect behavior itself |
| `src/services/apiClient.test.ts` | Mock server URLs, not real API calls |
| `src/services/aiApiClient.test.ts` | Mock server URLs for MSW handlers |
| `src/services/googleGeocodingService.server.test.ts` | External Google API URL |
**Also exclude** (not API paths):
- Lines containing `vi.mock('@bull-board/api` (import mocks)
- Lines containing `/api/v99` (intentional unsupported version tests)
- `describe()` and `it()` block descriptions
- Comment lines (`// `)
## Execution Batches
### Batch 1: High-Impact Integration (4 files, ~58 occurrences)
```bash
# Files with most occurrences
src/tests/integration/inventory.integration.test.ts
src/tests/integration/receipt.integration.test.ts
src/tests/integration/recipe.integration.test.ts
src/tests/integration/user.routes.integration.test.ts
```
### Batch 2: Medium Integration (6 files, ~27 occurrences)
```bash
src/tests/integration/admin.integration.test.ts
src/tests/integration/flyer-processing.integration.test.ts
src/tests/integration/budget.integration.test.ts
src/tests/integration/notification.integration.test.ts
src/tests/integration/data-integrity.integration.test.ts
src/tests/integration/upc.integration.test.ts
```
### Batch 3: Low Integration (6 files, ~10 occurrences)
```bash
src/tests/integration/edge-cases.integration.test.ts
src/tests/integration/user.integration.test.ts
src/tests/integration/public.routes.integration.test.ts
src/tests/integration/flyer.integration.test.ts
src/tests/integration/category.routes.test.ts
src/tests/integration/gamification.integration.test.ts
```
### Batch 4: E2E Tests (7 files, ~31 occurrences)
```bash
src/tests/e2e/inventory-journey.e2e.test.ts
src/tests/e2e/receipt-journey.e2e.test.ts
src/tests/e2e/budget-journey.e2e.test.ts
src/tests/e2e/upc-journey.e2e.test.ts
src/tests/e2e/deals-journey.e2e.test.ts
src/tests/e2e/user-journey.e2e.test.ts
src/tests/e2e/flyer-upload.e2e.test.ts
```
## Verification Strategy
### Per-Batch Verification
After each batch:
```bash
# Type check
podman exec -it flyer-crawler-dev npm run type-check
# Run specific test file
podman exec -it flyer-crawler-dev npx vitest run <file-path> --reporter=verbose
```
### Full Verification
After all batches:
```bash
# Full integration test suite
podman exec -it flyer-crawler-dev npm run test:integration
# Full E2E test suite
podman exec -it flyer-crawler-dev npm run test:e2e
```
### Success Criteria
- [x] No `301 Moved Permanently` responses in test output
- [x] All tests pass or fail for expected reasons (not redirect-related)
- [x] Type check passes
- [x] No regressions in unmodified tests
## Edge Cases
### Describe Block Text
Do NOT modify describe/it block descriptions:
```typescript
// KEEP AS-IS (documentation only):
describe('GET /api/users/profile', () => { ... });
// UPDATE (actual API call):
const response = await request.get('/api/v1/users/profile');
```
### Console Logging
Do NOT modify debug/error logging paths:
```typescript
// KEEP AS-IS:
console.error('[DEBUG] GET /api/admin/stats failed:', ...);
```
### Query Parameters
Include query parameters in update:
```typescript
// OLD:
.get(`/api/budgets/spending-analysis?startDate=${start}&endDate=${end}`)
// NEW:
.get(`/api/v1/budgets/spending-analysis?startDate=${start}&endDate=${end}`)
```
## Post-Completion Checklist
- [x] All 23 files updated
- [x] ~70 path occurrences migrated
- [x] Exclusion files unchanged
- [x] Type check passes
- [x] Integration tests pass (345/348)
- [x] E2E tests pass
- [x] Commit with message: `fix(tests): Update API paths to use /api/v1/ prefix (ADR-008)`
## Rollback
If issues arise:
```bash
git checkout HEAD -- src/tests/
```
## Related Documentation
- ADR-008: API Versioning Strategy
- `docs/architecture/api-versioning-infrastructure.md`
- `src/routes/versioning.integration.test.ts` (reference for expected behavior)