Guía de Migración
Migración a Vitest 2.0
El Pool por Defecto es forks
Vitest 2.0 cambia la configuración por defecto de pool
a 'forks'
para mejorar la estabilidad. Puedes consultar la justificación completa en el PR.
Si has utilizado poolOptions
sin especificar un pool
, es posible que necesites actualizar tu configuración:
export default defineConfig({
test: {
poolOptions: {
threads: {
singleThread: true,
},
forks: {
singleFork: true,
},
}
}
});
Los Hooks se Ejecutan en Secuencia
Antes de Vitest 2.0, todos los hooks se ejecutaban en paralelo. En la versión 2.0, todos los hooks se ejecutan en serie. Además, los hooks afterAll
/afterEach
se ejecutan en orden inverso.
Para revertir a la ejecución paralela de los hooks, cambia sequence.hooks
a 'parallel'
:
export default defineConfig({
test: {
sequence: {
hooks: 'parallel',
},
},
});
suite.concurrent
Ejecuta Todas las Pruebas Concurrentemente
Anteriormente, especificar concurrent
en una suite agrupaba las pruebas concurrentes por suites y las ejecutaba secuencialmente. Ahora, siguiendo el comportamiento de Jest, todas las pruebas se ejecutan concurrentemente (sujeto a los límites de maxConcurrency
).
La Opción coverage.ignoreEmptyLines
de V8 Coverage Está Habilitada por Defecto
El valor por defecto de coverage.ignoreEmptyLines
ahora es true
. Este cambio significativo puede afectar los informes de cobertura de código, lo que podría requerir ajustes en los umbrales de cobertura para algunos proyectos. Este ajuste solo afecta la configuración por defecto cuando coverage.provider
es 'v8'
.
Eliminación de la Opción watchExclude
Vitest utiliza el observador de Vite. Excluye archivos o directorios añadiéndolos a server.watch.ignored
:
export default defineConfig({
server: {
watch: {
ignored: ['!node_modules/examplejs']
}
}
});
--segfault-retry
Eliminado
Con los cambios en el pool por defecto, esta opción ya no es necesaria. Si experimentas errores de segfault, intenta cambiar al pool 'forks'
. Si el problema persiste, por favor, abre un nuevo issue con una reproducción.
Eliminación de Tareas Vacías en Suites
Este es un cambio en la API de tareas avanzada. Anteriormente, al iterar sobre .suite
se accedía a la suite interna vacía que se utilizaba en lugar de una tarea de archivo.
Esto hace que .suite
sea opcional; si la tarea se define en el nivel superior, no tendrá una suite asociada. Puedes usar la propiedad .file
que ahora está presente en todas las tareas (incluida la propia tarea de archivo, así que ten cuidado de no caer en una recursión infinita).
Este cambio también elimina el archivo de expect.getState().currentTestName
y hace que expect.getState().testPath
sea obligatorio.
task.meta
se Añade al JSON Reporter
El reportero JSON ahora incluye task.meta
para cada resultado de aserción.
Tipos Genéricos Simplificados de Funciones Mock (ej. vi.fn<T>
, Mock<T>
)
Anteriormente, vi.fn<TArgs, TReturn>
aceptaba dos tipos genéricos, uno para los argumentos y otro para el valor de retorno. Esto se ha cambiado para aceptar directamente un tipo de función vi.fn<T>
para simplificar su 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();
Acceso a mock.results
Resueltos
Anteriormente, Vitest resolvía los valores de mock.results
si la función devolvía una Promesa. Ahora hay una propiedad mock.settledResults
separada que se completa solo cuando la Promesa devuelta se resuelve o se rechaza.
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'
Con este cambio, también introducimos nuevos matchers toHaveResolved*
similares a toHaveReturned
para facilitar la migración si usabas toHaveReturned
antes:
const fn = vi.fn().mockResolvedValueOnce('result');
await fn();
expect(fn).toHaveReturned('result');
expect(fn).toHaveResolved('result');
Modo Navegador
El Modo Navegador de Vitest experimentó muchos cambios durante el ciclo beta. Puedes leer sobre nuestra filosofía en el Modo Navegador en la página de discusión de GitHub.
La mayoría de los cambios fueron aditivos, pero hubo algunos pequeños cambios que rompen la compatibilidad:
- El proveedor
none
fue renombrado apreview
#5842 - El proveedor
preview
ahora es el predeterminado #5842 indexScripts
fue renombrado aorchestratorScripts
#5842
Opciones Obsoletas Eliminadas
Algunas opciones obsoletas fueron eliminadas:
- Comando
vitest typecheck
- usavitest --typecheck
en su lugar - Variables de entorno
VITEST_JUNIT_CLASSNAME
yVITEST_JUNIT_SUITE_NAME
(usa las opciones del reportero en su lugar) - Verificación de cobertura de
c8
(usa coverage-v8 en su lugar) - Exportación de
SnapshotEnvironment
desdevitest
- impórtalo desdevitest/snapshot
en su lugar SpyInstance
se elimina a favor deMockInstance
Migración a Vitest 1.0
Requisitos Mínimos
Vitest 1.0 requiere Vite 5.0 y Node.js 18 o superior.
Todos los subpaquetes @vitest/*
requieren la versión 1.0 de Vitest.
Actualización de Snapshots #3961
Las comillas en los snapshots ya no se escapan, y todos los snapshots usan comillas invertidas (`) incluso si la cadena es de una sola línea.
- Las comillas ya no se escapan:
expect({ foo: 'bar' }).toMatchInlineSnapshot(`
Object {
- \\"foo\\": \\"bar\\",
+ "foo": "bar",
}
`)
- Los snapshots de una línea ahora usan comillas "`" en lugar de ':
- expect('some string').toMatchInlineSnapshot('"some string"')
+ expect('some string').toMatchInlineSnapshot(`"some string"`)
También hubo cambios en el paquete @vitest/snapshot
. Si no lo estás usando directamente, no necesitas cambiar nada.
- Ya no necesitas extender
SnapshotClient
solo para sobrescribir el métodoequalityCheck
: simplemente pásalo comoisEqual
al iniciar una instancia client.setTest
fue renombrado aclient.startCurrentRun
client.resetCurrent
fue renombrado aclient.finishCurrentRun
Los Pools están Estandarizados #4172
Hemos eliminado muchas opciones de configuración para facilitar la adaptación del runner a tus necesidades. Por favor, consulta los ejemplos de migración si dependes de --threads
u otras opciones relacionadas.
--threads
ahora es--pool=threads
--no-threads
ahora es--pool=forks
--single-thread
ahora es--poolOptions.threads.singleThread
--experimental-vm-threads
ahora es--pool=vmThreads
--experimental-vm-worker-memory-limit
ahora es--poolOptions.vmThreads.memoryLimit
--isolate
ahora es--poolOptions.<pool-name>.isolate
ybrowser.isolate
test.maxThreads
ahora estest.poolOptions.<pool-name>.maxThreads
test.minThreads
ahora estest.poolOptions.<pool-name>.minThreads
test.useAtomics
ahora estest.poolOptions.<pool-name>.useAtomics
test.poolMatchGlobs.child_process
ahora estest.poolMatchGlobs.forks
test.poolMatchGlobs.experimentalVmThreads
ahora estest.poolMatchGlobs.vmThreads
{
scripts: {
- "test": "vitest --no-threads"
// Para un comportamiento idéntico:
+ "test": "vitest --pool forks --poolOptions.forks.singleFork"
// O múltiples 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"
}
}
Cambios en la Cobertura #4265, #4442
La opción coverage.all
ahora está habilitada por defecto. Esto significa que todos los archivos del proyecto que coincidan con el patrón coverage.include
serán procesados, incluso si no se ejecutan.
La estructura de la API de umbrales de cobertura cambió, y ahora soporta la especificación de umbrales para archivos específicos usando patrones 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
Algunos tipos fueron eliminados a favor de la nomenclatura "Mock" al estilo Jest.
- import { EnhancedSpy, SpyInstance } from 'vitest'
+ import { MockInstance } from 'vitest'
WARNING
SpyInstance
está deprecado a favor de MockInstance
y será eliminado en la próxima versión principal.
Mocks de Temporizador #3925
vi.useFakeTimers()
ya no simula automáticamente process.nextTick
. Todavía es posible simular process.nextTick
especificándolo explícitamente usando vi.useFakeTimers({ toFake: ['nextTick'] })
.
Sin embargo, la simulación de process.nextTick
no es posible cuando se usa --pool=forks
. Usa una opción --pool
diferente si necesitas la simulación de process.nextTick
.
Migración desde Jest
Vitest ha sido diseñado con una API compatible con Jest para hacer la migración desde Jest lo más sencilla posible. A pesar de esos esfuerzos, aún puedes encontrarte con las siguientes diferencias:
Globales por Defecto
Jest tiene su API de globales habilitada de forma predeterminada. Vitest no. Puedes habilitar los globales a través de la configuración globals
o actualizar tu código para usar importaciones del módulo vitest
en su lugar.
Si decides mantener los globales deshabilitados, ten en cuenta que bibliotecas comunes como testing-library
no realizarán la limpieza automática del DOM.
Mocks de Módulos
Al simular un módulo en Jest, el valor de retorno de la función de fábrica es la exportación por defecto. En Vitest, el argumento de fábrica debe devolver un objeto con cada exportación definida explícitamente. Por ejemplo, el siguiente jest.mock
tendría que actualizarse de la siguiente manera:
jest.mock('./some-path', () => 'hello');
vi.mock('./some-path', () => ({
default: 'hello',
}));
Para más detalles, consulta la sección de la API vi.mock
.
Comportamiento de Auto-Mocking
A diferencia de Jest, los módulos simulados en <root>/__mocks__
no se cargan a menos que se llame a vi.mock()
. Si necesitas que se simulen en cada prueba, como en Jest, puedes configurarlos dentro de setupFiles
.
Importar el Original de un Paquete Mockeado
Si solo estás simulando parcialmente un paquete, es posible que hayas usado previamente la función requireActual
de Jest. En Vitest, debes reemplazar estas llamadas con vi.importActual
.
const { cloneDeep } = jest.requireActual('lodash/cloneDeep');
const { cloneDeep } = await vi.importActual('lodash/cloneDeep');
Extender la Simulación a Bibliotecas Externas
A diferencia de Jest, que lo hace por defecto, cuando simulas un módulo y quieres que esta simulación se extienda a otras bibliotecas externas que usan el mismo módulo, debes indicar explícitamente qué biblioteca de terceros deseas simular. Esto se logra haciendo que la biblioteca externa forme parte de tu código fuente, utilizando server.deps.inline.
server.deps.inline: ["lib-name"]
expect.getState().currentTestName
Los nombres de test
de Vitest se unen con un símbolo >
para facilitar la distinción entre pruebas y suites, mientras que Jest usa un espacio vacío ().
- `${describeTitle} ${testTitle}`
+ `${describeTitle} > ${testTitle}`
Variables de Entorno
Al igual que Jest, Vitest establece NODE_ENV
a test
, si no estaba configurado antes. Vitest también tiene un equivalente para JEST_WORKER_ID
llamado VITEST_POOL_ID
(siempre menor o igual a maxThreads
), así que si dependes de ella, no olvides renombrarla. Vitest también expone VITEST_WORKER_ID
que es un ID único de un worker en ejecución - este número no se ve afectado por maxThreads
, y aumentará con cada worker creado.
Reemplazo de Propiedades
Si quieres modificar un objeto, en Jest usarías la API replaceProperty
. En Vitest, puedes lograr lo mismo usando vi.stubEnv
o vi.spyOn
.
Callback done
A partir de Vitest v0.10.0, el estilo de callback para declarar pruebas ha sido deprecado. Puedes reescribirlas para usar funciones async
/await
, o usar Promesas para imitar el estilo de callback.
it('should work', (done) => {
it('should work', () => new Promise(done => {
// ...
done()
})
}))
Hooks
Los hooks beforeAll
/beforeEach
pueden devolver una función de limpieza en Vitest. Por lo tanto, es posible que necesites reescribir tus declaraciones de hooks si devuelven algo diferente a undefined
o null
:
beforeEach(() => setActivePinia(createTestingPinia()));
beforeEach(() => { setActivePinia(createTestingPinia()) });
En Jest, los hooks se llaman secuencialmente (uno tras otro). Por defecto, Vitest ejecuta los hooks en paralelo. Para usar el comportamiento de Jest, actualiza la opción sequence.hooks
:
export default defineConfig({
test: {
sequence: {
hooks: 'list',
}
}
});
Tipos
Vitest no tiene un equivalente al espacio de nombres jest
, por lo que necesitarás importar los tipos directamente desde vitest
:
let fn: jest.Mock<(name: string) => number>;
import type { Mock } from 'vitest';
let fn: Mock<(name: string) => number>;
Temporizadores
Vitest no soporta los temporizadores legados de Jest.
Tiempo Límite
Si usaste jest.setTimeout
, tendrás que migrar a vi.setConfig
:
jest.setTimeout(5_000);
vi.setConfig({ testTimeout: 5_000 });
Snapshots de Vue
Esta no es una característica específica de Jest, pero si anteriormente usabas Jest con el preset de vue-cli, necesitarás instalar el paquete jest-serializer-vue
e incluirlo 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);
De lo contrario, tus snapshots tendrán muchos caracteres "
escapados.