Vitest — primeiros testes.
Instalação, primeiro arquivo .test.ts, describe, test, expect. Matchers mais usados (toBe, toEqual, toContain, toThrow).
Vitest é o framework de testes natural para projetos Vite. Ele reutiliza a mesma configuração — TypeScript, aliases, plugins — e oferece uma API idêntica à do Jest, com o benefício de ser significativamente mais rápido. Para o blog React com Vite e TypeScript, praticamente não há configuração adicional.
Instalação e configuração
npm install -D vitest {
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"test": "vitest",
"test:ui": "vitest --ui",
"coverage": "vitest run --coverage"
}
} Para a maioria dos projetos Vite + TypeScript, isso é suficiente. Vitest lê o vite.config.ts automaticamente. Se você precisar de configuração específica para testes (como o ambiente jsdom para componentes React), adicione uma seção test no vite.config.ts ou crie um vitest.config.ts separado:
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
export default defineConfig({
plugins: [react()],
test: {
environment: "jsdom", // simula o DOM do navegador
globals: true, // describe, test, expect sem import
setupFiles: ["./src/test/setup.ts"], // arquivo de setup global
},
}); import "@testing-library/jest-dom"; // matchers adicionais de DOM (opcional, para lição 7) Estrutura de um arquivo de teste
import { describe, it, expect } from "vitest";
import { formatarData, gerarSlug } from "./utils";
// describe agrupa testes relacionados — geralmente uma função ou módulo
describe("formatarData", () => {
// it (ou test) descreve um comportamento específico
it("retorna 'agora' para datas dos últimos 60 segundos", () => {
// Arrange — preparar o cenário
const agora = new Date();
// Act — executar
const resultado = formatarData(agora);
// Assert — verificar
expect(resultado).toBe("agora");
});
it("retorna data formatada para datas com mais de 7 dias", () => {
const dataAntiga = new Date("2024-01-15");
expect(formatarData(dataAntiga)).toBe("15 de jan. de 2024");
});
}); Convenções de nomes de arquivo:
utils.test.ts— junto ao arquivo testado (padrão mais comum)utils.spec.ts— equivalente, preferido em alguns projetos__tests__/utils.ts— em pasta separada (comum em projetos maiores)
Matchers essenciais
// .toBe() — igualdade estrita (===)
// Use para primitivos: strings, números, booleans
expect(2 + 2).toBe(4);
expect("slug-gerado").toBe("slug-gerado");
expect(true).toBe(true);
// .toEqual() — igualdade profunda de conteúdo
// Use para objetos e arrays — .toBe() falha com referências diferentes
expect([1, 2, 3]).toEqual([1, 2, 3]); // ✅
expect({ id: 1 }).toEqual({ id: 1 }); // ✅
expect([1, 2, 3]).toBe([1, 2, 3]); // ❌ referências diferentes
// .toBeTruthy() e .toBeFalsy()
// Para verificar truthiness sem checar o valor exato
expect("algum texto").toBeTruthy();
expect(null).toBeFalsy();
expect(0).toBeFalsy();
// .toContain() — verifica que array contém item ou string contém substring
expect(["css", "html", "js"]).toContain("css");
expect("Introdução ao React").toContain("React");
// .toHaveLength() — tamanho de array ou string
expect([1, 2, 3]).toHaveLength(3);
expect("abc").toHaveLength(3);
// .toBeNull() e .toBeUndefined()
expect(null).toBeNull();
expect(undefined).toBeUndefined();
// .toBeGreaterThan() e similares
expect(5).toBeGreaterThan(3);
expect(2).toBeLessThanOrEqual(2);
// .toThrow() — verifica que uma função lança erro
// Sempre passe a função como callback — não chame diretamente
expect(() => gerarSlug(null as any)).toThrow();
expect(() => dividir(10, 0)).toThrow("Divisão por zero"); Primeiro teste real — gerarSlug
import { describe, it, expect } from "vitest";
import { gerarSlug } from "./utils";
describe("gerarSlug", () => {
it("converte texto simples para slug", () => {
expect(gerarSlug("Introdução ao CSS")).toBe("introducao-ao-css");
});
it("converte para minúsculas", () => {
expect(gerarSlug("React e TypeScript")).toBe("react-e-typescript");
});
it("substitui espaços por hífens", () => {
expect(gerarSlug("como a web funciona")).toBe("como-a-web-funciona");
});
it("remove acentos e caracteres especiais", () => {
expect(gerarSlug("Flexbox: guia completo")).toBe("flexbox-guia-completo");
});
it("remove espaços extras nas bordas", () => {
expect(gerarSlug(" CSS Grid ")).toBe("css-grid");
});
it("retorna string vazia para entrada vazia", () => {
expect(gerarSlug("")).toBe("");
});
}); Rodando os testes
# rodar uma vez — para CI ou verificação rápida
npm test -- --run
# modo watch — re-roda quando arquivos mudam (padrão de desenvolvimento)
npm test
# filtrar por nome — rodar apenas testes com "slug" no nome
npm test -- --reporter=verbose gerarSlug
# relatório de cobertura
npm run coverage O output de uma suite passando:
✓ src/utils.test.ts (6)
✓ gerarSlug (6)
✓ converte texto simples para slug
✓ converte para minúsculas
✓ substitui espaços por hífens
✓ remove acentos e caracteres especiais
✓ remove espaços extras nas bordas
✓ retorna string vazia para entrada vazia
Test Files 1 passed (1)
Tests 6 passed (6)
Duration 187ms E quando um teste falha — a mensagem mostra exatamente o que era esperado e o que chegou:
FAIL src/utils.test.ts > gerarSlug > remove acentos e caracteres especiais
AssertionError: expected 'flexbox:-guia-completo' to be 'flexbox-guia-completo'
- Expected: "flexbox-guia-completo"
+ Received: "flexbox:-guia-completo" Resumo
- Instalação:
npm install -D vitest+ script"test": "vitest"nopackage.json. Para React, adicioneenvironment: "jsdom"na config. - Estrutura:
describeagrupa,it/testdescreve um comportamento,expectfaz a asserção. - Matchers essenciais:
.toBe()para igualdade estrita,.toEqual()para objetos/arrays,.toContain()para listas e strings,.toThrow()para erros esperados. npm testroda em modo watch — re-roda automaticamente ao salvar.npm test -- --runroda uma vez.- Mensagens de falha mostram o valor esperado vs. o recebido — fácil de diagnosticar.
Por que Vitest precisa de pouca configuração em projetos Vite?
Qual é a diferença entre .toBe() e .toEqual()?
O que o modo --watch do Vitest faz?
Como você testa que uma função lança um erro?
Aula concluída
Quase lá.