Files
maternal-app/docs/implementation-docs/TESTING_STRATEGY.md
Andrei 8ae42ffc75
Some checks failed
ParentFlow CI/CD Pipeline / Backend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Frontend Tests (push) Has been cancelled
ParentFlow CI/CD Pipeline / Security Scanning (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-app/maternal-app-backend dockerfile:Dockerfile.production name:backend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Build Docker Images (map[context:maternal-web dockerfile:Dockerfile.production name:frontend]) (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Development (push) Has been cancelled
ParentFlow CI/CD Pipeline / Deploy to Production (push) Has been cancelled
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
chore: Remove production Docker infrastructure and reorganize docs
- Remove production Docker Compose files (docker-compose.production.yml, docker-compose.prod-simple.yml)
- Remove production Dockerfiles (backend and frontend)
- Move implementation docs to docs/implementation-docs/ directory
- Remove test scripts (test-embeddings.js, test-voice-*.js/sh)
- Update ecosystem.config.js with production environment variables (CORS, JWT secrets, database config)
- Add database connection pooling configuration
- Update CORS configuration for production domains (parentflowapp.com)
- Fix frontend dev server port configuration (3005)
- Add PWA web push implementation plan documentation
- Simplify health check endpoints (remove MongoDB/Redis specific checks)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-06 21:03:11 +00:00

527 lines
13 KiB
Markdown

# 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:**
```typescript
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:**
```typescript
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:**
```typescript
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
```typescript
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
```typescript
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
```typescript
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
```typescript
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`:**
```yaml
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:**
```typescript
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
```typescript
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
```bash
# 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