import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import request from 'supertest';
// ============================================
// Unit Test Examples
// ============================================
// Math Utilities Tests
describe('Math Utilities', () => {
describe('add', () => {
it('adds two positive numbers', () => {
expect(add(2, 3)).toBe(5);
});
it('adds negative numbers', () => {
expect(add(-1, -1)).toBe(-2);
});
it('handles zero', () => {
expect(add(0, 5)).toBe(5);
});
});
describe('divide', () => {
it('divides two numbers', () => {
expect(divide(10, 2)).toBe(5);
});
it('throws error on division by zero', () => {
expect(() => divide(10, 0)).toThrow('Cannot divide by zero');
});
});
});
// Async Function Tests
describe('Async Operations', () => {
it('fetches data successfully', async () => {
const result = await fetchData('123');
expect(result).toHaveProperty('id', '123');
});
it('handles errors gracefully', async () => {
await expect(fetchData('invalid')).rejects.toThrow('Not found');
});
});
// ============================================
// Mock Examples
// ============================================
describe('User Service with Mocks', () => {
const mockUserRepo = {
findById: vi.fn(),
create: vi.fn(),
update: vi.fn(),
delete: vi.fn(),
};
beforeEach(() => {
vi.clearAllMocks();
});
it('finds user by id', async () => {
const mockUser = { id: 1, name: 'John' };
mockUserRepo.findById.mockResolvedValue(mockUser);
const userService = new UserService(mockUserRepo);
const result = await userService.getUser(1);
expect(mockUserRepo.findById).toHaveBeenCalledWith(1);
expect(result).toEqual(mockUser);
});
it('creates user with hashed password', async () => {
const input = { email: 'test@example.com', password: 'secret123' };
mockUserRepo.create.mockResolvedValue({ id: 1, email: input.email });
const userService = new UserService(mockUserRepo);
const result = await userService.createUser(input);
expect(mockUserRepo.create).toHaveBeenCalled();
expect(result.email).toBe(input.email);
expect(mockUserRepo.create.mock.calls[0][0].password).not.toBe(input.password);
});
});
// ============================================
// Integration Test Examples
// ============================================
describe('API Integration Tests', () => {
let app: Express;
beforeEach(async () => {
app = createApp();
await setupTestDatabase();
});
afterEach(async () => {
await cleanupTestDatabase();
});
describe('POST /api/users', () => {
it('creates a new user', async () => {
const response = await request(app)
.post('/api/users')
.send({
email: 'new@example.com',
name: 'New User',
password: 'password123',
})
.expect(201);
expect(response.body.success).toBe(true);
expect(response.body.data).toHaveProperty('id');
expect(response.body.data.email).toBe('new@example.com');
});
it('rejects duplicate email', async () => {
// Create first user
await request(app)
.post('/api/users')
.send({ email: 'test@example.com', name: 'Test', password: 'pass' });
// Try to create duplicate
const response = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', name: 'Test2', password: 'pass' })
.expect(400);
expect(response.body.error).toContain('already exists');
});
it('validates required fields', async () => {
const response = await request(app)
.post('/api/users')
.send({ email: 'test@example.com' })
.expect(400);
expect(response.body.error).toBeDefined();
});
});
describe('GET /api/users/:id', () => {
it('returns user by id', async () => {
const createRes = await request(app)
.post('/api/users')
.send({ email: 'test@example.com', name: 'Test', password: 'pass' });
const response = await request(app)
.get(`/api/users/${createRes.body.data.id}`)
.expect(200);
expect(response.body.data.email).toBe('test@example.com');
});
it('returns 404 for non-existent user', async () => {
await request(app)
.get('/api/users/99999')
.expect(404);
});
});
});
// ============================================
// E2E Test Examples
// ============================================
describe('Authentication Flow E2E', () => {
let app: Express;
let authToken: string;
beforeAll(async () => {
app = createApp();
await setupTestDatabase();
});
afterAll(async () => {
await cleanupTestDatabase();
});
it('registers a new user', async () => {
const response = await request(app)
.post('/api/auth/register')
.send({
email: 'e2e@example.com',
name: 'E2E User',
password: 'securePassword123',
})
.expect(201);
expect(response.body.user.email).toBe('e2e@example.com');
});
it('logs in with credentials', async () => {
const response = await request(app)
.post('/api/auth/login')
.send({
email: 'e2e@example.com',
password: 'securePassword123',
})
.expect(200);
expect(response.body.token).toBeDefined();
authToken = response.body.token;
});
it('accesses protected route with token', async () => {
const response = await request(app)
.get('/api/profile')
.set('Authorization', `Bearer ${authToken}`)
.expect(200);
expect(response.body.email).toBe('e2e@example.com');
});
it('rejects access without token', async () => {
await request(app)
.get('/api/profile')
.expect(401);
});
});
// ============================================
// Test Utilities
// ============================================
export function createTestUser(overrides = {}) {
return {
email: `test-${Date.now()}@example.com`,
name: 'Test User',
password: 'testPassword123',
...overrides,
};
}
export async function authenticateAs(app: Express, role: 'user' | 'admin' = 'user') {
const user = createTestUser({ role });
await request(app).post('/api/auth/register').send(user);
const response = await request(app)
.post('/api/auth/login')
.send({ email: user.email, password: user.password });
return response.body.token;
}
// Stubs for examples (would be real implementations)
function add(a: number, b: number) { return a + b; }
function divide(a: number, b: number) { if (b === 0) throw new Error('Cannot divide by zero'); return a / b; }
async function fetchData(id: string) { if (id === 'invalid') throw new Error('Not found'); return { id }; }
class UserService { constructor(private repo: any) { } async getUser(id: number) { return this.repo.findById(id); } async createUser(data: any) { return this.repo.create({ ...data, password: 'hashed' }); } }
function createApp(): any { return {}; }
async function setupTestDatabase() { }
async function cleanupTestDatabase() { }
type Express = any;