O que test-suite-doctor faz?
Reduza uma suíte de testes superdimensionada (ex.: 2.000+ testes, muitos deles conteúdo gerado por IA de baixa qualidade) para uma suíte pequena e de alta qualidade, mantendo uma parcela configurável da cobertura real — medida, não estimada.
Regras rígidas
- Métricas antes de opiniões. Nunca proponha deletar um teste antes que
collecteminimizetenham produzido um plano. Ler o código do teste e julgá-lo "inútil" não é evidência — um teste de aparência trivial pode ser a única cobertura para um ramo. - O plano é uma proposta, não um veredito. A cobertura não enxerga contratos de API, casos de regressão documentados ou invariantes de propriedade. Cada candidato a exclusão é revisado (passo 3) antes da remoção.
- Trabalhe em um branch. Antes de deletar qualquer coisa, verifique se a árvore de trabalho está limpa e crie um branch (ex.:
test-doctor/minimize). Nunca delete testes em uma árvore suja ou no branch padrão. - Verifique ou reverta. O trabalho só está concluído quando
verifysai com código 0. Se falhar, regenere testes para as lacunas reportadas e verifique novamente — ou restaure os testes deletados.
Verificação de requisitos (faça isso primeiro)
- Node.js ≥ 22 e um package.json usando Vitest ou Jest instalado localmente (
node <skill-root>/dist/cli.mjs collect --help). - Um provedor de cobertura deve estar instalado (Vitest:
@vitest/coverage-v8; Jest já possui um integrado). Se estiver faltando, ofereça-se para instalá-lo como dependência de desenvolvimento. - A verificação por mutação adicionalmente precisa do
@stryker-mutator/coreconfigurado no repositório alvo — é opcional, não instale sem ser solicitado. - A suíte deve estar verde antes de começar. Se a execução inicial reportar falhas, informe o usuário e obtenha acordo sobre como tratá-las antes de minimizar (testes com falha contribuem com cobertura não confiável).
Todos os comandos abaixo são executados a partir da raiz do repositório alvo; $SKILL é o diretório desta skill. Os artefatos são salvos em .test-doctor/ (sugira adicioná-lo ao .gitignore).
Fluxo de trabalho
1. MEDIR (script — sempre primeiro)
node "$SKILL/dist/cli.mjs" collect --cwd .
Detecta o executor, executa a suíte completa uma vez como linha de base de cobertura e, em seguida, executa cada arquivo de teste isoladamente, registrando linhas/ramos cobertos e tempo de execução. Escreve .test-doctor/report.json.
- A granularidade padrão é por arquivo de teste (isolamento por teste é exato, mas executa cada teste separadamente — ofereça
--granularity testapenas para suítes pequenas ou já reduzidas, ou com escopo definido via--filter). - Em uma suíte com 2.000 testes, isso leva um tempo; execute em segundo plano e reporte o progresso. Leve
collectionErrorsno relatório a sério — essas unidades bloqueiam a minimização por padrão. Se o usuário escolher explicitamente--keep-unmeasured, toda unidade afetada é mantida obrigatoriamente e o plano é marcado como não confiável. --filtercria uma linha de base deliberadamente com escopo: coleta, minimização e verificação cobrem apenas os arquivos de teste correspondentes. Indique esse escopo em toda recomendação; não é uma garantia para todo o repositório.
2. MINIMIZAR (script)
node "$SKILL/dist/cli.mjs" minimize --coverage-floor 0.97 --target-count 200
Seleção gulosa por soma ponderada: mantém repetidamente a unidade com mais linhas/ramos recém-cobertos por milissegundo de execução até que o piso de cobertura seja atingido. Escreve .test-doctor/plan.json e um arquivo legível .test-doctor/plan.md com uma justificativa para cada unidade mantida ou descartada.
- Pergunte ao usuário seus limites se não forem informados; os padrões são piso de 0,97 para linhas, nenhum piso para ramos e nenhum limite de contagem.
--helplista todas as opções. - Forçar a manutenção de testes de contrato/regressão conhecidos antecipadamente:
--keep 'contract' --keep 'regression'(regex no identificador da unidade). - Preste atenção ao array
warningsdo plano — por exemplo, piso inatingível ou necessidade de mais unidades que o limite de contagem. Repasse-os ao usuário exatamente como estão.
3. REVISAR (julgamento — seu)
Leia references/slop-patterns.md, depois revise a lista de exclusão em plan.md:
- Resgate qualquer teste que verifique comportamento invisível para a cobertura: contratos de API pública, regressões referenciando um ID de issue/bug, redação de mensagens de erro usadas por consumidores, verificações de propriedade/invariante. Execute
minimizenovamente com padrões--keepadicionais, em vez de editar o plano manualmente. - Confirme que os demais são exclusões seguras; classifique-os por padrão de "slop" para que o usuário veja por que cada um morre (o arquivo de padrões tem o catálogo).
Em seguida, revise a lista de mantidos com base em references/quality-rules.md: testes mantidos que pareçam suspeitos (mock-do-mock, tautologias, snapshots vazios) são reescritos no local — eles merecem sua cobertura, mas devem merecê-la de forma limpa.
Somente após esta revisão, exclua os arquivos/casos de teste descartados no branch. Exclua arquivos inteiros quando todas as suas unidades forem descartadas; edite arquivos quando apenas alguns testes dentro deles morrerem (granularidade de teste).
4. REGENERAR (julgamento — seu)
Execute verify uma vez (espere que possa falhar) para obter o relatório de lacunas de cobertura e, em seguida, escreva novos testes para os arquivos fonte mais afetados listados por verify, seguindo references/quality-rules.md: estrutura AAA, nomes orientados a comportamento, um comportamento por teste, mocks apenas em limites externos. Prefira um teste forte cobrindo um comportamento real visível ao usuário a três testes superficiais.
5. VERIFICAR (script — bloqueia a conclusão)
node "$SKILL/dist/cli.mjs" verify --coverage-floor 0.97
# opcionalmente, apenas para módulos críticos (lento):
node "$SKILL/dist/cli.mjs" verify --mutation --mutate "src/billing/**/*.ts" --mutation-floor 80
Executa novamente a suíte, exige que esteja verde e exige que a retenção de linhas em relação à linha de base atinja o piso. Saída 0 = concluído; saída 1 = corrija e execute novamente (regenerar mais testes ou restaurar exclusões); saída 2 = problema de ambiente, pare e reporte. Testes de mutação são opcionais por módulo, pois são lentos — ofereça-os para os módulos que o usuário considerar críticos.
A versão 2 cria uma linha de base com impressões digitais do código fonte coberto, configuração do executor, arquivo de bloqueio, executor e provedor de cobertura. Se verify reportar desvio de proveniência, colete uma nova linha de base. Use --allow-provenance-drift apenas com acordo explícito do usuário e reporte o veredito resultante como não confiável. Linhas de base legadas da v1 também exigem a opção de escape explícita --allow-legacy-baseline.
Reportando de volta
Resuma para o usuário: unidades antes → depois, retenção de linhas/ramos, tempo de execução antes → depois, padrões de "slop" encontrados (com contagens), testes resgatados da lista de exclusão e por quê, testes regenerados e o veredito final do verify. Inclua o caminho para plan.md para a trilha de auditoria completa.
Modos de falha
- Executor não detectado / ambíguo → a CLI sai com código 2 e orientações; passe
--runnerou--cwd(monorepos: execute por pacote). - Coleta incompleta → corrija as falhas isoladas. Não filtre apenas para fazer um plano passar; um filtro altera o escopo declarado da linha de base.
--keep-unmeasuredé a opção de escape conservadora. - Verify continua falhando após regeneração → pare de repetir após ~3 tentativas; apresente a lacuna residual arquivo por arquivo e deixe o usuário decidir entre reduzir o piso e manter mais testes.
- Suíte estava vermelha antes de começar → não "corrija" falhas não relacionadas silenciosamente; reporte-as e obtenha acordo sobre o escopo primeiro.