Guia de Migração
Migrando para o Vitest 2.0
O Pool Padrão Agora é forks
O Vitest 2.0 altera a configuração padrão para pool
para 'forks'
visando maior estabilidade. Você pode ler a motivação completa no PR.
Se você utilizava poolOptions
sem especificar um pool
, pode ser necessário atualizar sua configuração:
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
},
},
});
Hooks Agora São Executados em Sequência
Antes do Vitest 2.0, todos os hooks eram executados em paralelo. No 2.0, todos os hooks são executados serialmente. Além disso, os hooks afterAll
/afterEach
são executados em ordem inversa.
Para reverter para a execução paralela de hooks, altere sequence.hooks
para 'parallel'
:
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
});
suite.concurrent
Executa Todos os Testes Concorrentemente
Anteriormente, especificar concurrent
em uma suíte agrupava testes concorrentes por suítes, executando-os sequencialmente. Agora, seguindo o comportamento do Jest, todos os testes são executados concorrentemente (sujeito aos limites de maxConcurrency
).
coverage.ignoreEmptyLines
do V8 Coverage Está Habilitado por Padrão
O valor padrão de coverage.ignoreEmptyLines
agora é true
. Essa mudança significativa pode afetar os relatórios de cobertura de código, exigindo ajustes nos limites de cobertura para alguns projetos. Esse ajuste afeta apenas a configuração padrão quando coverage.provider
é 'v8'
.
Remoção da Opção watchExclude
O Vitest utiliza o observador do Vite. Exclua arquivos ou diretórios adicionando-os a server.watch.ignored
:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs'],
},
},
});
--segfault-retry
Removido
Com as mudanças no pool padrão, esta opção não é mais necessária. Se você tiver erros de segfault, tente mudar para o pool 'forks'
. Se o problema persistir, abra um novo problema com uma reprodução.
Tarefa Vazia em Suítes Foi Removida
Esta é uma mudança na API de tarefas avançada. Anteriormente, percorrer .suite
eventualmente levaria à suíte interna vazia que era usada em vez de uma tarefa de arquivo.
Isso torna .suite
opcional; se a tarefa for definida no nível superior, ela não terá uma suíte associada. Você pode recorrer à propriedade .file
que agora está presente em todas as tarefas (incluindo a própria tarefa de arquivo, então tome cuidado para não cair em recursão infinita).
Essa mudança também remove o arquivo de expect.getState().currentTestName
e torna expect.getState().testPath
obrigatório.
task.meta
é Adicionado ao JSON Reporter
O JSON reporter agora imprime task.meta
para cada resultado de asserção.
Tipos Genéricos Simplificados de Funções Simuladas (por exemplo, vi.fn<T>
, Mock<T>
)
Anteriormente, vi.fn<TArgs, TReturn>
aceitava dois tipos genéricos separadamente para argumentos e valor de retorno. Isso foi alterado para aceitar diretamente um tipo de função vi.fn<T>
para simplificar o uso.
import { type Mock, vi } from 'vitest';
const add = (x: number, y: number): number => x + y;
// usando vi.fn<T>
const mockAdd = vi.fn<Parameters<typeof add>, ReturnType<typeof add>>();
const mockAdd = vi.fn<typeof add>();
// usando Mock<T>
const mockAdd: Mock<Parameters<typeof add>, ReturnType<typeof add>> = vi.fn();
const mockAdd: Mock<typeof add> = vi.fn();
Acessando mock.results
Resolvidos
Anteriormente, o Vitest resolvia os valores de mock.results
se a função retornasse uma Promise. Agora existe uma propriedade separada mock.settledResults
que é preenchida apenas quando a Promise retornada é resolvida ou rejeitada.
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
const result = fn.mock.results[0]; // 'result'
const result = fn.mock.results[0]; // 'Promise<result>'
const settledResult = fn.mock.settledResults[0]; // 'result'
Com essa mudança, também introduzimos novos matchers toHaveResolved*
semelhantes a toHaveReturned
para facilitar a migração se você usava toHaveReturned
antes:
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result');
Modo Browser
O Modo Browser do Vitest teve muitas mudanças durante o ciclo beta. Você pode ler sobre nossa filosofia no Modo Browser na página de discussão do GitHub.
A maioria das mudanças foram aditivas, mas houve algumas pequenas mudanças que quebram a compatibilidade:
- O provedor
none
foi renomeado parapreview
#5842 - O provedor
preview
agora é o padrão #5842 indexScripts
foi renomeado paraorchestratorScripts
#5842
Opções Obsoletas Removidas
Algumas opções obsoletas foram removidas:
- Comando
vitest typecheck
- usevitest --typecheck
em vez disso - Variáveis de ambiente
VITEST_JUNIT_CLASSNAME
eVITEST_JUNIT_SUITE_NAME
(use as opções do reporter em vez disso) - Verificação de cobertura
c8
(use coverage-v8 em vez disso) - Exportação de
SnapshotEnvironment
devitest
- importe-o devitest/snapshot
em vez disso SpyInstance
foi removido em favor deMockInstance
Migrando para o Vitest 1.0
Requisitos Mínimos
O Vitest 1.0 requer Vite 5.0 e Node.js 18 ou superior.
Todos os subpacotes @vitest/*
requerem a versão 1.0 do Vitest.
Atualização de Snapshots #3961
Aspas em snapshots não são mais escapadas, e todos os snapshots usam aspas de crase (`) mesmo que a string seja de apenas uma linha.
- Aspas não são mais escapadas:
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)
- Snapshots de uma linha agora usam aspas "`" em vez de ':
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)
Também houve mudanças no pacote @vitest/snapshot
. Se você não o estiver usando diretamente, não precisa mudar nada.
- Você não precisa mais estender
SnapshotClient
apenas para sobrescrever o métodoequalityCheck
: basta passá-lo comoisEqual
ao iniciar uma instância client.setTest
foi renomeado paraclient.startCurrentRun
client.resetCurrent
foi renomeado paraclient.finishCurrentRun
Pools são Padronizados #4172
Removemos muitas opções de configuração para facilitar a configuração do executor às suas necessidades. Por favor, veja os exemplos de migração se você depende de --threads
ou outras flags relacionadas.
--threads
agora é--pool=threads
--no-threads
agora é--pool=forks
--single-thread
agora é--poolOptions.threads.singleThread
--experimental-vm-threads
agora é--pool=vmThreads
--experimental-vm-worker-memory-limit
agora é--poolOptions.vmThreads.memoryLimit
--isolate
agora é--poolOptions.<pool-name>.isolate
ebrowser.isolate
test.maxThreads
agora étest.poolOptions.<pool-name>.maxThreads
test.minThreads
agora étest.poolOptions.<pool-name>.minThreads
test.useAtomics
agora étest.poolOptions.<pool-name>.useAtomics
test.poolMatchGlobs.child_process
agora étest.poolMatchGlobs.forks
test.poolMatchGlobs.experimentalVmThreads
agora étest.poolMatchGlobs.vmThreads
{
scripts: {
- "test": "vitest --no-threads"
// Para comportamento idêntico:
+ "test": "vitest --pool forks --poolOptions.forks.singleFork"
// Ou múltiplos forks paralelos:
+ "test": "vitest --pool forks"
}
}
{
scripts: {
- "test": "vitest --experimental-vm-threads"
+ "test": "vitest --pool vmThreads"
}
}
{
scripts: {
- "test": "vitest --isolate false"
+ "test": "vitest --poolOptions.threads.isolate false"
}
}
{
scripts: {
- "test": "vitest --no-threads --isolate false"
+ "test": "vitest --pool forks --poolOptions.forks.isolate false"
}
}
Mudanças na Cobertura #4265, #4442
A opção coverage.all
agora está habilitada por padrão. Isso significa que todos os arquivos do projeto que correspondem ao padrão coverage.include
serão processados, mesmo que não sejam executados.
O formato da API de limites de cobertura foi alterado, e agora suporta a especificação de limites para arquivos específicos usando padrões glob:
export default defineConfig({
test: {
coverage: {
- perFile: true,
- thresholdAutoUpdate: true,
- 100: true,
- lines: 100,
- functions: 100,
- branches: 100,
- statements: 100,
+ thresholds: {
+ perFile: true,
+ autoUpdate: true,
+ 100: true,
+ lines: 100,
+ functions: 100,
+ branches: 100,
+ statements: 100,
+ }
}
}
})
Tipos de Mock #4400
Alguns tipos foram removidos em favor da nomenclatura "Mock" no estilo Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'
WARNING
SpyInstance
está depreciado em favor de MockInstance
e será removido na próxima versão principal.
Mocks de Temporizadores #3925
vi.useFakeTimers()
não simula mais automaticamente process.nextTick
. Ainda é possível simular process.nextTick
especificando-o explicitamente usando vi.useFakeTimers({ toFake: ['nextTick'] })
.
No entanto, simular process.nextTick
não é possível ao usar --pool=forks
. Use uma opção --pool
diferente se precisar de simulação de process.nextTick
.
Migrando do Jest
O Vitest foi projetado com uma API compatível com Jest, a fim de tornar a migração do Jest o mais simples possível. Apesar desses esforços, você ainda pode encontrar as seguintes diferenças:
Globais como Padrão
O Jest tem sua API de globais habilitada por padrão. O Vitest não. Você pode habilitar as globais através da configuração globals
ou atualizar seu código para usar importações do módulo vitest
em vez disso.
Se você decidir manter as globais desabilitadas, esteja ciente de que bibliotecas comuns como testing-library
não executarão a limpeza automática do DOM.
Simulações de Módulo
Ao simular um módulo no Jest, o valor de retorno do argumento de fábrica é a exportação padrão. No Vitest, o argumento de fábrica deve retornar um objeto com cada exportação explicitamente definida. Por exemplo, o seguinte jest.mock
teria que ser atualizado da seguinte forma:
jest.mock('./some-path', () => 'hello');
vi.mock('./some-path', () => ({
default: 'hello',
}));
Para mais detalhes, consulte a seção da API vi.mock
.
Comportamento de Auto-Simulação
Ao contrário do Jest, módulos simulados em <root>/__mocks__
não são carregados a menos que vi.mock()
seja chamado. Se você precisar que eles sejam simulados em cada teste, como no Jest, você pode simulá-los dentro de setupFiles
.
Importando o Original de um Pacote Simulado
Se você estiver apenas simulando parcialmente um pacote, pode ter usado anteriormente a função requireActual
do Jest. No Vitest, você deve substituir essas chamadas por vi.importActual
.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep');
Estendendo a Simulação para Bibliotecas Externas
Onde o Jest faz isso por padrão, ao simular um módulo e querer que essa simulação seja estendida a outras bibliotecas externas que usam o mesmo módulo, você deve dizer explicitamente qual biblioteca de terceiros você deseja que seja simulada, para que a biblioteca externa faça parte do seu código-fonte, usando server.deps.inline.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
Os nomes dos test
do Vitest são unidos com um símbolo >
para facilitar a distinção entre testes e suítes, enquanto o Jest usa um espaço vazio ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`
Envs
Assim como o Jest, o Vitest define NODE_ENV
como test
, se não foi definido antes. O Vitest também tem uma contraparte para JEST_WORKER_ID
chamada VITEST_POOL_ID
(sempre menor ou igual a maxThreads
), então se você depende dela, não se esqueça de renomeá-la. O Vitest também expõe VITEST_WORKER_ID
que é um ID único de um worker em execução - este número não é afetado por maxThreads
, e aumentará a cada worker criado.
Substituição de Propriedade
Se você quiser modificar o objeto, você usará a API replaceProperty no Jest, você pode usar vi.stubEnv
ou vi.spyOn
para fazer o mesmo também no Vitest.
Callback done
A partir do Vitest v0.10.0, o estilo de callback para declarar testes está depreciado. Você pode reescrevê-los para usar funções async
/await
, ou usar Promise para imitar o estilo de callback.
it('should work', (done) => { // [!code --]
it('should work', () => new Promise(done => { // [!code ++]
// ...
done()
}) // [!code --]
})) // [!code ++]
Hooks
Os hooks beforeAll
/beforeEach
podem retornar uma função de teardown no Vitest. Por causa disso, você pode precisar reescrever suas declarações de hooks, se eles retornarem algo diferente de undefined
ou null
:
beforeEach(() => setActivePinia(createTestingPinia()));
beforeEach(() => {
setActivePinia(createTestingPinia());
});
No Jest, os hooks são chamados sequencialmente. Por padrão, o Vitest executa os hooks em paralelo. Para usar o comportamento do Jest, atualize a opção sequence.hooks
:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
},
},
});
Tipos
O Vitest não possui um equivalente ao namespace jest
, portanto, você precisará importar os tipos diretamente do vitest
:
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>;
Temporizadores
O Vitest não suporta os temporizadores legados do Jest.
Timeout
Se você utilizou jest.setTimeout
, precisará migrar para vi.setConfig
:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 });
Snapshots do Vue
Este não é um recurso específico do Jest, mas se você usava o Jest com o preset vue-cli, precisará instalar o pacote jest-serializer-vue
e usá-lo dentro de setupFiles:
import { defineConfig } from 'vite';
export default defineConfig({
test: {
setupFiles: ['./tests/unit/setup.js'],
},
});
import vueSnapshotSerializer from 'jest-serializer-vue';
expect.addSnapshotSerializer(vueSnapshotSerializer);
Caso contrário, seus snapshots terão muitas aspas duplas ("
) escapadas.