- 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>
5.4 KiB
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:
- Navigate to http://localhost:5173
- Click "Add Book" button
- Search for "Name of the Wind"
- Select first result
- Set deadline to 30 days from today
- Click "Add to Reading List"
- Verify book appears in list with status "on-track" or "unknown"
- Click "Log Progress" button
- Enter page number: 50
- Click "Save"
- 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