<h2>Introdução aos Frameworks de Teste em JavaScript</h2>
<p>Testes automatizados são a base de software confiável e manutenível. Em JavaScript, você tem três ferramentas principais: Jest (robusto e completo), Vitest (moderno e rápido), e Testing Library (focado em comportamento do usuário). Cada uma resolve problemas específicos, e dominá-las é essencial para qualquer desenvolvedor profissional.</p>
<p>A escolha entre elas depende do seu contexto. Jest é ideal para projetos estabelecidos; Vitest excele em aplicações Vite modernas; Testing Library complementa ambos quando você precisa testar interfaces de usuário. Neste artigo, você aprenderá configuração, padrões práticos e como usá-las em conjunto.</p>
<h2>Jest: A Base Sólida</h2>
<h3>Configuração e Setup</h3>
<p>Jest é o framework de testes mais usado em JavaScript. Sua configuração é mínima graças aos padrões inteligentes. Instale com <code>npm install --save-dev jest</code> e crie um arquivo <code>jest.config.js</code>:</p>
<pre><code class="language-javascript">module.exports = {
testEnvironment: 'node',
collectCoverageFrom: ['src/*/.js'],
coveragePathIgnorePatterns: ['/node_modules/'],
testMatch: ['/__tests__//*.test.js']
};</code></pre>
<h3>Escrevendo Testes Básicos</h3>
<p>Vamos testar uma função simples de cálculo. Crie <code>src/calculator.js</code>:</p>
<pre><code class="language-javascript">function soma(a, b) {
return a + b;
}
function multiplicacao(a, b) {
return a * b;
}
module.exports = { soma, multiplicacao };</code></pre>
<p>Agora <code>src/__tests__/calculator.test.js</code>:</p>
<pre><code class="language-javascript">const { soma, multiplicacao } = require('../calculator');
describe('Calculator', () => {
it('deve somar dois números corretamente', () => {
expect(soma(2, 3)).toBe(5);
});
it('deve multiplicar dois números corretamente', () => {
expect(multiplicacao(4, 5)).toBe(20);
});
it('deve retornar 0 para soma com valores negativos', () => {
expect(soma(-5, 5)).toBe(0);
});
});</code></pre>
<p>Execute com <code>npm test</code>. Jest fornece assertions claras (<code>toBe</code>, <code>toEqual</code>, <code>toMatch</code>), setup/teardown com <code>beforeEach</code> e <code>afterEach</code>, e relatórios de cobertura automaticamente. Para testes mais avançados, use mocks: <code>jest.fn()</code> para funções e <code>jest.mock()</code> para módulos inteiros.</p>
<h2>Vitest: Performance e Modernidade</h2>
<h3>Por Que Vitest?</h3>
<p>Vitest é construído sobre Vite e oferece reload instantâneo (HMR) e execução paralela nativa. É perfeito se você já usa Vite. A API é compatível com Jest, facilitando a migração.</p>
<h3>Primeiros Passos</h3>
<p>Instale: <code>npm install --save-dev vitest</code>. Crie <code>vitest.config.js</code>:</p>
<pre><code class="language-javascript">import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
coverage: {
provider: 'v8'
}
}
});</code></pre>
<p>Teste o mesmo calculator com Vitest em <code>src/__tests__/calculator.vitest.js</code>:</p>
<pre><code class="language-javascript">import { describe, it, expect } from 'vitest';
import { soma, multiplicacao } from '../calculator';
describe('Calculator com Vitest', () => {
it('soma dois números', () => {
expect(soma(10, 20)).toBe(30);
});
it('trata erros de entrada', () => {
expect(() => soma(null, 5)).toBeDefined();
});
});</code></pre>
<p>Execute com <code>npm run test -- vitest</code>. A diferença prática: Vitest reconstrói testes modificados em milissegundos, não segundos. Para projetos grandes, isso muda a experiência de desenvolvimento significativamente.</p>
<h2>Testing Library: Testando Como Usuários</h2>
<h3>Filosofia de Teste</h3>
<p>Testing Library não testa implementação, testa comportamento. Você evita selecionar por <code>className</code> ou <code>data-testid</code> desnecessários, focando em como usuários realmente interagem: clicam em botões, preenchem campos, leem texto.</p>
<h3>Testando Componentes React</h3>
<p>Instale: <code>npm install --save-dev @testing-library/react @testing-library/jest-dom</code>. Crie um componente simples <code>src/components/LoginForm.jsx</code>:</p>
<pre><code class="language-javascript">import { useState } from 'react';
export function LoginForm({ onSubmit }) {
const [email, setEmail] = useState('');
return (
<form onSubmit={(e) => {
e.preventDefault();
onSubmit(email);
}}>
<label htmlFor="email">Email</label>
<input
id="email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
/>
<button type="submit">Entrar</button>
</form>
);
}</code></pre>
<p>Teste com <code>src/__tests__/LoginForm.test.jsx</code>:</p>
<pre><code class="language-javascript">import { render, screen, fireEvent } from '@testing-library/react';
import { LoginForm } from '../components/LoginForm';
describe('LoginForm', () => {
it('chama onSubmit quando formulário é enviado', () => {
const handleSubmit = jest.fn();
render(<LoginForm onSubmit={handleSubmit} />);
const input = screen.getByLabelText('Email');
const button = screen.getByRole('button', { name: /entrar/i });
fireEvent.change(input, { target: { value: 'test@example.com' } });
fireEvent.click(button);
expect(handleSubmit).toHaveBeenCalledWith('test@example.com');
});
it('exibe label corretamente', () => {
render(<LoginForm onSubmit={() => {}} />);
expect(screen.getByLabelText('Email')).toBeInTheDocument();
});
});</code></pre>
<p>Use <code>getByRole</code> e <code>getByLabelText</code> (acessíveis a usuários) em vez de <code>getByTestId</code>. Isso garante que sua aplicação é usável por todos e força boas práticas de acessibilidade.</p>
<h2>Integrando as Três Ferramentas</h2>
<p>Na prática profissional, você usa todas juntas. Jest para lógica de negócio pura, Vitest para performance em desenvolvimento, Testing Library para UI. Um padrão comum:</p>
<pre><code class="language-javascript">// src/__tests__/integration.test.js
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { App } from '../App';
describe('Fluxo completo de usuário', () => {
it('usuário faz login e acessa dashboard', async () => {
render(<App />);
const user = userEvent.setup();
const emailInput = screen.getByLabelText('Email');
await user.type(emailInput, 'user@test.com');
await user.click(screen.getByRole('button', { name: /entrar/i }));
await waitFor(() => {
expect(screen.getByText(/bem-vindo/i)).toBeInTheDocument();
});
});
});</code></pre>
<p>Use <code>userEvent</code> (simulação mais realista que <code>fireEvent</code>) e <code>waitFor</code> para operações assíncronas. Adicione coverage: <code>jest --coverage</code> gera relatórios HTML detalhados.</p>
<h2>Conclusão</h2>
<p>Dominar testes em JavaScript exige entender quando usar cada ferramenta. <strong>Primeiro aprendizado:</strong> Jest fornece a base sólida com API simples e integração perfeita com qualquer projeto. <strong>Segundo:</strong> Vitest moderniza a experiência com HMR e performance, ideal para workflows de desenvolvimento intensivo. <strong>Terceiro:</strong> Testing Library muda seu mindset, forçando código mais acessível e testável focando em comportamento, não implementação. A combinação desses conhecimentos transforma você de quem escreve testes em quem escreve código testável desde o início.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://jestjs.io/docs/getting-started" target="_blank" rel="noopener noreferrer">Jest Documentation</a></li>
<li><a href="https://vitest.dev/guide/" target="_blank" rel="noopener noreferrer">Vitest Guide</a></li>
<li><a href="https://testing-library.com/docs/queries/about" target="_blank" rel="noopener noreferrer">Testing Library Best Practices</a></li>
<li><a href="https://kentcdodds.com/blog/common-mistakes-with-react-testing-library" target="_blank" rel="noopener noreferrer">React Testing Patterns</a></li>
<li><a href="https://www.pearson.com/en-us/subject-catalog/p/test-driven-development-by-example/P200000009675" target="_blank" rel="noopener noreferrer">Test Driven Development by Example - Kent Beck</a></li>
</ul>