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;