Domine o test runner mais rápido do JavaScript, sem configuração
O Bun inclui um test runner nativo que elimina a necessidade de Jest, Vitest ou outras ferramentas de teste.
// src/utils/calculator.ts
export function add(a: number, b: number): number {
return a + b;
}
export function multiply(a: number, b: number): number {
return a * b;
}
export function divide(a: number, b: number): number {
if (b === 0) {
throw new Error("Divisão por zero não é permitida");
}
return a / b;
}
export function isEven(num: number): boolean {
return num % 2 === 0;
}// src/utils/calculator.test.ts
import { test, expect, describe } from "bun:test";
import { add, multiply, divide, isEven } from "./calculator";
describe("Calculator", () => {
test("should add two numbers", () => {
expect(add(2, 3)).toBe(5);
expect(add(-1, 1)).toBe(0);
expect(add(0, 0)).toBe(0);
});
test("should multiply two numbers", () => {
expect(multiply(3, 4)).toBe(12);
expect(multiply(-2, 3)).toBe(-6);
expect(multiply(0, 5)).toBe(0);
});
test("should divide two numbers", () => {
expect(divide(10, 2)).toBe(5);
expect(divide(7, 2)).toBe(3.5);
});
test("should throw error when dividing by zero", () => {
expect(() => divide(5, 0)).toThrow("Divisão por zero não é permitida");
});
test("should check if number is even", () => {
expect(isEven(4)).toBe(true);
expect(isEven(3)).toBe(false);
expect(isEven(0)).toBe(true);
});
});bun testO Bun test runner é compatível com a API do Jest, incluindo todos os matchers principais:
expect(value).toBe(expected) expect(value).toEqual(expected) expect(value).toBeNull() expect(value).toBeUndefined() expect(value).toBeTruthy() expect(value).toBeFalsy() expect(value).toBeGreaterThan(3) expect(value).toBeCloseTo(0.3)
expect(array).toContain(item)
expect(string).toMatch(/pattern/)
expect(fn).toThrow()
expect(fn).toThrow("message")
expect(object).toHaveProperty("key")
expect(array).toHaveLength(3)// src/services/api.ts
export async function fetchUser(id: number) {
// Simula uma chamada de API
await new Promise(resolve => setTimeout(resolve, 100));
if (id <= 0) {
throw new Error("ID inválido");
}
return {
id,
name: `User ${id}`,
email: `user${id}@example.com`
};
export default
}
export async function fetchUsers(): Promise<any[]> {
await new Promise(resolve => setTimeout(resolve, 200));
return [
{ id: 1, name: "João" },
{ id: 2, name: "Maria" }
];
}// src/services/api.test.ts
import { test, expect, describe } from "bun:test";
import { fetchUser, fetchUsers } from "./api";
describe("API Service", () => {
test("should fetch user by id", async () => {
const user = await fetchUser(1);
expect(user).toEqual({
id: 1,
name: "User 1",
email: "user1@example.com"
});
});
test("should throw error for invalid id", async () => {
await expect(fetchUser(-1)).rejects.toThrow("ID inválido");
});
test("should fetch all users", async () => {
const users = await fetchUsers();
expect(users).toHaveLength(2);
expect(users[0]).toHaveProperty("name", "João");
});
});// src/services/database.test.ts
import { test, expect, mock, spyOn } from "bun:test";
// Mock de uma função
const mockFetch = mock(() => Promise.resolve({
json: () => Promise.resolve({ data: "test" })
}));
test("should mock fetch", async () => {
// @ts-ignore
global.fetch = mockFetch;
const response = await fetch("/api/test");
const data = await response.json();
expect(data).toEqual({ data: "test" });
expect(mockFetch).toHaveBeenCalledTimes(1);
});
// Spy em métodos
test("should spy on console.log", () => {
const spy = spyOn(console, "log");
console.log("Hello, World!");
expect(spy).toHaveBeenCalledWith("Hello, World!");
spy.mockRestore();
});# bunfig.toml
[test]
# Timeout padrão para testes (em ms)
timeout = 5000
# Executar testes em paralelo
parallel = true
# Padrão de arquivos de teste
testMatch = ["**/*.test.{js,ts,tsx,jsx}"]
# Setup file (executado antes de cada teste)
setupFiles = ["./test-setup.ts"]// test-setup.ts
import { beforeAll, afterAll } from "bun:test";
// Configuração global antes de todos os testes
beforeAll(() => {
console.log("🧪 Iniciando testes...");
// Configurar variáveis de ambiente para teste
process.env.NODE_ENV = "test";
process.env.DATABASE_URL = "sqlite://test.db";
});
// Limpeza após todos os testes
afterAll(() => {
console.log("✅ Testes finalizados!");
});bun test - Executa todos os testesbun test --watch - Modo watch (re-executa ao salvar)bun test calculator.test.ts - Executa arquivo específicobun test --timeout 10000 - Define timeout personalizadobun test --bail - Para no primeiro erroVamos criar testes para funções do nosso projeto Restaurantix:
validateEmail(email: string)calculateOrderTotal(items: OrderItem[])bun test --watch// src/utils/validation.ts
export function validateEmail(email: string): boolean {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return emailRegex.test(email);
}
export interface OrderItem {
name: string;
price: number;
quantity: number;
}
export function calculateOrderTotal(items: OrderItem[]): number {
return items.reduce((total, item) => {
return total + (item.price * item.quantity);
}, 0);
}
// src/utils/validation.test.ts
import { test, expect, describe } from "bun:test";
import { validateEmail, calculateOrderTotal } from "./validation";
describe("Validation Utils", () => {
test("should validate email correctly", () => {
expect(validateEmail("test@example.com")).toBe(true);
expect(validateEmail("invalid-email")).toBe(false);
expect(validateEmail("")).toBe(false);
});
test("should calculate order total", () => {
const items = [
{ name: "Pizza", price: 25.90, quantity: 2 },
{ name: "Refrigerante", price: 5.50, quantity: 1 }
];
expect(calculateOrderTotal(items)).toBe(57.30);
expect(calculateOrderTotal([])).toBe(0);
});
});