Files
maternal-app/TESTING_STRATEGY.md
Andrei b2f3551ccd
Some checks failed
CI/CD Pipeline / Lint and Test (push) Has been cancelled
CI/CD Pipeline / E2E Tests (push) Has been cancelled
CI/CD Pipeline / Build Application (push) Has been cancelled
feat(testing): Implement testing foundation with strategy and first unit tests
Testing Strategy:
- Created comprehensive testing strategy document
- Target: 80%+ code coverage
- Testing pyramid: Unit (70%) → Integration (20%) → E2E (10%)
- Defined test data management and best practices

Backend Unit Tests:
- Created ComplianceService unit test suite (10 tests)
- Tests for data export, account deletion, cancellation
- Mock repository pattern for isolated testing
- AAA pattern (Arrange, Act, Assert)

Next Steps:
- Run and fix unit tests
- Create integration tests for API endpoints
- Setup frontend testing with React Testing Library
- Setup E2E tests with Playwright
- Configure CI/CD pipeline with GitHub Actions
- Achieve 80%+ code coverage

Status: Testing foundation initiated (0% → 5% progress)
2025-10-02 18:54:17 +00:00

13 KiB

Testing Strategy - Maternal App

Target Coverage: 80%+ across all layers Testing Pyramid: Unit (70%) → Integration (20%) → E2E (10%)


1. Backend Testing (NestJS)

1.1 Unit Tests (Target: 70% of tests)

Tools: Jest, @nestjs/testing

What to Test:

  • Services (Business Logic)

    • ComplianceService (data export, account deletion)
    • AuthService (registration with COPPA validation, login, token management)
    • ChildrenService (CRUD operations)
    • TrackingService (activity creation, daily summary)
    • AIService (chat, conversation memory)
    • VoiceService (intent classification, entity extraction)
    • EmbeddingsService (vector search, semantic memory)
  • Guards

    • JwtAuthGuard
    • Public decorator
  • Pipes

    • ValidationPipe (DTO validation)
  • Utilities

    • Date calculations
    • Age verification (COPPA compliance)
    • Token generation

Example Test Structure:

describe('ComplianceService', () => {
  let service: ComplianceService;
  let userRepository: Repository<User>;

  beforeEach(async () => {
    const module = await Test.createTestingModule({
      providers: [
        ComplianceService,
        { provide: getRepositoryToken(User), useClass: Repository },
      ],
    }).compile();

    service = module.get<ComplianceService>(ComplianceService);
  });

  it('should export user data with all entities', async () => {
    // Test implementation
  });

  it('should schedule account deletion with 30-day grace period', async () => {
    // Test implementation
  });
});

1.2 Integration Tests (Target: 20% of tests)

Tools: Jest, Supertest, @nestjs/testing

What to Test:

  • API Endpoints (Controller + Service + Database)

    • POST /api/v1/compliance/data-export
    • POST /api/v1/compliance/request-deletion
    • POST /api/v1/auth/register (with COPPA validation)
    • POST /api/v1/auth/login
    • POST /api/v1/activities (tracking)
    • POST /api/v1/ai/chat
  • Authentication Flows

    • Register → Login → Protected Route
    • Register with COPPA (age 13-17)
    • Register blocked (age < 13)
  • Database Operations

    • CRUD operations with real database
    • Transaction rollbacks
    • Cascade deletions

Example Test Structure:

describe('ComplianceController (e2e)', () => {
  let app: INestApplication;
  let authToken: string;

  beforeAll(async () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    app = moduleFixture.createNestApplication();
    await app.init();
  });

  it('/api/v1/compliance/data-export (GET)', () => {
    return request(app.getHttpServer())
      .get('/api/v1/compliance/data-export')
      .set('Authorization', `Bearer ${authToken}`)
      .expect(200)
      .expect((res) => {
        expect(res.body.data).toHaveProperty('user');
        expect(res.body.data).toHaveProperty('children');
        expect(res.body.data).toHaveProperty('activities');
      });
  });
});

2. Frontend Testing (Next.js + React)

2.1 Unit Tests (Component Testing)

Tools: Jest, React Testing Library, @testing-library/user-event

