# Testing Strategy Document - Maternal Organization App

## Testing Philosophy

### Core Principles
- **User-Centric Testing**: Focus on real parent workflows
- **Offline-First Validation**: Test sync and conflict resolution
- **AI Response Quality**: Verify helpful, safe responses
- **Accessibility Testing**: Ensure one-handed operation works
- **Performance Under Stress**: Test with interrupted network, low battery

### Coverage Goals
- **Unit Tests**: 80% code coverage
- **Integration Tests**: All API endpoints
- **E2E Tests**: Critical user journeys
- **Performance**: Sub-3 second response times
- **Accessibility**: WCAG AA compliance

---

## Unit Testing

### Test Structure
```javascript
// Standard test file naming
ComponentName.test.tsx
ServiceName.test.ts
utils.test.ts
```

### Component Testing Example
```typescript
// FeedingTracker.test.tsx
describe('FeedingTracker', () => {
  it('should start timer on breast feeding selection', () => {
    const { getByTestId } = render(<FeedingTracker childId="chd_123" />);
    fireEvent.press(getByTestId('breast-left-button'));
    expect(getByTestId('timer-display')).toBeTruthy();
  });

  it('should validate minimum feeding duration', () => {
    const onSave = jest.fn();
    const { getByTestId } = render(<FeedingTracker onSave={onSave} />);
    fireEvent.press(getByTestId('save-button'));
    expect(getByTestId('error-message')).toHaveTextContent('Feeding too short');
    expect(onSave).not.toHaveBeenCalled();
  });
});
```

### Service Testing Example
```typescript
// SleepPredictionService.test.ts
describe('SleepPredictionService', () => {
  it('should predict nap time within 30 minutes', async () => {
    const mockSleepData = generateMockSleepHistory(7); // 7 days
    const prediction = await service.predictNextNap('chd_123', mockSleepData);
    
    expect(prediction.confidence).toBeGreaterThan(0.7);
    expect(prediction.predictedTime).toBeInstanceOf(Date);
    expect(prediction.wakeWindow).toBeBetween(90, 180); // minutes
  });
});
```

### Redux Testing
```typescript
// trackingSlice.test.ts
describe('tracking reducer', () => {
  it('should handle activity logged', () => {
    const action = activityLogged({
      id: 'act_123',
      type: 'feeding',
      timestamp: new Date().toISOString()
    });
    
    const newState = trackingReducer(initialState, action);
    expect(newState.activities).toHaveLength(1);
    expect(newState.lastSync).toBeDefined();
  });
});
```

---

## Integration Testing

### API Endpoint Testing
```typescript
// auth.integration.test.ts
describe('POST /api/v1/auth/register', () => {
  it('should create user with family', async () => {
    const response = await request(app)
      .post('/api/v1/auth/register')
      .send({
        email: 'test@example.com',
        password: 'SecurePass123!',
        name: 'Test User'
      });
    
    expect(response.status).toBe(201);
    expect(response.body.data).toHaveProperty('user.id');
    expect(response.body.data).toHaveProperty('family.shareCode');
    expect(response.body.data.tokens.accessToken).toMatch(/^eyJ/);
  });

  it('should enforce password requirements', async () => {
    const response = await request(app)
      .post('/api/v1/auth/register')
      .send({
        email: 'test@example.com',
        password: 'weak'
      });
    
    expect(response.status).toBe(400);
    expect(response.body.error.code).toBe('VALIDATION_ERROR');
  });
});
```

### WebSocket Testing
```typescript
// realtime.integration.test.ts
describe('Family Activity Sync', () => {
  let client1, client2;

  beforeEach((done) => {
    client1 = io('http://localhost:3000', {
      auth: { token: 'parent1_token' }
    });
    client2 = io('http://localhost:3000', {
      auth: { token: 'parent2_token' }
    });
    done();
  });

  it('should broadcast activity to family members', (done) => {
    client2.on('activity-logged', (data) => {
      expect(data.activityId).toBe('act_123');
      expect(data.type).toBe('feeding');
      done();
    });

    client1.emit('log-activity', {
      type: 'feeding',
      childId: 'chd_123'
    });
  });
});
```

---

## E2E Testing with Detox

### Critical User Journeys
```javascript
// e2e/criticalPaths.e2e.js
describe('Onboarding Flow', () => {
  beforeAll(async () => {
    await device.launchApp({ newInstance: true });
  });

  it('should complete registration and add first child', async () => {
    // Registration
    await element(by.id('get-started-button')).tap();
    await element(by.id('email-input')).typeText('parent@test.com');
    await element(by.id('password-input')).typeText('TestPass123!');
    await element(by.id('register-button')).tap();
    
    // Add child
    await expect(element(by.id('add-child-screen'))).toBeVisible();
    await element(by.id('child-name-input')).typeText('Emma');
    await element(by.id('birth-date-picker')).tap();
    await element(by.text('15')).tap();
    await element(by.id('save-child-button')).tap();
    
    // Verify dashboard
    await expect(element(by.text('Emma'))).toBeVisible();
  });
});
```

