Files
flyer-crawler.projectium.com/docs/TESTING.md

6.5 KiB

Testing Guide

Overview

This project has comprehensive test coverage including unit tests, integration tests, and E2E tests. All tests must be run in the Linux dev container environment for reliable results.

Test Execution Environment

CRITICAL: All tests and type-checking MUST be executed inside the dev container (Linux environment).

Why Linux Only?

  • Path separators: Code uses POSIX-style paths (/) which may break on Windows
  • TypeScript compilation works differently on Windows vs Linux
  • Shell scripts and external dependencies assume Linux
  • Test results from Windows are unreliable and should be ignored

Running Tests Correctly

Open VS Code and use "Reopen in Container", then:

npm test                    # Run all tests
npm run test:unit          # Run unit tests only
npm run test:integration   # Run integration tests
npm run type-check         # Run TypeScript type checking

Option 2: Via Podman from Windows Host

From the Windows host, execute commands in the container:

# Run unit tests (2900+ tests - pipe to file for AI processing)
podman exec -it flyer-crawler-dev npm run test:unit 2>&1 | tee test-results.txt

# Run integration tests
podman exec -it flyer-crawler-dev npm run test:integration

# Run type checking
podman exec -it flyer-crawler-dev npm run type-check

# Run specific test file
podman exec -it flyer-crawler-dev npm test -- --run src/hooks/useAuth.test.tsx

Type Checking

TypeScript type checking is performed using tsc --noEmit.

Type Check Command

npm run type-check

Type Check Validation

The type-check command will:

  • Exit with code 0 if no errors are found
  • Exit with non-zero code and print errors if type errors exist
  • Check all files in the src/ directory as defined in tsconfig.json

IMPORTANT: Type-check on Windows may not show errors reliably. Always verify type-check results by running in the dev container.

Verifying Type Check Works

To verify type-check is working correctly:

  1. Run type-check in dev container: podman exec -it flyer-crawler-dev npm run type-check
  2. Check for output - errors will be displayed with file paths and line numbers
  3. No output + exit code 0 = no type errors

Example error output:

src/pages/MyDealsPage.tsx:68:31 - error TS2339: Property 'store_name' does not exist on type 'WatchedItemDeal'.

68                   <span>{deal.store_name}</span>
                                  ~~~~~~~~~~

Pre-Commit Hooks

The project uses Husky and lint-staged for pre-commit validation:

# .husky/pre-commit
npx lint-staged

Lint-staged configuration (.lintstagedrc.json):

{
  "*.{js,jsx,ts,tsx}": ["eslint --fix --no-color", "prettier --write"],
  "*.{json,md,css,html,yml,yaml}": ["prettier --write"]
}

Note: The --no-color flag prevents ANSI color codes from breaking file path links in git output.

Test Suite Structure

Unit Tests (~2900 tests)

Located throughout src/ directory alongside source files with .test.ts or .test.tsx extensions.

npm run test:unit

Integration Tests (5 test files)

Located in src/tests/integration/:

  • admin.integration.test.ts
  • flyer.integration.test.ts
  • price.integration.test.ts
  • public.routes.integration.test.ts
  • receipt.integration.test.ts

Requires PostgreSQL and Redis services running.

npm run test:integration

E2E Tests (3 test files)

Located in src/tests/e2e/:

  • deals-journey.e2e.test.ts
  • budget-journey.e2e.test.ts
  • receipt-journey.e2e.test.ts

Requires all services (PostgreSQL, Redis, BullMQ workers) running.

npm run test:e2e

Test Result Interpretation

  • Tests that pass on Windows but fail on Linux = BROKEN tests (must be fixed)
  • Tests that fail on Windows but pass on Linux = PASSING tests (acceptable)
  • Always use Linux (dev container) results as the source of truth

Test Helpers

Store Test Helpers

Located in src/tests/utils/storeHelpers.ts:

// Create a store with a location in one call
const store = await createStoreWithLocation({
  storeName: 'Test Store',
  address: {
    address_line_1: '123 Main St',
    city: 'Toronto',
    province_state: 'ON',
    postal_code: 'M1M 1M1',
  },
  pool,
  log,
});

// Cleanup stores and their locations
await cleanupStoreLocations([storeId1, storeId2], pool, log);

Mock Factories

Located in src/tests/utils/mockFactories.ts:

// Create mock data for tests
const mockStore = createMockStore({ name: 'Test Store' });
const mockAddress = createMockAddress({ city: 'Toronto' });
const mockStoreLocation = createMockStoreLocationWithAddress();
const mockStoreWithLocations = createMockStoreWithLocations({
  locations: [{ address: { city: 'Toronto' } }],
});

Known Integration Test Issues

See CLAUDE.md for documentation of common integration test issues and their solutions, including:

  1. Vitest globalSetup context isolation
  2. BullMQ cleanup queue timing issues
  3. Cache invalidation after direct database inserts
  4. Unique filename requirements for file uploads
  5. Response format mismatches
  6. External service availability

Continuous Integration

Tests run automatically on:

  • Pre-commit (via Husky hooks)
  • Pull request creation/update (via Gitea CI/CD)
  • Merge to main branch (via Gitea CI/CD)

CI/CD configuration:

  • .gitea/workflows/deploy-to-prod.yml
  • .gitea/workflows/deploy-to-test.yml

Coverage Reports

Test coverage is tracked using Vitest's built-in coverage tools.

npm run test:coverage

Coverage reports are generated in the coverage/ directory.

Debugging Tests

Enable Verbose Logging

# Run tests with verbose output
npm test -- --reporter=verbose

# Run specific test with logging
DEBUG=* npm test -- --run src/path/to/test.test.ts

Using Vitest UI

npm run test:ui

Opens a browser-based test runner with filtering and debugging capabilities.

Best Practices

  1. Always run tests in dev container - never trust Windows test results
  2. Run type-check before committing - catches TypeScript errors early
  3. Use test helpers - createStoreWithLocation(), mock factories, etc.
  4. Clean up test data - use cleanup helpers in afterEach/afterAll
  5. Verify cache invalidation - tests that insert data directly must invalidate cache
  6. Use unique filenames - file upload tests need timestamp-based filenames
  7. Check exit codes - npm run type-check returns 0 on success, non-zero on error