12k
All articles

O que mudou no Vitest 5

Veja o que mudou no Vitest 5: ganhos de desempenho, alterações incompatíveis, novos padrões, caminhos de relatórios e etapas para atualizar testes e CI.

OpenReplay Team
OpenReplay Team
O que mudou no Vitest 5

O Vitest 5.0, lançado em 3 de setembro de 2026, é uma versão major focada em desempenho. Ele exige Node.js 22.12.0+ e Vite 6.4.0+, ativa a limpeza de mocks por padrão, faz falhar asserções assíncronas sem await e move a saída dos reporters para um único diretório .vitest/.

A maioria das falhas após a atualização é fácil de resolver. As difíceis são os testes que passam localmente no Vitest 4 e ficam vermelhos no CI com um erro que não diz nada sobre a causa.

Este artigo organiza as notas de lançamento da v5.0.0 por impacto. Primeiro, o que realmente ficou mais rápido. Em seguida, as mudanças que exigem edições no código, as mudanças que alteram silenciosamente caminhos e regras de correspondência, um checklist de atualização e um veredito.

Principais pontos

  • O Vitest 5.0 exige Node.js 22.12.0 ou posterior e Vite 6.4.0 ou posterior.
  • Os benchmarks da equipe do Vitest mostram a maioria das configurações testadas rodando de 8 a 25% mais rápido, e até 53% mais rápido em algumas configurações com pools de VM. Configurações dominadas pela preparação do ambiente praticamente não mudam.
  • clearMocks agora tem true como padrão. Por isso, uma asserção sobre o histórico de chamadas registrado em um arquivo de setup, em um hook beforeAll ou em um teste anterior agora vê zero chamadas.
  • Relatórios blob, anexos e a saída dos reporters JSON, JUnit e HTML agora usam, por padrão, caminhos dentro de .vitest/. As etapas de artefatos do CI precisam ser atualizadas.
  • toThrow('') agora corresponde a qualquer erro lançado. Uma asserção que pretende verificar uma mensagem vazia precisa de um padrão explícito.

Por que o Vitest 5 é mais rápido?

A maioria das configurações nos benchmarks da própria equipe do Vitest roda de 8 a 25% mais rápido, segundo o anúncio do Vitest 5. Os pools de VM são os que mais ganham, com até 53% em algumas configurações. Nem toda configuração fica mais rápida. Execuções em que a criação do ambiente de teste consome a maior parte do tempo, como forks com jsdom e isolamento, ficam a menos de 3% do Vitest 4.1.

Os números vêm do vitest-dev/benchmarks, onde a equipe gerou aplicações de teste de diferentes tamanhos, desde um pacote pequeno de 5 arquivos até um monólito de 1.280 módulos. No post de lançamento da VoidZero, isso é arredondado para “pools de VM até 53% mais rápidos, ganho de ~18% em todos os cenários, incluindo o Browser Mode”.

Segundo as notas de lançamento, quatro mudanças produzem a maior parte do ganho:

  • Servidor Vite compartilhado. Os projetos inline agora compartilham um único servidor Vite, em vez de cada um iniciar o seu.
  • fsModuleCache. Agora é uma opção de nível superior. Ela salva os módulos transformados em disco, de modo que uma nova execução ou outro processo do Vitest pode pular esse trabalho.
  • Menos idas e voltas. Módulos já transformados agora chegam a um worker em uma única viagem a partir do processo principal.
  • Reutilização nos pools de VM. Os pools vmThreads e vmForks compartilham código compilado entre contextos e carregam o grafo de módulos antecipadamente.

O Vitest também oferece suporte ao cache de compilação em disco do Node, mas ele precisa ser ativado explicitamente.

Quais mudanças do Vitest 5 exigem edição no código?

Seis mudanças do Vitest 5 causam uma falha de teste ou um erro de configuração na primeira execução. O guia de migração aborda cada uma delas.

MudançaSintoma na primeira execuçãoCorreção
clearMocks: true por padrãoAsserções de contagem de chamadas veem 0Dispare as chamadas dentro do teste que faz a asserção ou defina clearMocks: false
Asserção assíncrona sem awaitO teste falhaAdicione await
Chamada vi içada fora do nível superiorLança um erroMova-a para o escopo do módulo
sequential removidoAPI removida{ concurrent: false }
Sem busca de config em diretórios paisConfig não encontradaAdicione uma config na pasta do pacote
API de bench reescritaCódigo de bench antigo quebraMigre para o modelo de fixtures

Limpeza de mocks e hoisting

No Vitest 5, clearMocks tem true como padrão, então vi.clearAllMocks() é executado antes de cada teste. O histórico de chamadas registrado em um arquivo de setup, em um hook beforeAll ou em um teste anterior é apagado antes que o próximo teste faça asserções sobre ele. As implementações dos mocks são mantidas.

