NodeJS
Jest
Implementando Testes com Jest: Garantindo a Confiabilidade do Código
Adotei o Jest pra testar meu código e ganhei muito em confiança e qualidade. Essa jornada me fez enxergar o valor real do TDD no dia a dia.
Última atualização realizada em:
Você pode acessar o código completo do projeto diretamente no GitHub através deste link: clique aqui
Estava explorando algumas discussões sobre tecnologia e mercado no Reddit quando encontrei a seguinte pergunta de um usuário: “Quão utilizado na indústria é o TDD (Test Driven Development)?”. A resposta foi tão boa quanto a dúvida: “o termo (TDD) foi tão banalizado que, hoje, usam isso com a ideia de que 'Testou?! Então é TDD!', quando na verdade não é.”
Essa troca me fez refletir. No código que tenho desenvolvido, a prática não é TDD — e o motivo é simples: escrevi a aplicação primeiro e só depois criei os testes. Se o nome da abordagem é literalmente “desenvolvimento orientado a testes”, não faz sentido dizer que estou seguindo TDD quando o fluxo foi o inverso.
Mas, independentemente da nomenclatura, o ponto central é outro: testes são indispensáveis. Eles mantêm o código confiável enquanto o projeto cresce, e sem eles cada manutenção ou correção se torna uma caçada às cegas por possíveis erros.
Tabela de conteúdos
Por que escrever testes importa?Por que escolhi testar com Jest?Exemplo práticoEvoluindo a mentalidadeRoadmap e próximos passosConclusão
Por que escrever testes importa?
Testes não são um “extra” que colocamos no final do projeto. Eles são parte fundamental do ciclo de desenvolvimento porque permitem que o código evolua com segurança. Quando existe cobertura de testes, é possível refatorar sem medo de quebrar algo que já estava funcionando.
Outro ponto importante é que, à medida em que a aplicação cresce, a complexidade cresce junto. Encontrar um bug sem testes se torna cada vez mais custoso. Já com testes, qualquer mudança pode ser validada de forma rápida e previsível. Em resumo:
- Eles aumentam a confiabilidade do sistema.
- Tornam a manutenção mais fácil e menos arriscada.
- Permitem refatorações seguras sem a sensação de “andar no escuro”.
Por que escolhi testar com Jest?
Para implementar testes, escolhi o Jest. A decisão foi simples: além de ser muito usado na comunidade JavaScript/TypeScript, o Jest é robusto e traz recursos que facilitam a vida no dia a dia.
Alguns pontos que pesaram na escolha:
- Resultados legíveis em múltiplos formatos, facilitando entender falhas rapidamente.
- Cache de resultados de testes, o que agiliza bastante quando a suíte cresce.
- Mocks e spies nativos, que simplificam o isolamento de dependências.
- Configuração mínima, funcionando bem desde o início sem precisar de muito setup.
É claro que eu poderia escrever testes em NodeJS puro, mas o Jest acelera a implementação, traz mais clareza nos relatórios e se adapta facilmente a diferentes cenários do projeto.
Exemplo prático
Você pode acessar o código completo do projeto diretamente no GitHub através deste link: clique aqui
Uma das maiores vantagens do Jest é justamente a capacidade de se adaptar ao código já existente. Não precisei reescrever funções ou refatorar a aplicação inteira só para começar a testar — bastou criar os testes em cima do que já estava pronto.
Observe como o Jest se adapta ao que já existe e facilita mocks/relatórios, no código abaixo:
// __tests__/get-post-list.spec.ts // - usa @notionhq/client com um Client({ auth }) // - consulta data_source_id "collection-123" // - aplica filtro { published: true } quando NODE_ENV === 'production' // - ordena por updated_at desc // - normaliza resultados, ignorando páginas no lixo, objetos que não são "page" e páginas sem props mínimas import { Client } from '@notionhq/client' import { getPostList } from '../src/services/get.posts.list' import { createPage } from './fakes/page.ts' // --- Mock da lib externa (@notionhq/client) jest.mock('@notionhq/client', () => { const mockQuery = jest.fn() const MockClient = jest.fn().mockImplementation(() => ({ dataSources: { query: mockQuery, }, })) // expõe o mock para uso no teste ;(MockClient as any).__mockQuery = mockQuery return { Client: MockClient } }) describe('get post list', () => { const mockQuery = (Client as any).__mockQuery as jest.Mock const OLD_ENV = process.env beforeEach(() => { jest.clearAllMocks() jest.useFakeTimers().setSystemTime(new Date('2025-01-01T12:00:00Z')) process.env = { ...OLD_ENV, NOTION_TOKEN: 'test-token' } }) afterAll(() => { process.env = OLD_ENV jest.useRealTimers() }) it('usa filtro published=true em produção', async () => { // força ambiente de produção para validar o filtro process.env.NODE_ENV = 'production' const results = [ createPage({}), // válido createPage({ id: 'trash', in_trash: true }), // deve ser ignorado createPage({ id: 'not-page', object: 'database' }), // deve ser ignorado createPage({ id: 'missing-props', withProps: false }), // deve ser ignorado // outro válido, com props vazias que sua normalização trata: createPage({ id: 'empty-props', slug: '', title: '', description: '', withProps: true, }), ] mockQuery.mockResolvedValueOnce({ results }) const list = await getPostList() // 1) o Client foi instanciado com o token esperado expect(Client).toHaveBeenCalledWith({ auth: 'test-token' }) // 2) a consulta foi feita com os parâmetros corretos em produção expect(mockQuery).toHaveBeenCalledWith({ data_source_id: 'collection-123', filter: { property: 'published', checkbox: { equals: true }, }, sorts: [{ property: 'updated_at', direction: 'descending' }], page_size: 10, }) // 3) a lista final contém apenas os itens válidos e normalizados expect(list).toHaveLength(2) expect(list[0]).toEqual({ slug: 'my-slug', title: 'My Title', description: 'My Description', created_at: expect.any(Date), updated_at: expect.any(Date), }) expect(list[1]).toEqual({ slug: '', title: '', description: '', created_at: expect.any(Date), updated_at: expect.any(Date), }) }) })
Esse padrão permite que eu controle totalmente as respostas da biblioteca sem precisar me conectar de fato à API da Notion. Assim, consigo validar o comportamento do meu código em diferentes cenários — sucesso, erro, exceções — apenas manipulando o mock.
Além disso, as asserções do Jest tornam a checagem dos resultados esperados muito clara (
toBe, toEqual, toHaveBeenCalledWith, etc.), e os relatórios de execução mostram com precisão quais testes passaram, quais falharam e até a cobertura geral do projeto.No fim, o que mais gosto é isso: com poucas linhas, consigo simular um ambiente inteiro e ter confiança de que meu código vai se comportar como esperado em produção.
Além deste, há diversos outros testes implementados na aplicação — todos seguindo uma abordagem semelhante: criar mocks, simular cenários e validar o comportamento esperado. A ideia é justamente não precisar refatorar o código por enquanto, aproveitando o fato de que o Jest se encaixa bem no fluxo já existente.
Evoluindo a mentalidade
Hoje, minha abordagem é simples: escrevo o código e depois crio os testes. Isso já traz benefícios imediatos de confiabilidade e reduz bastante o risco de regressões.
Mas o ponto é que, agora que os testes já existem, fica mais fácil inverter o processo: refatorar primeiro o teste e só depois o código. Essa mudança de perspectiva abre caminho para o TDD, onde cada funcionalidade nasce a partir de um teste que define o comportamento esperado.
Não se trata de virar a chave de uma hora para outra, mas de uma evolução natural. Aos poucos, essa prática transforma a forma como pensamos a implementação: em vez de apenas garantir que algo funciona, passamos a desenhar o código a partir de como ele será usado e validado.
Roadmap e próximos passos
- Expandir a implementação de testes automatizados para outras áreas do projeto.
- Melhorar o design para refletir um blog mais moderno e consistente.
- Adicionar scripts de monitoramento de performance do conteúdo.
- Utilizar uma ferramenta de bundle para otimizar o tamanho da aplicação dentro do monorepo.
- Refatorar o código para desacoplar módulos e preparar a aplicação para futuras substituições sem grandes impactos.
Conclusão
Implementar testes não é apenas sobre aumentar a cobertura de código. É sobre criar uma base confiável que permita que o projeto evolua sem medo de quebrar o que já existe.
O Jest entrou aqui como uma ferramenta prática e robusta, que me permitiu validar comportamentos, mockar dependências externas e ganhar clareza com relatórios e asserções simples.
Mais do que isso, esses testes já abrem espaço para uma mudança de mentalidade: aos poucos, o fluxo pode migrar de escrever o código primeiro para desenhar o comportamento esperado via testes. Esse é o passo natural para chegar ao TDD.
O ponto central é que, independentemente da abordagem, a qualidade não pode ser opcional. Testar é parte do desenvolvimento — e é exatamente isso que garante confiabilidade, escalabilidade e evolução segura do projeto.