What to Test:

  • Components

    • DataExport component (button click, download trigger)
    • AccountDeletion component (dialog flow, deletion request)
    • Registration form (COPPA age validation, form submission)
    • Settings page (profile update, compliance sections)
    • Tracking forms (feeding, sleep, diaper)
  • Redux Slices

    • authSlice (login, logout, token refresh)
    • childrenSlice (CRUD operations)
    • activitiesSlice (create, update, delete)
    • offlineSlice (sync queue, conflict resolution)
  • API Clients

    • complianceApi (all methods)
    • authApi, childrenApi, trackingApi
  • Utilities

    • Date formatting
    • Age calculation
    • Token storage

Example Test Structure:

import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { DataExport } from '@/components/settings/DataExport';
import { complianceApi } from '@/lib/api/compliance';

jest.mock('@/lib/api/compliance');

describe('DataExport Component', () => {
  it('should download user data when button is clicked', async () => {
    const mockDownload = jest.fn();
    (complianceApi.downloadUserData as jest.Mock) = mockDownload;

    render(<DataExport />);

    const button = screen.getByText('Download My Data');
    fireEvent.click(button);

    await waitFor(() => {
      expect(mockDownload).toHaveBeenCalledTimes(1);
    });

    expect(screen.getByText('Your data has been downloaded successfully!')).toBeInTheDocument();
  });

  it('should show error message on download failure', async () => {
    (complianceApi.downloadUserData as jest.Mock).mockRejectedValue(
      new Error('Network error')
    );

    render(<DataExport />);
    fireEvent.click(screen.getByText('Download My Data'));

    await waitFor(() => {
      expect(screen.getByText(/Failed to export data/)).toBeInTheDocument();
    });
  });
});

2.2 Integration Tests (API Interaction)

What to Test:

  • Form submission with API calls
  • Authentication flows
  • Error handling and retry logic
  • Optimistic updates with Redux

3. End-to-End Tests (Target: 10% of tests)

Tools: Playwright

Critical User Journeys:

3.1 Registration & COPPA Compliance

test('User under 13 cannot register', async ({ page }) => {
  await page.goto('/register');
  await page.fill('[name="name"]', 'John Doe');
  await page.fill('[name="email"]', 'john@example.com');
  await page.fill('[name="dateOfBirth"]', '2015-01-01'); // 9 years old
  await page.fill('[name="password"]', 'SecurePass123');
  await page.fill('[name="confirmPassword"]', 'SecurePass123');
  await page.check('[name="agreeToTerms"]');
  await page.check('[name="agreeToPrivacy"]');

  await page.click('button[type="submit"]');

  await expect(page.locator('text=/Users under 13/')).toBeVisible();
});

test('User 13-17 requires parental consent', async ({ page }) => {
  await page.goto('/register');
  await page.fill('[name="dateOfBirth"]', '2010-01-01'); // 14 years old

  // Parental email field should appear
  await expect(page.locator('[name="parentalEmail"]')).toBeVisible();
  await expect(page.locator('text=/parental consent/')).toBeVisible();
});

3.2 Account Deletion Flow

test('User can request account deletion and cancel it', async ({ page }) => {
  // Login
  await login(page, 'user@example.com', 'password');

  // Navigate to settings
  await page.goto('/settings');

  // Request deletion
  await page.click('text=Delete My Account');
  await page.fill('[name="reason"]', 'Testing deletion flow');
  await page.click('button:has-text("Delete Account")');

  // Verify deletion scheduled
  await expect(page.locator('text=/Account deletion scheduled/')).toBeVisible();

  // Cancel deletion
  await page.click('text=Cancel Deletion Request');
  await page.click('button:has-text("Cancel Deletion")');

  // Verify cancellation
  await expect(page.locator('text=/cancelled successfully/')).toBeVisible();
});

3.3 Data Export Flow

test('User can export their data', async ({ page }) => {
  await login(page, 'user@example.com', 'password');
  await page.goto('/settings');

  const [download] = await Promise.all([
    page.waitForEvent('download'),
    page.click('text=Download My Data')
  ]);

  expect(download.suggestedFilename()).toMatch(/maternal-app-data-export.*\.json/);
});

3.4 Activity Tracking Flow

test('User can track feeding activity', async ({ page }) => {
  await login(page, 'user@example.com', 'password');
  await page.goto('/track/feeding');

  await page.selectOption('[name="childId"]', { index: 0 });
  await page.fill('[name="amount"]', '120');
  await page.selectOption('[name="unit"]', 'ml');
  await page.click('button:has-text("Save")');

  await expect(page.locator('text=/Activity saved/')).toBeVisible();

  // Verify on dashboard
  await page.goto('/');
  await expect(page.locator('text=/Feeding/')).toBeVisible();
});

