Communitygithub.com

gpanakkal/crucible

Habilidade de agente para testes unitários TypeScript que falham quando deveriam.

O que é crucible?

Crucible é uma habilidade especializada para agentes de IA (como Claude Code ou Cursor) focada em escrever, corrigir e auditar testes unitários em projetos TypeScript. Seu principal diferencial é garantir que os testes falhem quando o código testado está com bugs, evitando falsos positivos. A habilidade instrui o agente a usar Vitest para cobertura de branch e Stryker Mutator para testes de mutação, buscando a máxima cobertura e eliminando mutantes sobreviventes. Os testes devem ser baseados em propriedades sempre que possível, com arbitrariedades que cubram todas as entradas possíveis, e nunca usar `test.fails`/`.skip`, pois isso esconderia falhas. O agente também é instruído a verificar a configuração do projeto (como a presença de um arquivo `.no-crucible` para opt-out), avaliar testes existentes, e gerar relatórios detalhados (debriefs) com pontuações de cobertura e mutação antes e depois das alterações. A habilidade suporta fluxos de trabalho para escrever novos testes, corrigir testes existentes e auditar projetos inteiros ou partes específicas, sempre sem modificar código de aplicação ou testes pré-existentes a menos que explicitamente solicitado.

Funciona com✓Claude Code~Codex CLI~Cursor
npx skills add gpanakkal/crucible

Perguntar na sua IA favorita

Abre um novo chat com esta habilidade de agente já pré-carregada.

Documentação

O que crucible faz?

Quando usar isto

Quando solicitado a escrever, corrigir ou auditar testes unitários em projetos TypeScript.

Quando NÃO usar isto

Ao escrever testes de ponta a ponta, integração, UI ou simulação.

Desativação por projeto

Antes de ativar, verifique se o projeto optou por desativar esta habilidade. Procure por qualquer um dos seguintes:

  • Um arquivo .no-crucible na raiz do projeto
  • "crucible": false em qualquer lugar de AGENTS.md ou .claude/settings.json

Se algum sinal de desativação for encontrado, não ative automaticamente; apenas aplique esta habilidade se o usuário solicitar explicitamente nesta conversa.

Regras

  • Os comandos de exemplo usam pnpm, mas sempre use o gerenciador de pacotes do projeto.
  • Não modifique o código da aplicação a menos que seja especificamente solicitado.
  • Quando solicitado a adicionar testes, não modifique os testes existentes.
  • Quando solicitado a corrigir testes, não adicione novos testes.
  • Quando solicitado a auditar testes, corrija os testes existentes e depois adicione testes conforme necessário para atender aos critérios de teste.

Critérios de Teste

Testes unitários devem:

  • Ter a cobertura de branch máxima possível de acordo com Vitest.
  • Matar todos os mutantes matáveis, alcançando a pontuação de mutação máxima possível em todo o código no escopo do prompt (não apenas o coberto pelos testes). Mutantes imatáveis impedirão uma pontuação de 100.
  • Ser baseados em propriedades sempre que possível, exceto se houver apenas um punhado de casos de entrada. Por exemplo, uma função com um único parâmetro booleano e sem entradas implícitas tem apenas dois casos de entrada possíveis, então não se preocupe em torná-la baseada em propriedades.
  • (se baseado em propriedades) ter arbitrariedades que cubram todos os parâmetros e entradas implícitas possíveis. É vital que nenhum caso que possa ocorrer em produção seja excluído. Se necessário ou incerto, erre para tornar as arbitrariedades muito amplas.
  • Falhar se testarem código incorreto ou se as arbitrariedades forem propositalmente ampliadas demais. Pense nos testes como requisitos: eles devem ser nomeados de acordo e devem passar automaticamente assim que o usuário corrigir o bug no futuro, após corrigir a função e/ou as arbitrariedades. Não use test.fails/.skip; isso torna menos óbvio para o usuário que atenção é necessária, então testes passando quando não deveriam é o erro de maior prioridade a ser evitado.

Verifique a cobertura de branch e execute os testes: pnpm exec vitest run src/foo.test.ts --coverage Verifique os mutantes sobreviventes no código sendo testado: pnpm exec stryker run --mutate "src/foo.ts"

Verificando a configuração de teste

  1. Verifique se todos os seguintes pacotes estão instalados no projeto: vitest fast-check @stryker-mutator/core @stryker-mutator/vitest-runner @stryker-mutator/typescript-checker
  2. Verifique se as configurações do Vitest e do Stryker incluem/excluem arquivos corretamente. O Stryker não deve verificar arquivos que contenham apenas dados de teste.
  3. Verifique a configuração do Stryker:
    1. Use o reporter clear-text (outros reporters são opcionais).
    2. Use o TypeScript checker e aponte corretamente para o arquivo de configuração do TS.
  4. Procure por outros problemas de configuração que possam causar problemas no fluxo de trabalho de escrita de testes.
  5. Relate as descobertas ao usuário.

Escrevendo Testes

Quando solicitado a escrever novos testes, NÃO MODIFIQUE O CÓDIGO DA APLICAÇÃO NEM OS TESTES EXISTENTES.

Primeiro, avalie os testes existentes seguindo Avaliando um módulo. Crie um novo arquivo de debrief usando o modelo e registre a cobertura inicial e as pontuações de mutação lá.

Segundo, escreva os testes seguindo este processo exatamente:

Faça o seguinte para cada função/método na interface do módulo, terminando uma função antes de começar a próxima:

  1. Determine o propósito da função examinando comentários, seu nome, sua assinatura de tipo e como é usada. Se estiver incerto, anote isso no debrief, pule a escrita de testes e passe para a próxima função.
  2. Anote quaisquer bugs potenciais na implementação da função.
  3. Com base em seu propósito, identifique quaisquer suposições falhas que a função faz sobre seus parâmetros e entradas implícitas, e anote quaisquer casos de entrada que provavelmente levem a um comportamento incorreto da função. Por exemplo, uma função que recebe um inteiro positivo, mas não valida sua entrada, faz uma suposição falha sobre sua entrada.
  4. NUNCA MODIFIQUE TESTES PRÉ-EXISTENTES. Se você encontrar problemas nos testes existentes, notifique o usuário sobre os problemas encontrados.
  5. Escreva novos testes fazendo o seguinte: a. Usando fast-check, crie stubs de teste baseados em propriedades com arbitrariedades que cubram todos os parâmetros e entradas implícitas possíveis da função. Use fc.asyncProperty + await fc.assert(...) quando a função sob teste for assíncrona. Em caso de dúvida, erre para tornar as arbitrariedades muito amplas e mencione isso no debrief para que o usuário possa corrigi-las. Nomeie os testes como descrições do comportamento desejado. b. Usando vitest, escreva asserções dentro dos stubs cobrindo quaisquer valores retornados e efeitos colaterais, como lançar exceções, mutar entradas, mutar/redefinir variáveis de escopos externos, etc. Certifique-se de que os testes afirmem o comportamento desejado, capturando as suposições falhas/bugs identificados anteriormente e falhando de acordo.
  6. Re-verifique a cobertura: pnpm exec vitest run src/foo.test.ts --coverage
  7. Teste de mutação apenas a função atual: pnpm exec stryker run --mutate "src/foo.ts:<linhaInicial>-<linhaFinal>"
  8. Revise os testes recém-escritos e repita as etapas 5a e 5b até que os critérios de teste (listados acima) sejam atendidos para a função.
  9. Atualize o debrief com uma seção sobre esta função.

Depois de escrever testes para todas as funções, verifique novamente se você adicionou seções ao debrief para cada função e termine de escrever a seção de resumo.

Auditando Testes

Se solicitado a auditar o projeto como um todo, verifique a cobertura de código e as pontuações de mutação em todo o projeto e recomende áreas para auditorias mais detalhadas ou para adicionar/atualizar testes. Pondere recomendações para as áreas mais importantes e propensas a bugs do código-fonte – lógica de negócios central, código orientado a eventos e funções complexas.

Se solicitado a auditar uma parte do projeto, procure por módulos ou funções (dentro do escopo do prompt) que não têm testes e relate-os ao usuário no debrief pós-auditoria.

Para cada módulo dentro do escopo do prompt que tenha testes, siga Avaliando um módulo. Em seguida, se algum critério de teste ainda não for atendido após as correções da avaliação, siga Escrevendo Testes para preencher as lacunas restantes.

Avaliando um módulo

Use este processo sempre que precisar avaliar um arquivo de teste existente em relação aos critérios de teste – tanto antes de escrever novos testes quanto ao auditar.

  1. Verifique a cobertura de código usando Vitest: pnpm exec vitest run src/foo.test.ts --coverage.
  2. Verifique mutantes sobreviventes usando Stryker Mutator: pnpm exec stryker run --mutate "src/foo.ts".
  3. Para cada função no módulo que tenha testes:
    • Para testes baseados em propriedades:
      • Procure entradas que a função aceitaria sem lançar ou retornar um valor de erro, mas que não podem ser geradas pelas arbitrariedades. Amplie as arbitrariedades conforme necessário para incluir tais entradas.
      • Procure entradas que não sejam cobertas pelas arbitrariedades, especialmente entradas implícitas como campos de classe, variáveis globais, data/hora e números gerados aleatoriamente. Adicione arbitrariedades para estas.
    • Corrija quaisquer erros nas implementações de mock.
    • Procure gargalos de desempenho.
  4. Registre a cobertura e as pontuações de mutação, mais quaisquer descobertas, no debrief.

Debriefs de Teste

Formate os debriefs de acordo com o modelo abaixo. Se não houver nada a relatar em uma subseção de função, simplesmente escreva "n/a". Produza o debrief em um arquivo Markdown em debriefs/.

Debrief: {nomeDoMódulo/nomeDoArquivo} {aaaa-mm-dd}

Resumo

Cobertura (branch) Antes: X% → Depois: Y% Linhas que não puderam ser cobertas: {intervalos de linhas}

Pontuação de mutação (total) Antes: X% → Depois: Y%

Problemas

{lista de marcadores de suposições falhas, bugs encontrados, problemas encontrados em testes e testes com falha. Cada item da lista deve começar com o caminho relativo à raiz do projeto para o arquivo e número(s) de linha(s) onde o problema foi encontrado}

{nomeDaFunção}

Propósito da função {uma frase descrevendo o que a função deve fazer} (confiança: alta | incerta) {se incerta: o que não está claro e por quê}

Suposições falhas encontradas

  • (linha {número/intervalo de linhas}): {suposição sobre o tipo/faixa/forma da entrada que a função não valida}

Bugs encontrados na implementação

  • (linha {número/intervalo de linhas}): {descrição + número da linha}

Problemas encontrados em testes pré-existentes

  • (linha {número/intervalo de linhas}): {descrição do problema + nome do teste}

Casos de teste escritos

  • {breve descrição de cada propriedade/invariante testada}

Testes com falha

  • (linha {número/intervalo de linhas}): {nome do teste + motivo}

Mutantes imatáveis

  • (linha {número/intervalo de linhas}): {breve descrição}

Habilidades Relacionadas