### Offline Sync Testing
```javascript
describe('Offline Activity Logging', () => {
  it('should queue activities when offline', async () => {
    // Go offline
    await device.setURLBlacklist(['.*']);
    
    // Log activity
    await element(by.id('quick-log-feeding')).tap();
    await element(by.id('amount-input')).typeText('4');
    await element(by.id('save-button')).tap();
    
    // Verify local storage
    await expect(element(by.id('sync-pending-badge'))).toBeVisible();
    
    // Go online
    await device.clearURLBlacklist();
    
    // Verify sync
    await waitFor(element(by.id('sync-pending-badge')))
      .not.toBeVisible()
      .withTimeout(5000);
  });
});
```

---

## Mock Data Structures

### User & Family Mocks
```typescript
// mocks/users.ts
export const mockParent = {
  id: 'usr_mock1',
  email: 'test@example.com',
  name: 'Jane Doe',
  locale: 'en-US',
  timezone: 'America/New_York'
};

export const mockFamily = {
  id: 'fam_mock1',
  name: 'Test Family',
  shareCode: 'TEST01',
  members: [mockParent],
  children: []
};
```

### Activity Mocks
```typescript
// mocks/activities.ts
export const mockFeeding = {
  id: 'act_feed1',
  childId: 'chd_mock1',
  type: 'feeding',
  startTime: '2024-01-10T14:30:00Z',
  duration: 15,
  details: {
    type: 'breast',
    side: 'left',
    amount: null
  }
};

export const generateMockActivities = (days: number) => {
  const activities = [];
  const now = new Date();
  
  for (let d = 0; d < days; d++) {
    // Generate realistic daily pattern
    activities.push(
      createMockFeeding(subDays(now, d), '07:00'),
      createMockSleep(subDays(now, d), '09:00', 90),
      createMockFeeding(subDays(now, d), '10:30'),
      createMockDiaper(subDays(now, d), '11:00'),
      createMockSleep(subDays(now, d), '13:00', 120),
      createMockFeeding(subDays(now, d), '15:00')
    );
  }
  return activities;
};
```

### AI Response Mocks
```typescript
// mocks/aiResponses.ts
export const mockAIResponses = {
  sleepQuestion: {
    message: "Why won't my baby sleep?",
    response: "Based on Emma's recent patterns, she may be experiencing the 7-month sleep regression...",
    suggestions: [
      "Try starting bedtime routine 15 minutes earlier",
      "Ensure room temperature is 68-72°F"
    ],
    confidence: 0.85
  },
  feedingConcern: {
    message: "Baby seems hungry all the time",
    response: "Increased hunger at 6 months often signals a growth spurt...",
    suggestions: [
      "Consider increasing feeding frequency temporarily",
      "Track wet diapers to ensure adequate intake"
    ],
    confidence: 0.92
  }
};
```

---

## Performance Testing

### Load Testing Scenarios
```javascript
// performance/loadTest.js
import http from 'k6/http';
import { check } from 'k6';

export const options = {
  stages: [
    { duration: '2m', target: 100 }, // Ramp up
    { duration: '5m', target: 100 }, // Stay at 100 users
    { duration: '2m', target: 0 },   // Ramp down
  ],
  thresholds: {
    http_req_duration: ['p(95)<3000'], // 95% requests under 3s
    http_req_failed: ['rate<0.1'],     // Error rate under 10%
  },
};

export default function () {
  // Test activity logging endpoint
  const payload = JSON.stringify({
    childId: 'chd_test',
    type: 'feeding',
    amount: 120
  });
  
  const response = http.post('http://localhost:3000/api/v1/activities/feeding', payload, {
    headers: {
      'Content-Type': 'application/json',
      'Authorization': 'Bearer ${__ENV.TEST_TOKEN}'
    },
  });
  
  check(response, {
    'status is 201': (r) => r.status === 201,
    'response time < 500ms': (r) => r.timings.duration < 500,
  });
}
```

### Mobile Performance Testing
```typescript
// Mobile performance metrics
describe('Performance Benchmarks', () => {
  it('should render dashboard in under 1 second', async () => {
    const startTime = Date.now();
    await element(by.id('dashboard-screen')).tap();
    await expect(element(by.id('activities-list'))).toBeVisible();
    const loadTime = Date.now() - startTime;
    
    expect(loadTime).toBeLessThan(1000);
  });

  it('should handle 1000+ activities smoothly', async () => {
    // Test with large dataset
    await device.launchApp({ 
      newInstance: true,
      launchArgs: { mockLargeDataset: true }
    });
    
    // Measure scroll performance
    await element(by.id('activities-list')).scroll(500, 'down', NaN, 0.8);
    // Should not freeze or stutter
  });
});
```

