Testes Unitários com Node.js, Jest e TypeScript
Neste artigo você vai aprender como executar testes unitários com Node.js, Jest e TypeScript de forma clara e objetiva
Tutorial de Testes com Jest e TypeScript em Node.js
O objetivo deste tutorial é mostrar como executar testes unitários com Jest e TypeScript de forma objetiva, clara e direta ao ponto. Então vamos ao que interessa.
Instalação
Primeiramente você instala o TypeScript:
npm install typescript --save-dev
Agora você pode instalar o Jest:
npm install jest --save-dev
Por fim você precisa instalar o pacote ts-jest e outro pacote com os tipos do Jest:
npm install ts-jest --save-dev
npm install @types/jest --save-dev
Configuração
Antes de iniciar os testes você precisar configurar o preset. No Jest o preset é um conjunto de configurações que servem de base.
Embora essas configurações sejam muito simples, o ts-jest disponibiliza um comando para criar o arquivo jest.config.js com o preset correto.
npx ts-jest config:init
Para mais detalhes sobre as configurações do Jest veja estes links:
Executando Testes com Jest e TypeScript
Por padrão o Jest executa todos os arquivos que ficam na pasta __tests__ ou que tenham os trechos "test" ou "spec" no nome do arquivo.
Digamos que você tenha o arquivo "/src/index.ts":
export function double(x: number): number {
return x * 2;
}
export function concat(...args: string[]): string {
return args.reduce((result, param) => result + param, '');
}
Para testar essas funções basta você criar o arquivo "__tests__/index.test.ts":
import { double, concat } from '../src/index';
describe('testing index file', () => {
test('double function', () => {
expect(double(5)).toBe(10);
});
test('concat function', () => {
expect(concat('Paul', ' ', 'McCartney')).toBe('Paul McCartney');
});
});
Este exemplo contém um grupo de testes definido pela função describe
e dentro do grupo tem dois testes definidos com a função test
. Lembrando que também é possível criar sub-grupos com a função describe
.
Dentro da função test
você precisa declarar uma expectativa seguida de um "matcher". Neste exemplo, expect
é a expectativa e toBe
é o matcher. Ou seja, você espera que o retorno de uma função (ou uma varíavel) seja igual a um determinado valor.
Para realizar os testes, execute este comando:
npx jest
Pronto! Agora se algum teste falhar o Jest vai mostrar uma mensagem de erro. Como estamos utilizando Jest e TypeScript, vale destacar que inconsistências de tipos também serão apresentadas.
Aperfeiçoando seus Testes
O exemplo que mostrei é algo muito simples, mas conforme seu software cresce seus testes também crescerão e provavelmente você precisará de funcionalidades mais avançadas.
O matcher mais comum é o toBe
e que funciona muito bem para comparar valores primitivos, porém com o tempo você precisará de matchers mais avançados. Eu fiz uma lista com os matchers mais populares:
- toEqual: Útil para verificar objetos e suas propriedades
- toBeFalsy: Útil para verificar valores que podem ser convertidos para
false
por meio da coerção do JavaScript. - toBeTruthy: Útil para verificar valores que podem ser convertidos para
true
por meio da coerção do JavaScript. - toContain: Útil para verificar arrays com valores primitivos.
- toContainEqual: Útil para verificar arrays com objetos.
- toMatch: Útil para verificar strings e expressões regulares.
- toThrow: Útil para verificar se uma função lançou uma exceção.
Algo muito interessante sobre os matchers, é que se você usar o prefixo .not
a condição será invertida. Por exemplo:
expect(1).not.toBe(2);
Se você deseja ver todos os matchers, clique aqui para acessar a documentação oficial.
Testes Assíncronos com Promises
Algo muito comum em JavaScript é testar funções assícronas. Por exemplo, digamos que você tenha a seguinte função:
export function waitSeconds(seconds: number): Promise<string> {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`waited ${seconds} seconds`);
}, seconds * 1000);
});
}
Basicamente essa é uma função que aguarda alguns segundos e retorna uma mensagem. Ela tem como parâmetro um número que represente a quantidade de segundos e retorna uma Promise<string>
.
Você pode testar isso de várias maneiras, mas eu separei quatro tipos de testes para esta função:
import { waitSeconds } from '../src/index';
describe('example of asynchronous testing', () => {
test('testing with async/await', async () => {
expect(await waitSeconds(1)).toBe('waited 1 seconds');
});
test('testing returning a promise', () => {
return expect(waitSeconds(1.5)).resolves.toBe('waited 1.5 seconds');
});
test('testing returning a promise with callback function', () => {
return waitSeconds(0.5).then((response) => {
expect(response).toBe('waited 0.5 seconds');
});
});
test('testing with callback function', (done) => {
waitSeconds(0.8).then((response) => {
expect(response).toBe('waited 0.8 seconds');
done();
});
});
});
Vale destacar que embora sejam quatro tipos diferentes de testes, o resultado deles é o mesmo e você pode escolher o que for mais conveniente para seu caso. Vou deixar aqui o link da documentação oficial sobre testes assíncronos.
Vou deixar aqui também as versões das bibliotecas utilizadas:
- jest: 26.1
- typescript: 4.0
Dúvidas ou sugestões é só entrar em contato. Abraço.