A Cobertura de Testes no Node.js mede quais linhas, funções e branches foram executados durante a suíte. O Node.js Test Runner consegue coletar cobertura usando o V8, gerar resumo no terminal e produzir arquivo LCOV para integração com ferramentas de CI.
Na documentação do Node.js 26.5.0, a coleta nativa continua marcada como experimental. Isso significa que flags, formato e comportamento podem mudar. O recurso já é útil em projetos que fixam a versão do runtime e validam a saída no pipeline.
Neste guia, você aprenderá a ativar cobertura, configurar include e exclude, gerar LCOV, definir thresholds no CI, interpretar métricas, ignorar código justificadamente, combinar testes unitários e integração e evitar a busca por 100% sem qualidade.
O que é cobertura de código?
Cobertura registra quais partes do programa foram executadas pelos testes. A documentação oficial de cobertura do Node.js Test Runner descreve a flag e os filtros. A documentação de cobertura do V8 explica a coleta nativa do motor.
Para criar a suíte, consulte Node Test Runner. Para dependências simuladas, veja Mocks no Node.js Test Runner. O artigo de Módulo V8 no Node.js ajuda a entender o motor.
Ativando cobertura
node --test --experimental-test-coverageAo final, reporters como spec e tap mostram um resumo. Como a flag é experimental, fixe a versão usada pelo projeto.
Script no package.json
{
"scripts": {
"test": "node --test",
"test:coverage": "node --test --experimental-test-coverage"
}
}Métricas principais
- Lines: linhas executadas.
- Functions: funções chamadas.
- Branches: caminhos condicionais executados.
Uma linha coberta não prova que o resultado foi validado. O teste pode executar o código sem fazer assert útil.
Incluindo arquivos
node --test \
--experimental-test-coverage \
--test-coverage-include='src/**/*.js'O filtro permite incluir arquivos que talvez não tenham sido carregados. Coloque globs entre aspas para evitar expansão diferente pelo shell.
Excluindo arquivos
node --test \
--experimental-test-coverage \
--test-coverage-exclude='src/generated/**'Exclua código gerado, migrations imutáveis ou arquivos sem lógica apenas quando houver justificativa.
Testes e node_modules
Por padrão, módulos internos do Node.js, node_modules e arquivos de teste costumam não entrar no relatório. As opções de inclusão e exclusão podem alterar esse comportamento.
Gerando LCOV
node --test \
--experimental-test-coverage \
--test-reporter=lcov \
--test-reporter-destination=lcov.infoO reporter LCOV não mostra necessariamente o resultado normal dos testes. Use múltiplos reporters quando precisar de saída humana e arquivo:
node --test \
--experimental-test-coverage \
--test-reporter=spec \
--test-reporter-destination=stdout \
--test-reporter=lcov \
--test-reporter-destination=lcov.infoDiretório coverage
mkdir -p coverage
node --test \
--experimental-test-coverage \
--test-reporter=lcov \
--test-reporter-destination=coverage/lcov.infoAdicione artefatos gerados ao .gitignore, salvo quando a política do projeto exige versioná-los.
NODE_V8_COVERAGE
NODE_V8_COVERAGE=coverage/raw node --testA variável solicita arquivos brutos de cobertura do V8. Eles podem ser grandes e precisar de processamento adicional.
Cobertura de TypeScript
Quando o Node.js executa TypeScript com remoção de tipos ou quando o projeto transpila código, confirme se os caminhos e source maps correspondem à fonte. Caso contrário, a cobertura pode apontar para JavaScript gerado.
Consulte o que é TypeScript e Module API no Node.js para source maps.
Branches
function calculateDiscount(user) {
if (user.isPremium) {
return 0.2;
}
return 0;
}Um teste apenas com usuário premium cobre parte das linhas, mas deixa o branch comum sem validação.
Condições compostas
if (user.active && user.age >= 18) {
allowAccess();
}Teste combinações relevantes: ativo e adulto, inativo e adulto, ativo e menor. Não é necessário cobrir combinações impossíveis pelo domínio.
Funções não chamadas
Functions coverage revela código que nenhum teste invoca. Pode indicar lacuna, função morta ou export desnecessário.
Cobertura não é qualidade
Este teste aumenta cobertura sem verificar comportamento:
test('executa função', () => {
calculateTotal([{ price: 10 }]);
});Prefira:
test('soma os preços', () => {
assert.equal(
calculateTotal([{ price: 10 }, { price: 15 }]),
25
);
});Thresholds
O runner nativo pode não oferecer em todas as versões a mesma configuração de thresholds encontrada em ferramentas externas. Uma opção é analisar o LCOV ou o evento de cobertura em um script de CI.
Threshold global
Exigir um percentual mínimo global evita regressões grandes, mas pode esconder um módulo crítico sem testes porque outros arquivos têm cobertura alta.
Threshold por arquivo
Aplicar limites por arquivo é mais rigoroso. Exclua adapters triviais apenas com revisão.
Regra de não regressão
Uma política prática é impedir que a cobertura total diminua e exigir cobertura alta para código novo.
Diff coverage
Ferramentas externas podem calcular cobertura apenas das linhas alteradas. Isso ajuda projetos legados a melhorar gradualmente.
CI com GitHub Actions
- name: Run tests with coverage
run: npm run test:coverage
- name: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/lcov.infoFixe a versão do Node.js no workflow.
Falha dos testes
Cobertura só faz sentido quando a suíte passa. Não publique relatório de uma execução interrompida como se fosse completo.
Processos filhos
O Test Runner executa arquivos em processos separados por padrão. A infraestrutura do runner combina a cobertura. Processos criados manualmente pela aplicação podem exigir configuração adicional.
Worker Threads
Confirme se código executado em workers aparece conforme esperado. Testes específicos do worker ajudam a evitar lacunas.
Veja Worker Threads no Node.js.
Código carregado dinamicamente
Imports condicionais só aparecem quando o caminho é executado. Crie testes para plugins e configurações relevantes.
Erros e catch
try {
return await repository.find(id);
} catch (error) {
logger.error(error);
throw new ServiceError('Falha ao buscar');
}Teste também a rejeição do repositório para cobrir o catch e validar o erro traduzido.
Retries
Teste sucesso inicial, falha transitória seguida de sucesso e esgotamento. Veja Retry com Backoff no Node.js.
Código de shutdown
Handlers de sinais são difíceis de testar no mesmo processo. Extraia a lógica de shutdown para uma função e teste com dependências falsas.
Ignorando linhas
O Node.js reconhece comentários de cobertura:
/* node:coverage ignore next */
if (platformSpecificCondition) {
runPlatformFallback();
}Ignorando várias linhas
/* node:coverage ignore next 3 */
if (impossibleInProduction) {
emergencyFallback();
}Disable e enable
/* node:coverage disable */
function generatedCode() {
// conteúdo gerado
}
/* node:coverage enable */Comentários de ignore devem ser raros e revisados. Eles podem esconder código testável.
Código defensivo
Não ignore automaticamente branches “impossíveis”. Se protegem contra entrada inválida, teste a falha.
Código gerado
Prefira excluir pela configuração em vez de inserir comentários em arquivos gerados.
Ordenação de testes
Uma suíte que depende de ordem pode produzir cobertura variável. Isole estado e use diretórios, bancos e portas independentes.
Randomização
Versões recentes do Test Runner oferecem randomização experimental ou em desenvolvimento. Isso ajuda a encontrar dependência de ordem, mas não funciona em todas as estruturas de subtests.
Watch mode
Coverage em watch pode gerar resultados parciais e custo alto. Para relatório oficial, execute a suíte completa em processo limpo.
Snapshots
Snapshots aumentam cobertura ao executar serializers, mas não substituem asserts de regras críticas.
Mocks
Mocks podem cobrir branches de erro rapidamente, porém escondem problemas de integração. Equilibre com testes reais.
Testes unitários
São rápidos e cobrem regras isoladas. Normalmente compõem a maior parte da suíte.
Testes de integração
Cobrem banco, filesystem, filas e HTTP reais ou em containers. São mais lentos, mas validam contratos.
Testes end-to-end
Cobrem caminhos completos. Mesmo com poucos casos, protegem fluxos críticos.
Arquivos sem cobertura
Se um arquivo nunca é importado, ele pode não aparecer sem um include explícito. Configure o glob de source para revelar arquivos completamente não testados.
Arquivos de entrada
Scripts CLI, server bootstrap e migrations costumam ter baixa cobertura. Extraia lógica para módulos testáveis e mantenha o entrypoint pequeno.
Relatórios HTML
O reporter nativo gera LCOV, que pode ser convertido por ferramentas externas em HTML navegável. Não exponha o relatório publicamente se caminhos ou código forem sensíveis.
Armazenamento de artefatos
Retenha relatórios por período limitado. Arquivos brutos do V8 podem consumir espaço significativo.
Performance
Coletar cobertura adiciona overhead. Não use em benchmarks de desempenho e não habilite permanentemente em produção.
Flakiness
Testes instáveis tornam o percentual variável. Corrija flakiness antes de usar cobertura como gate rígido.
Revisão humana
Um relatório mostra “onde não passou”, não “quais casos faltam”. A revisão deve perguntar:
- quais regras têm maior risco;
- quais erros não foram simulados;
- quais integrações não foram exercitadas;
- quais asserts são fracos;
- quais testes dependem de implementação.
Meta realista
Projetos diferentes precisam de metas diferentes. Código financeiro e autorização merece cobertura e revisão maiores que adapters simples.
Testes de mutação
Mutation testing altera o código e verifica se os testes detectam a mudança. Ele mede força dos asserts melhor que cobertura isolada, mas custa mais.
Erros comuns
- Buscar 100% cegamente: testes sem valor são criados.
- Não incluir todo src: arquivos sem teste desaparecem.
- Ignorar branches: caminhos de erro ficam frágeis.
- Usar cobertura experimental sem fixar Node: CI muda.
- Publicar relatório de suíte falha: dados ficam incompletos.
- Habilitar em benchmark: resultados são distorcidos.
- Confiar apenas em unitários: integrações quebram.
Boas práticas
- Fixe a versão do Node.js.
- Inclua todos os fontes.
- Exclua apenas com justificativa.
- Gere LCOV no CI.
- Evite regressão.
- Revise branches críticos.
- Combine níveis de teste.
- Use ignores raramente.
- Corrija testes instáveis.
- Avalie qualidade dos asserts.
Conclusão
A Cobertura de Testes no Node.js oferece visibilidade sobre linhas, funções e branches executados pelo Test Runner, com filtros e saída LCOV.
Como a coleta permanece experimental no Node.js 26.5.0, o projeto deve fixar o runtime e validar a integração. O percentual é um indicador, não o objetivo final. Com includes completos, thresholds equilibrados e testes de integração, a cobertura ajuda a localizar riscos sem incentivar uma falsa sensação de segurança.




