Skip to content

2026-01-01: Layered Testing Strategy

Task Metadata

  • 📆 Date: 2026-01-01
  • 🚥 Status: Completed

1. Context

  • Goal: Establish a robust testing infrastructure to prevent regressions (like the recent Settings Race Condition). We need to move beyond manual verification.
  • Trigger: Post-Mortem of "Settings Race Condition" incident.
  • Scope: Implement Layer 2 (Unit) and Layer 3 (Integration) testing.
    • Note: Layer 4 (Network Mocking) will be tackled in a follow-up task or as part of specific feature work. This task is about infrastructure.

2. Approach

  • Tool Selection:
    • Runner: vitest (Fast, Native Vite support).
    • Environment: jsdom (for React components).
    • Integration: react-testing-library (RTL) for component interactions.
  • Architecture:
    • Backend Tests: appsync/__tests__/ (Resolvers are pure functions).
    • Frontend Tests: Co-located __tests__ directories near the source files.
  • Testing Scope & Priorities (Phase 1):
    • MUST TEST (Priorities):
      • Core Business Logic (Backend): updateUserTargets.js (Verify mapping logic, error handling).
      • Core Utilities (Frontend): dateUtils.js (CRITICAL: 4 AM rule, time zone conversions).
      • Complex Interaction (Frontend): SettingsModal (Form state, submission handlers, validation).
    • SKIP (For Now):
      • Pure Presentation: Header, ProgressBar, DailyTotals (unless logic changes).
      • Simple Fetchers: useMeals (Wait for Layer 4/Network Mocking).
      • Full E2E: Playwright network mocking (Layer 4) is out of scope for this setup task.

3. Impact Analysis

  • Files to Modify:
    • frontend/package.json (Add vitest, jsdom, testing-library).
    • frontend/vite.config.js (Configure test runner).
    • docs/architecture/testing_strategy.md (Update status).
    • docs/project_management/templates/work_log_template.md (Add "Test Coverage" section to guide future work).
  • Risks:
    • Configuration Hell: Setting up ESM/CJS compatibility for AppSync resolvers (which might rely on specific AWS runtimes) can be tricky in Node.

4. Execution Plan

  • Step 1: Install & Configure Vitest
    • Install vitest, jsdom, @testing-library/react, @testing-library/jest-dom.
    • Create frontend/vitest.setup.js.
  • Step 2: Update Process Documentation
    • Update docs/project_management/templates/work_log_template.md: Add a section requiring explicit "Test Coverage" definition for new features (What to test vs. What to skip).
  • Step 3: Backend Unit Tests
    • Create appsync/__tests__/updateUserTargets.test.js.
    • Mock @aws-appsync/utils.
  • Step 4: Frontend Unit Tests
    • Create frontend/src/utils/__tests__/dateUtils.test.js.
  • Step 5: Frontend Integration Tests
    • Create frontend/src/components/__tests__/SettingsModal.test.jsx.
  • Step 6: CI Integration
    • Add test script to package.json.
    • Verify bun run test works.
  • Step 7: Document Data Behavior
    • Update docs/architecture/data_model.md to reflect findings about partial target updates and 0/null handling logic discovered during testing.
    • Create docs/architecture/ui_data_validation.md to explicitly document valid values, unit conversion logic, and the "0 as empty" pattern used in the UI.

5. Execution Notes

(AI to add details discovered during implementation)

  • Backend Testing: The @aws-appsync/utils package (v2.0.3) does not provide a runtime implementation for util.dynamodb (it exports empty objects). I had to manually mock toMapValues in the test setup to simulate DynamoDB JSON generation.
  • Frontend Accessibility: Integration testing with react-testing-library revealed that SettingsModal inputs were not semantically associated with their labels. I added htmlFor and id attributes to fix this, improving accessibility and enabling robust testing via getByLabelText.
  • Test Co-location: Tests are placed in __tests__ folders adjacent to the source code. This pattern was chosen to keep the project structure clean while ensuring tests stay close to the logic they verify (co-location), making it easier to maintain and find relevant tests without cluttering the primary source directories.
  • DynamoDB Mocking: Refactored backend tests to use a centralized mockUtils.js which implements an "identity mock" for util.dynamodb. This simplifies assertions by allowing us to check against plain JavaScript objects instead of verbose DynamoDB JSON structures, keeping unit tests focused on business logic.
  • Tech Debt / Future Improvements:
    • Layer 4 (Network Playwright): Not included in this task. Scheduled for "UI Polish" or subsequent feature.
    • Float Support: Currently, the GraphQL Schema enforces Int types. DynamoDB native Number type supports floats. A future task should update schema.graphql (change Int to Float) and the Frontend logic to support decimal entries (e.g. 1.5 scoops).

6. User Approval & Key Learnings

(User to confirm approval and add notes/learnings)

  • Approved by User: The task highlighted the importance of thinking through edge cases (user entry vs local state vs API calls vs DB representation).
  • Infrastructure: The automated testing pipeline (Vitest + Pre-commit) provides a strong safety net for future refactors, specifically the upcoming "Data Format Uplift".