nock para TypeScript: Mocking de HTTP em Testes
1. O que é nock e por que usar?
nock é uma biblioteca poderosa para Node.js, projetada para interceptar e simular (mockar) requisições HTTP. Ela permite que desenvolvedores imitem respostas de serviços externos (REST APIs, microsserviços de terceiros, webhooks) sem a necessidade de realizar requisições de rede reais. Isso é essencial ao escrever testes unitários e de integração, onde estabilidade e velocidade de execução são cruciais.
Por que usar? Imagine que sua aplicação envia requisições para um gateway de pagamento, uma API de clima ou um banco de dados via HTTP. Em um ambiente de teste, você não quer depender da disponibilidade desses serviços, da velocidade de resposta ou de limites de requisições. O nock permite "substituir" essas requisições, retornando dados pré-definidos. Isso torna os testes rápidos, previsíveis e isolados de fatores externos. Além disso, você pode testar cenários de erro (timeouts, códigos 500, respostas vazias) que são difíceis de reproduzir em condições reais.
No contexto do TypeScript, o nock se integra perfeitamente com frameworks de teste populares (Jest, Mocha, Vitest) e oferece suporte a tipagem, tornando o trabalho mais seguro e produtivo. A biblioteca intercepta requisições no nível do Node.js (através dos módulos http e https), funcionando com qualquer cliente HTTP: axios, node-fetch, got e até mesmo o fetch nativo (com algumas ressalvas).
2. Instalação
Para instalar o nock em um projeto TypeScript, execute um dos seguintes comandos no terminal:
# Via npm
npm install --save-dev nock @types/nock
# Via yarn
yarn add --dev nock @types/nock
# Via pnpm
pnpm add --save-dev nock @types/nock
Importante: O pacote @types/nock contém as declarações de tipos para TypeScript. Se você estiver usando TypeScript 4.0+, os tipos podem já estar incluídos na própria biblioteca, mas para garantir compatibilidade, é recomendável instalá-los explicitamente.
3. Primeiros Passos
Vamos escrever um teste mínimo que demonstra o funcionamento básico do nock. Suponha que temos uma função que obtém dados de um usuário de uma API externa.
// userService.ts
import axios from 'axios';
export async function getUser(userId: number): Promise<{ id: number; name: string; email: string }> {
const response = await axios.get(`https://jsonplaceholder.typicode.com/users/${userId}`);
return response.data;
}
Agora, vamos escrever um teste que simula (mocka) essa requisição:
// userService.test.ts
import nock from 'nock';
import { getUser } from './userService';
describe('getUser', () => {
afterEach(() => {
nock.cleanAll(); // Limpa todos os mocks após cada teste
});
it('deve retornar os dados do usuário', async () => {
// 1. Configura a interceptação
const mockUser = { id: 1, name: 'João Silva', email: 'joao@exemplo.com' };
nock('https://jsonplaceholder.typicode.com')
.get('/users/1')
.reply(200, mockUser);
// 2. Chama a função sendo testada
const user = await getUser(1);
// 3. Verifica o resultado
expect(user).toEqual(mockUser);
});
it('deve lançar um erro quando o servidor retorna 500', async () => {
nock('https://jsonplaceholder.typicode.com')
.get('/users/1')
.reply(500, { error: 'Erro no Servidor' });
await expect(getUser(1)).rejects.toThrow();
});
});
Este exemplo mostra como é fácil simular a resposta de um servidor e testar tanto cenários de sucesso quanto de erro.