1

71 arquivos de teste, 845 testes, e nenhum deles estava rodando

Durante algumas semanas o pnpm test do meu projeto terminava assim:

 ❯ test/analyzeChange.test.ts  (0 test)
 ❯ test/rowMapper.test.ts      (0 test)
 ... 69 arquivos ...

 Test Files  no tests
      Tests  no tests

Todos os 71 arquivos imprimiam No test suite found in file, e a execução saía com código diferente de
zero.

Eu li isso como problema de configuração. E é exatamente com o que parece: um glob de include errado,
uma entrada de projects apontando para o diretório errado, um environment incompatível — aquele tipo
de coisa em que o runner está bem e o seu setup está torto. Então ficou lá.

O estado real era que 845 testes não executavam nem uma vez, e nada na tela dizia isso com essas
palavras.

A causa era uma linha que eu mesmo escrevi

No pnpm-workspace.yaml:

overrides:
  # Patch de segurança: advisories de vite que só afetam dev.
  vite: ">=6.4.3"

Eu não dependo do vite diretamente. Ele chega de forma transitiva, embaixo do vitest. Saiu um conjunto de
advisories, a versão corrigida era a 6.4.3, e um override foi o caminho mais curto para garantir que toda
cópia na árvore estivesse igual ou acima disso.

Só que >=6.4.3 não é um pin. É um intervalo aberto — e um override tem precedência sobre o que a
dependência declara. Quando o vite 8.1.4 saiu, o pnpm resolveu para ele, mesmo o vitest 3.2.7
declarando ^5 || ^6 || ^7.0.0-0
, que não inclui a 8.

Essa é a parte que vale guardar: o intervalo que o vitest publica era exatamente a proteção que teria
impedido isso, e overrides é o mecanismo que manda o resolver ignorar essa proteção. Eu desliguei a
verificação e deixei um comentário explicando o motivo — e o comentário não dizia nada sobre o teto,
porque na época não existia nada acima.

Por que o vite 8 devolve zero suítes em vez de um erro

O vite 8 migrou o pipeline de transformação para rolldown/oxc, e o contrato do module-runner mudou junto.
O vitest carregou os 71 arquivos sem lançar exceção, avaliou todos, e não recebeu nenhuma suíte
registrada de volta.

Do ponto de vista do runner isso é indistinguível de um arquivo sem nenhum describe/test dentro.
Então ele reportou a coisa honesta que conseguia ver, uma vez por arquivo: No test suite found in file.

Existia uma única pista da causa real no meio do ruído, e eu vinha passando o olho por ela sem parar:

The `esbuild` option is deprecated, please use `oxc` instead

Esse aviso é o vite 8 se anunciando. Nada na saída jamais mencionou incompatibilidade de versão.

A correção

  vite: ">=6.4.3 <8"

Antes de colocar um teto, vale checar quem realmente pede o pacote:

$ pnpm why vite
  vitest
  vite-node
  @vitest/mocker

Só o runner de testes. Nada nos dois workspaces consome vite em build nem envia para produção, então
restringir não tem raio de impacto nenhum. Se a resposta tivesse incluído o framework ou o bundler, o
teto seria uma decisão de verdade em vez de ser de graça.

O vite caiu para 7.3.6. Os 71 arquivos foram coletados. 845 testes, todos passando.

E então um deles falhou

Não era regressão do período em que a suíte estava morta — nada que eu tinha mexido nesse intervalo
quebrou. A falha era mais antiga que isso, e era real.

Uma função minha montava colunas do banco a partir dos fatos extraídos de um evento de depreciação. Ela
tratava a data de desligamento e o modelo sucessor. Não havia ramo nenhum para a data de depreciação.

Ou seja: a coluna announced_at estava NULL. Não em algumas linhas — em todas as linhas já
escritas
. E é dela que sai o início do período de aviso, isto é, quanto tempo o fornecedor deu antes de
desligar um modelo. Para um projeto cujo assunto inteiro é ciclo de vida de modelo, não é uma falha
cosmética.

O teste que pega isso já existia, e existia esse tempo todo. O nome dele é
shutdown date, successor and announcement date. A extração estava lá. A assertiva estava lá. Faltava só
o mapeamento para a coluna — e o único processo que teria dito isso estava devolvendo no tests.

Depois disso rodei o verificador de tipos, que eu também não rodava há um tempo: exit 2. Um arquivo
lia um campo que a função nunca retornava. As duas verificações automáticas do repositório estavam
falhando, de duas formas diferentes, e nenhuma delas era alta o suficiente para interromper alguém.

O que eu levo disso

Um override de segurança precisa de teto também. O motivo de você escrever um é saber mais que o
resolver sobre uma borda inferior específica. Esse conhecimento não se estende para cima. Um >=x
publicado hoje é uma aposta em toda versão maior que sair depois que você parar de prestar atenção.

no tests é um estado de falha, não um estado neutro. Uma execução que coleta zero suítes carrega a
mesma informação que uma execução que falha: você não sabe se o seu código funciona. Ela já sai com
código diferente de zero — a lacuna estava na minha leitura, não na ferramenta.


Isso saiu de um projeto que faz crawl da documentação de 15 fornecedores de IA e registra cada mudança
com a data em que aconteceu: aichangewatch.com

Carregando publicação patrocinada...