// Vitest 5.0.x
const track = vi.fn()
beforeAll(() => initAnalytics(track))

it('tracks once on init', () => {
  expect(track).toHaveBeenCalledTimes(1) // now receives 0 calls
})

A correção é disparar a chamada dentro do teste que faz a asserção sobre ela. Definir clearMocks: false na config test restaura o comportamento antigo enquanto você audita a suíte.

Chamar vi.mock, ou qualquer outra chamada vi içada (hoisted), fora do nível superior de um arquivo agora lança um erro. O Vitest já içava essas chamadas para o topo do módulo de qualquer forma, então o código dentro de um bloco describe nunca era executado onde foi escrito.

// Vitest 5.0.x: throws
describe('UserCard', () => {
  const fetchUser = vi.fn()
  vi.mock('./api', () => ({ fetchUser }))
})

// Vitest 5.0.x: works
const { fetchUser } = vi.hoisted(() => ({ fetchUser: vi.fn() }))
vi.mock('./api', () => ({ fetchUser }))

describe('UserCard', () => {
  it('renders the user', async () => {
    fetchUser.mockResolvedValue({ name: 'Ada' })
    // mount and assert
  })
})

Se as suas suítes Vue fazem mock da camada de API, o mesmo padrão de nível superior se aplica ao mock de chamadas de API em testes Vue com Vitest.

Asserções sem await

Um teste que deixa uma asserção assíncrona sem await agora falha. A ausência de await antes de expect(...).resolves ou .rejects deixa o teste vermelho.

// Vitest 5.0.x
test('loads config', async () => {
  expect(loadConfig()).resolves.toEqual({ ok: true }) // fails
  await expect(loadConfig()).resolves.toEqual({ ok: true }) // passes
})

Este grep lista os candidatos. Você ainda precisa verificar se cada ocorrência tem um await antes:

grep -rnE "expect\(.*\)\.(resolves|rejects)" src/ --include='*.test.*' --include='*.spec.*'

Concorrência, busca de config e bench

As opções sequential em testes e suítes foram removidas. Para desativar a concorrência, use test('example', { concurrent: false }, ...) ou describe('suite', { concurrent: false }, ...).

O Vitest 5 deixa de procurar um arquivo de config nas pastas acima da atual. Se você executa vitest a partir de uma subpasta de pacote, essa pasta precisa da sua própria config.

A API de bench foi reescrita. Você não importa mais bench no topo de um arquivo. Em vez disso, obtém-no a partir do contexto do teste, dentro de uma chamada test() comum em um arquivo de benchmark.

As notas de lançamento listam outros itens incompatíveis que você deve verificar, caso se apliquem ao seu projeto:

  • expect.poll agora falha quando atinge o tempo limite.
  • Pontos de entrada obsoletos foram removidos.
  • @vitest/runner está obsoleto, e vitest não depende mais de @vitest/expect, porque o código de asserção agora é distribuído dentro do próprio vitest.
  • O provider @vitest/browser-webdriverio foi movido para a organização vitest-community e agora é mantido pela comunidade.
  • workerId agora começa em 1.

toThrow('') agora corresponde a qualquer erro lançado. Se você realmente quer verificar uma mensagem vazia, passe uma regex como /^$/.

O que muda silenciosamente no Vitest 5?

Seis mudanças do Vitest 5 não lançam erro. Em vez disso, um caminho, um filtro ou um resultado de correspondência muda por baixo da sua configuração existente.

  • Caminhos de saída. Relatórios blob e --merge-reports usam .vitest/blob/ por padrão. Os anexos passam de .vitest-attachements/ para .vitest/attachments/. Os arquivos dos reporters JSON, JUnit e HTML também usam .vitest por padrão.
  • Filtros -t. O separador dos filtros por nome de teste agora é >. Verifique todos os scripts de CI que filtram pelo caminho da suíte.
  • Locators do navegador. locators.exact agora vem ativado por padrão no Browser Mode.
  • Correspondência de texto. toHaveTextContent agora é estrito. toMatchTextContent é a nova alternativa.
  • Globs de cobertura. Os padrões include e exclude agora são comparados com o caminho de cada arquivo relativo à raiz do projeto, e um padrão sem curinga é tratado como uma pasta inteira. O conjunto de arquivos considerados na cobertura pode mudar, então verifique seus limites (thresholds) após a primeira execução.
  • Projetos inline. Os projetos inline agora herdam a config raiz como se extends: true estivesse definido.

Uma etapa típica de artefatos muda assim:

-          path: .vitest-attachements/
+          path: .vitest/attachments/
+          # sharded runs: upload .vitest/blob/ for --merge-reports