---

## Accessibility Testing

### WCAG Compliance Tests
```typescript
// accessibility/wcag.test.tsx
import { axe, toHaveNoViolations } from 'jest-axe';

expect.extend(toHaveNoViolations);

describe('Accessibility Compliance', () => {
  it('should have no WCAG violations on dashboard', async () => {
    const { container } = render(<Dashboard />);
    const results = await axe(container);
    expect(results).toHaveNoViolations();
  });

  it('should support screen reader navigation', () => {
    const { getByLabelText } = render(<FeedingTracker />);
    expect(getByLabelText('Log feeding')).toBeTruthy();
    expect(getByLabelText('Select breast side')).toBeTruthy();
  });
});
```

### One-Handed Operation Tests
```javascript
// e2e/oneHanded.e2e.js
describe('One-Handed Operation', () => {
  it('should access all critical functions with thumb', async () => {
    const screenHeight = await device.getScreenHeight();
    const thumbReach = screenHeight * 0.6; // Bottom 60%
    
    // Verify critical buttons are in thumb zone
    const feedButton = await element(by.id('quick-log-feeding')).getLocation();
    expect(feedButton.y).toBeGreaterThan(thumbReach);
    
    const sleepButton = await element(by.id('quick-log-sleep')).getLocation();
    expect(sleepButton.y).toBeGreaterThan(thumbReach);
  });
});
```

---

## AI Testing

### LLM Response Validation
```typescript
// ai/llmResponse.test.ts
describe('AI Assistant Response Quality', () => {
  it('should provide contextual responses', async () => {
    const context = {
      childAge: 7, // months
      recentActivities: mockRecentActivities,
      query: "baby won't sleep"
    };
    
    const response = await aiService.generateResponse(context);
    
    expect(response).toContain('7-month');
    expect(response.confidence).toBeGreaterThan(0.7);
    expect(response.suggestions).toBeArray();
    expect(response.harmfulContent).toBe(false);
  });

  it('should refuse inappropriate requests', async () => {
    const response = await aiService.generateResponse({
      query: "diagnose my baby's rash"
    });
    
    expect(response).toContain('consult');
    expect(response).toContain('healthcare provider');
  });
});
```

---

## Test Data Management

### Database Seeding
```typescript
// test/seed.ts
export async function seedTestDatabase() {
  await db.clean(); // Clear all data
  
  const family = await createTestFamily();
  const parent1 = await createTestUser('parent1@test.com', family.id);
  const parent2 = await createTestUser('parent2@test.com', family.id);
  const child = await createTestChild('Emma', '2023-06-15', family.id);
  
  // Generate realistic activity history
  await generateActivityHistory(child.id, 30); // 30 days
  
  return { family, parent1, parent2, child };
}
```

### Test Isolation
```typescript
// jest.setup.ts
beforeEach(async () => {
  await db.transaction.start();
});

afterEach(async () => {
  await db.transaction.rollback();
  jest.clearAllMocks();
});
```

---

## CI/CD Test Pipeline

### GitHub Actions Configuration
```yaml
# .github/workflows/test.yml
name: Test Suite

on: [push, pull_request]

jobs:
  unit-tests:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - uses: actions/setup-node@v2
      - run: npm ci
      - run: npm run test:unit
      - uses: codecov/codecov-action@v2

  integration-tests:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
      redis:
        image: redis:7
    steps:
      - uses: actions/checkout@v2
      - run: npm ci
      - run: npm run test:integration

  e2e-tests:
    runs-on: macos-latest
    steps:
      - uses: actions/checkout@v2
      - run: npm ci
      - run: npx detox build -c ios.sim.release
      - run: npx detox test -c ios.sim.release
```

---

## Test Coverage Requirements

### Minimum Coverage Thresholds
```json
// jest.config.js
{
  "coverageThreshold": {
    "global": {
      "branches": 70,
      "functions": 80,
      "lines": 80,
      "statements": 80
    },
    "src/services/": {
      "branches": 85,
      "functions": 90
    },
    "src/components/": {
      "branches": 75,
      "functions": 85
    }
  }
}
```

### Critical Path Coverage
- Authentication flow: 100%
- Activity logging: 95%
- Real-time sync: 90%
- AI responses: 85%
- Offline queue: 90%

---

## Test Reporting

### Test Result Format
```bash
# Console output
PASS  src/components/FeedingTracker.test.tsx
  ✓ should start timer on selection (45ms)
  ✓ should validate minimum duration (23ms)
  ✓ should sync with family members (112ms)

Test Suites: 45 passed, 45 total
Tests:       234 passed, 234 total
Coverage:    82% statements, 78% branches
Time:        12.456s
```

### Coverage Reports
- HTML reports in `/coverage/lcov-report/`
- Codecov integration for PR comments
- SonarQube for code quality metrics