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

9.3 KiB

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:

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

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)

# 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)

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)

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)

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:

# 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:

# 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

  • No 301 Moved Permanently responses in test output
  • All tests pass or fail for expected reasons (not redirect-related)
  • Type check passes
  • No regressions in unmodified tests

Edge Cases

Describe Block Text

Do NOT modify describe/it block descriptions:

// 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:

// KEEP AS-IS:
console.error('[DEBUG] GET /api/admin/stats failed:', ...);

Query Parameters

Include query parameters in update:

// OLD:
.get(`/api/budgets/spending-analysis?startDate=${start}&endDate=${end}`)

// NEW:
.get(`/api/v1/budgets/spending-analysis?startDate=${start}&endDate=${end}`)

Post-Completion Checklist

  • All 23 files updated
  • ~70 path occurrences migrated
  • Exclusion files unchanged
  • Type check passes
  • Integration tests pass (345/348)
  • E2E tests pass
  • Commit with message: fix(tests): Update API paths to use /api/v1/ prefix (ADR-008)

Rollback

If issues arise:

git checkout HEAD -- src/tests/
  • ADR-008: API Versioning Strategy
  • docs/architecture/api-versioning-infrastructure.md
  • src/routes/versioning.integration.test.ts (reference for expected behavior)