books/docs/architecture/testing-strategy.md
Greg fa8acef423 Epic 1, Story 1.1: Project Initialization & Repository Setup
- Initialize Git repository with main branch
- Create comprehensive .gitignore for Node.js, React, and environment files
- Set up directory structure (frontend/, backend/, docs/)
- Create detailed README.md with project overview and setup instructions
- Add .env.example with all required environment variables
- Configure Prettier for consistent code formatting

All acceptance criteria met:
 Git repository initialized with appropriate .gitignore
 Directory structure matches Technical Assumptions
 README.md created with project overview and setup docs
 .env.example file with all required environment variables
 Prettier config files added for code formatting consistency

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 15:12:30 +01:00

5.4 KiB

Testing Strategy

Testing Pyramid

        E2E Tests (Manual)
       /                  \
   Integration Tests (Backend)
  /                            \
Frontend Unit Tests    Backend Unit Tests

Coverage Targets:

  • Frontend: >70% for utils, services, business logic
  • Backend: >80% for controllers, services, business logic
  • Manual E2E: All critical user flows tested before deployment

Test Organization

Frontend Tests

frontend/tests/
├── components/
│   ├── BookCard.test.jsx
│   ├── LogProgressModal.test.jsx
│   └── StatusIndicator.test.jsx
├── utils/
│   ├── dateUtils.test.js
│   ├── paceUtils.test.js
│   └── validation.test.js
└── services/
    └── booksService.test.js

Backend Tests

backend/tests/
├── controllers/
│   ├── booksController.test.js
│   └── logsController.test.js
├── services/
│   ├── openLibraryService.test.js
│   └── paceCalculationService.test.js
└── integration/
    └── api.test.js

E2E Tests (Manual Checklist)

Manual E2E Test Checklist:
- [ ] Add book: Search → Select → Set deadline → Verify in list
- [ ] Log progress: Tap book → Enter page → Verify status updates
- [ ] View calendar: Navigate to book detail → See logged days
- [ ] Install PWA: "Add to Home Screen" → Launch from home screen
- [ ] Offline mode: Disable network → Log entry → Re-enable → Verify sync
- [ ] Mobile responsiveness: Test on iPhone and Android

Test Examples

Frontend Component Test

// tests/components/StatusIndicator.test.jsx
import { describe, it, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
import StatusIndicator from '../../src/components/progress/StatusIndicator';

describe('StatusIndicator', () => {
  it('displays green indicator for on-track status', () => {
    render(<StatusIndicator status="on-track" />);
    const indicator = screen.getByText(/on track/i);
    expect(indicator).toBeInTheDocument();
    expect(indicator).toHaveClass('text-green-600'); // Tailwind class
  });

  it('displays yellow indicator for slightly-behind status', () => {
    render(<StatusIndicator status="slightly-behind" />);
    const indicator = screen.getByText(/slightly behind/i);
    expect(indicator).toBeInTheDocument();
    expect(indicator).toHaveClass('text-yellow-600');
  });

  it('displays red indicator for behind status', () => {
    render(<StatusIndicator status="behind" />);
    const indicator = screen.getByText(/behind/i);
    expect(indicator).toBeInTheDocument();
    expect(indicator).toHaveClass('text-red-600');
  });
});

Backend API Test

// tests/controllers/booksController.test.js
const request = require('supertest');
const app = require('../../src/server');
const { PrismaClient } = require('@prisma/client');

const prisma = new PrismaClient();

describe('Books API', () => {
  beforeAll(async () => {
    // Setup test database
    await prisma.book.deleteMany();
  });

  afterAll(async () => {
    await prisma.$disconnect();
  });

  describe('POST /api/books', () => {
    it('creates a new book with valid data', async () => {
      const bookData = {
        title: 'The Name of the Wind',
        author: 'Patrick Rothfuss',
        totalPages: 662,
        deadlineDate: '2025-12-31',
      };

      const response = await request(app)
        .post('/api/books')
        .send(bookData)
        .expect(201);

      expect(response.body).toMatchObject({
        title: bookData.title,
        author: bookData.author,
        totalPages: bookData.totalPages,
        status: 'reading',
      });
      expect(response.body.id).toBeDefined();
    });

    it('returns 400 for invalid deadline (past date)', async () => {
      const bookData = {
        title: 'Test Book',
        totalPages: 300,
        deadlineDate: '2020-01-01', // Past date
      };

      const response = await request(app)
        .post('/api/books')
        .send(bookData)
        .expect(400);

      expect(response.body.error).toBe('Deadline must be in the future');
    });
  });

  describe('GET /api/books', () => {
    it('returns all active books with progress', async () => {
      // Create test book
      await prisma.book.create({
        data: {
          title: 'Test Book',
          totalPages: 300,
          deadlineDate: new Date('2025-12-31'),
        },
      });

      const response = await request(app)
        .get('/api/books')
        .expect(200);

      expect(response.body.books).toBeInstanceOf(Array);
      expect(response.body.books.length).toBeGreaterThan(0);
      expect(response.body.books[0]).toHaveProperty('requiredPace');
      expect(response.body.books[0]).toHaveProperty('status');
    });
  });
});

E2E Test (Manual)

Test Case: Add Book and Log Progress

Steps:

  1. Navigate to http://localhost:5173
  2. Click "Add Book" button
  3. Search for "Name of the Wind"
  4. Select first result
  5. Set deadline to 30 days from today
  6. Click "Add to Reading List"
  7. Verify book appears in list with status "on-track" or "unknown"
  8. Click "Log Progress" button
  9. Enter page number: 50
  10. Click "Save"
  11. Verify status updates to show required pace and actual pace

Expected Result:

  • Book added successfully
  • Progress logged successfully
  • Status indicator shows appropriate color
  • Pace calculations display correctly