4. Code Coverage Goals

4.1 Overall Targets

  • Total Coverage: 80%+
  • Statements: 80%+
  • Branches: 75%+
  • Functions: 80%+
  • Lines: 80%+

4.2 Module-Specific Targets

Backend:

  • Auth Module: 90%+ (critical security)
  • Compliance Module: 95%+ (legal requirement)
  • Tracking Module: 85%+
  • AI Module: 80%+
  • Voice Module: 80%+

Frontend:

  • Compliance Components: 95%+
  • Auth Components: 90%+
  • Tracking Components: 85%+
  • API Clients: 90%+
  • Redux Slices: 85%+

5. CI/CD Integration

5.1 GitHub Actions Workflow

Triggers:

  • Push to main branch
  • Pull request to main
  • Scheduled nightly runs

Steps:

  1. Checkout code
  2. Setup Node.js (v20)
  3. Install dependencies
  4. Run linter (ESLint)
  5. Run backend unit tests
  6. Run backend integration tests
  7. Run frontend tests
  8. Run E2E tests
  9. Generate coverage reports
  10. Upload coverage to Codecov
  11. Fail PR if coverage drops below 80%

Example .github/workflows/test.yml:

name: Test Suite

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  backend-tests:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: test
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test -- --coverage
      - uses: codecov/codecov-action@v3

  frontend-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npm ci
      - run: npm test -- --coverage

  e2e-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
      - run: npx playwright install --with-deps
      - run: npm run test:e2e

6. Test Data Management

6.1 Test Database

  • Use separate test database
  • Seed with test fixtures
  • Clean between tests

6.2 Test Fixtures

  • Create factory functions for test data
  • Predefined users, children, activities
  • COPPA-compliant test scenarios (various ages)

Example:

export const testUsers = {
  adult: {
    name: 'Adult User',
    email: 'adult@example.com',
    dateOfBirth: '1990-01-01',
  },
  minor14: {
    name: 'Teen User',
    email: 'teen@example.com',
    dateOfBirth: '2010-01-01',
    parentalEmail: 'parent@example.com',
    coppaConsentGiven: true,
  },
  child12: {
    name: 'Child User',
    email: 'child@example.com',
    dateOfBirth: '2012-01-01', // Should be blocked
  },
};

7. Testing Best Practices

7.1 General Principles

  • AAA Pattern: Arrange, Act, Assert
  • DRY: Don't Repeat Yourself (use factories and helpers)
  • Fast: Keep unit tests under 100ms
  • Isolated: No dependencies between tests
  • Deterministic: Same input = same output

7.2 Mocking Strategy

  • Mock external services (Azure OpenAI, Mailgun, MinIO)
  • Mock time-dependent functions
  • Use in-memory database for unit tests
  • Real database for integration tests

7.3 Naming Conventions

describe('ServiceName', () => {
  describe('methodName', () => {
    it('should do something when condition', () => {
      // Test
    });

    it('should throw error when invalid input', () => {
      // Test
    });
  });
});

8. Continuous Improvement

8.1 Metrics to Track

  • Code coverage percentage
  • Test execution time
  • Flaky test rate
  • Bug escape rate

8.2 Review Process

  • All PRs must have tests
  • Coverage must not decrease
  • CI must pass before merge

9. Implementation Timeline

Week 1:

  • Setup Jest for backend and frontend
  • Create first unit tests (Compliance, Auth)
  • Setup test database

Week 2:

  • Create integration tests for critical endpoints
  • Setup Playwright for E2E
  • Create E2E tests for COPPA flows

Week 3:

  • Expand coverage to 50%+
  • Setup CI/CD pipeline
  • Configure coverage reporting

Week 4:

  • Reach 80%+ coverage
  • Optimize test performance
  • Documentation and training

10. Quick Start Commands

# Backend
cd maternal-app-backend
npm test                    # Run all tests
npm test -- --coverage      # With coverage
npm test -- --watch         # Watch mode
npm run test:e2e            # Integration tests

# Frontend
cd maternal-web
npm test                    # Run all tests
npm test -- --coverage      # With coverage
npm test -- --watch         # Watch mode
npm run test:e2e            # E2E with Playwright

# Coverage Reports
npm test -- --coverage --coverageReporters=html
# Open coverage/index.html in browser

Status: IN PROGRESS

Current Coverage: 0% Target Coverage: 80%+ Estimated Completion: 3-4 weeks