087
LVL 04 — SENIOR-IN-TRAININGSESSION 087DAY 87

AUTOMATED TESTING

🎫 PIXELCRAFT-073
Feature | 🟠 Hard | Priority: 🔴 Critical

Every deploy is a gamble. A filter fix broke the upload flow last week. Nobody caught it until users complained. Write automated tests. Unit tests for logic, integration tests for API, component tests for React. npm test catches regressions before they ship.
CONCEPTS.UNLOCKED
🧪
Unit Testing (Vitest)
Test individual functions in isolation. Does applySepia() produce the right pixel values? Does generateFilename() handle edge cases? Fast, focused, hundreds of them.
🔗
Integration Testing
Test how pieces work together. Does POST /api/images/upload actually save to the database and enqueue a job? Test the real API with a real (test) database.
🖥️
Component Testing
Test React components with React Testing Library. Render the component, simulate user interactions, assert what's on screen. Test behavior, not implementation details.
🎭
Mocking
Replace real dependencies with fakes. Mock the database, mock the email service, mock Redis. Unit tests shouldn't need a running database — mock it and test the logic.
📐
The Test Pyramid
Many unit tests, some integration, few E2E. Unit tests are fast and cheap. E2E tests are slow and expensive. The pyramid shape gives maximum coverage with minimum cost.
🔌
Supertest
Test Express routes without starting the server. Send HTTP requests programmatically, assert status codes and response bodies. The standard for Node.js API testing.
HANDS-ON.TASKS
01
Set Up Vitest
npm install -D vitest @testing-library/react npm install -D @testing-library/jest-dom npm install -D supertest // package.json { "scripts": { "test": "vitest", "test:run": "vitest run", "test:coverage": "vitest --coverage" } }
02
Unit Tests: Pure Functions
// __tests__/filters.test.js import { describe, it, expect } from 'vitest'; import { applyColorMatrix, SEPIA_MATRIX } from '../src/filters'; describe('applyColorMatrix', () => { it('applies sepia to white pixel', () => { const data = new Uint8ClampedArray( [255, 255, 255, 255]); const imageData = { data, width: 1, height: 1 }; applyColorMatrix( imageData, SEPIA_MATRIX); // Sepia tints white → warm beige expect(data[0]).toBeGreaterThan(200); expect(data[2]).toBeLessThan(200); }); it('preserves alpha channel', () => { const data = new Uint8ClampedArray( [100, 100, 100, 128]); const imageData = { data, width: 1, height: 1 }; applyColorMatrix( imageData, SEPIA_MATRIX); expect(data[3]).toBe(128); }); }); describe('generateFilename', () => { it('adds timestamp prefix', () => { const name = generateFilename('photo.jpg'); expect(name).toMatch( /^\d{13}-photo\.jpg$/); }); it('sanitizes special characters', () => { const name = generateFilename( '../hack/../../etc/passwd'); expect(name).not.toContain('..'); expect(name).not.toContain('/'); }); });
03
Integration Tests: API Endpoints
// __tests__/api/auth.test.js import { describe, it, expect, beforeAll, afterAll } from 'vitest'; import request from 'supertest'; import { app } from '../server/app'; describe('POST /api/v1/auth/register', () => { it('creates user with valid input', async () => { const res = await request(app) .post('/api/v1/auth/register') .send({ email: 'test@example.com', password: 'SecurePass1', name: 'Test User', }); expect(res.status).toBe(201); expect(res.body.token) .toBeDefined(); expect(res.body.user.email) .toBe('test@example.com'); }); it('rejects invalid email', async () => { const res = await request(app) .post('/api/v1/auth/register') .send({ email: 'not-an-email', password: 'SecurePass1', name: 'Test', }); expect(res.status).toBe(400); expect(res.body.details[0].field) .toBe('email'); }); it('rejects duplicate email', async () => { // Register once await request(app) .post('/api/v1/auth/register') .send({ email: 'dupe@example.com', password: 'SecurePass1', name: 'First', }); // Try again const res = await request(app) .post('/api/v1/auth/register') .send({ email: 'dupe@example.com', password: 'SecurePass1', name: 'Second', }); expect(res.status).toBe(409); }); });
04
Component Tests: React Testing Library
// __tests__/components/FilterPicker.test.jsx import { render, screen, fireEvent } from '@testing-library/react'; import { FilterPicker } from '../src/components/FilterPicker'; describe('FilterPicker', () => { it('renders all filter options', () => { render(<FilterPicker onSelect={() => {}} />); expect(screen.getByText('Sepia')) .toBeInTheDocument(); expect(screen.getByText('Grayscale')) .toBeInTheDocument(); expect(screen.getByText('Sharpen')) .toBeInTheDocument(); }); it('calls onSelect when clicked', () => { const handleSelect = vi.fn(); render(<FilterPicker onSelect={handleSelect} />); fireEvent.click( screen.getByText('Sepia')); expect(handleSelect) .toHaveBeenCalledWith('sepia'); }); it('highlights active filter', () => { render(<FilterPicker active="sepia" onSelect={() => {}} />); const btn = screen.getByText('Sepia'); expect(btn.className) .toContain('active'); }); });
05
Close the Ticket
git switch -c feature/PIXELCRAFT-073-testing git add __tests__/ vitest.config.js git commit -m "Add unit, integration, component tests (PIXELCRAFT-073)" git push origin feature/PIXELCRAFT-073-testing # PR → Review → Merge → Close ticket ✅
CS.DEEP-DIVE

Tests are the only way to refactor with confidence.

Without tests, every change is a risk. With tests, you can restructure the entire codebase and know nothing broke — in seconds.

// The Test Pyramid:

       /\
      / \   E2E (few, slow)
     / \
    /------\  Integration (some)
   / \
  /----------\ Unit (many, fast)
 /____________\

// What to test:
Unit: pure functions, utils, filters
Integration: API routes, DB queries
Component: React behavior, user flows
E2E: critical paths (login, upload)

// "Write tests. Not too many.
// Mostly integration." — Kent C. Dodds
"Testing Lab"
[A]Add test coverage reporting: vitest --coverage. Identify untested code paths. Aim for 80%+ on critical modules (auth, filters, upload). Don't chase 100% — test what matters.
[B]Add snapshot testing for the undo system: save editor state, perform actions, undo, assert state matches the snapshot. Catch regressions in complex state management.
[C]Research: TDD (Test-Driven Development) vs BDD (Behavior-Driven Development). Try writing a new feature test-first: write the test, watch it fail, implement, watch it pass. Compare the experience.
REF.MATERIAL
ARTICLE
Vitest Team
Blazing fast unit testing powered by Vite. Jest-compatible API, ESM native, watch mode, coverage. The modern testing framework for JavaScript.
VITESTOFFICIALESSENTIAL
ARTICLE
Kent C. Dodds
Test React components the way users use them. Query by text, role, and label — not implementation details. The standard for React testing.
RTLOFFICIALESSENTIAL
VIDEO
Fireship
Quick overview of testing types: unit, integration, E2E, and the test pyramid. Why testing matters and how to start.
TESTINGQUICK
ARTICLE
Kent C. Dodds
"Write tests. Not too many. Mostly integration." The philosophy behind effective testing — focus on confidence, not coverage numbers.
TESTINGPHILOSOPHY
ARTICLE
ladjs
HTTP assertion library for Node.js. Test Express routes without starting the server. The standard API testing tool for Node.js.
SUPERTESTAPI
// LEAVE EXCITED BECAUSE
Run npm test42 tests pass in 1.3 seconds. Filters, API routes, React components — all verified automatically. Change any code → tests catch if you broke something. Deploy with confidence.