Novidades do Vitest 5 que vale a pena conhecer

vi.when permite definir um resultado diferente de um spy para cada conjunto de argumentos. calledWith aceita matchers assimétricos, e chamadas cujos argumentos não correspondem a nada recorrem à implementação original.

// Vitest 5.0.x
vi.when(getUser).calledWith(1).thenResolve({ id: 1, name: 'Ada' })

No Browser Mode, definir test.browser.traceView: true ativa a visualização de trace. Cada interação, asserção e chamada a page.mark é salva como um snapshot do DOM, permitindo reproduzir o teste passo a passo na interface.

Projetos aninhados agora são suportados, o que ajuda monorepos a agrupar projetos relacionados.

Checklist de atualização para o Vitest 5

  1. Migre os ambientes de CI e locais para Node.js 22.12.0+ e Vite 6.4.0+.
  2. Execute o grep acima e adicione await onde estiver faltando.
  3. Mova todas as chamadas vi.mock e vi.hoisted para o nível superior dos respectivos arquivos.
  4. Substitua sequential por { concurrent: false } e adicione configs às pastas de pacotes que dependiam de uma config em um diretório pai.
  5. Execute a suíte. Se asserções de contagem de chamadas falharem, corrija-as ou defina clearMocks: false como solução temporária.
  6. Atualize os caminhos de artefatos do CI para .vitest/ e revise os filtros -t e os limites de cobertura.

Atualizar para o Vitest 5 agora ou esperar?

Atualize para o Vitest 5 nesta sprint se o seu CI já roda Node.js 22.12.0+ e Vite 6.4.0+. A maior parte das edições necessárias é mecânica.

A exceção é uma suíte que faz asserções sobre o histórico de chamadas de mocks herdado entre testes, seja de arquivos de setup, de hooks beforeAll ou de um teste que depende das chamadas de outro. Essas falhas não dão nenhuma pista da causa, então audite essas asserções primeiro e só depois atualize. Suítes de componentes também devem reexecutar suas asserções de texto e de locators. Os padrões em testando componentes Svelte 5 com Vitest mostram onde elas costumam aparecer.

O Vitest 5 é mais rápido, e a maior parte do que ele quebra é código de teste que já estava errado. Comece pelo grep e pela movimentação dos vi.mock em uma branch, verifique os caminhos de artefatos do CI e deixe a primeira execução do CI apontar o restante.

Perguntas frequentes

O Vitest 5 também ativa mockReset ou restoreMocks por padrão?

Não. O guia de migração do Vitest 5 altera o padrão apenas de clearMocks. clearMocks chama vi.clearAllMocks() antes de cada teste e redefine mock.calls, mock.instances, mock.contexts e mock.results, mas mantém as implementações. mockReset vai além: limpa o histórico e redefine cada implementação para a original, de modo que um mock criado com vi.fn(impl) volta a impl. restoreMocks restaura as implementações originais dos spies criados com vi.spyOn.

Por que meu filtro -t corresponde a menos testes após atualizar para o Vitest 5?

No Vitest 5, testNamePattern (a flag -t) é comparado com o nome completo do teste, montado com ' > ' entre o nome de cada suíte e o nome do teste. É o mesmo texto que aparece na saída do reporter. O Vitest 4 usava um único espaço entre as partes, como o Jest. Um padrão só quebra se atravessar de uma parte do nome para a seguinte. Para corrigir, corresponda a apenas uma parte, como -t adds, ou coloque um curinga entre as partes, como -t 'math.*adds'.

Por que o Vitest 5 não consegue resolver o vite após a atualização com Yarn?

No Vitest 5, o vite deixou de ser uma dependência direta e passou a ser uma peer dependency obrigatória, então o Vitest roda com a versão do Vite instalada no seu projeto. npm, pnpm, Bun e Deno adicionam peer dependencies automaticamente. O Yarn deixa essa etapa por sua conta. Adicione o vite na versão 6.4.0 ou posterior ao seu package.json e reinstale as dependências; assim, o Vitest volta a conseguir resolvê-lo.

Como mesclar relatórios de testes fragmentados (sharding) no Vitest 5?

Execute cada shard com o reporter blob, por exemplo vitest run --reporter=blob --shard=1/3 na primeira máquina. Cada shard grava seus resultados em .vitest/blob/ por padrão, e a flag --outputFile.blob altera esse local. Copie o diretório de todas as máquinas para um único job final e execute vitest --merge-reports. Se os seus testes salvam anexos como arquivos, leve também a pasta de anexos para o job de mesclagem.

DevTools for the frontend

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.

Star on GitHub12k

We use cookies to improve your experience. By using our site, you accept cookies.