12k
All articles

Qué ha cambiado en Vitest 5

Consulta los cambios de Vitest 5: mejoras de rendimiento, cambios incompatibles, nuevos valores predeterminados, rutas de informes y pasos para actualizar pruebas y CI.

OpenReplay Team
OpenReplay Team
Qué ha cambiado en Vitest 5

Vitest 5.0, publicado el 3 de septiembre de 2026, es una versión major centrada en el rendimiento. Requiere Node.js 22.12.0+ y Vite 6.4.0+, activa por defecto la limpieza de mocks, hace fallar las aserciones asíncronas sin await y agrupa la salida de los reporters en un único directorio .vitest/.

La mayoría de los fallos que aparecen tras la actualización son fáciles de resolver. Los difíciles son los tests que pasan en local con Vitest 4 y se ponen en rojo en CI con un error que no dice nada sobre la causa.

Este artículo ordena las notas de la versión v5.0.0 según su impacto. Primero, qué es realmente más rápido. Después, los cambios que requieren modificar el código, los que alteran de forma silenciosa rutas y reglas de coincidencia, una lista de comprobación para la actualización y una valoración final.

Conclusiones clave

  • Vitest 5.0 requiere Node.js 22.12.0 o posterior y Vite 6.4.0 o posterior.
  • Los benchmarks del equipo de Vitest muestran que la mayoría de las configuraciones probadas se ejecutan entre un 8 y un 25 % más rápido, y hasta un 53 % más rápido en algunas configuraciones con pools de VM. Las configuraciones dominadas por la preparación del entorno apenas cambian.
  • clearMocks pasa a tener true como valor por defecto, de modo que una aserción sobre el historial de llamadas registrado en un archivo de setup, en un hook beforeAll o en un test anterior ahora ve cero llamadas.
  • Los informes blob, los adjuntos y la salida de los reporters JSON, JUnit y HTML se guardan ahora por defecto en rutas bajo .vitest/, por lo que hay que actualizar los pasos de artefactos de CI.
  • toThrow('') ahora coincide con cualquier error lanzado, así que una aserción pensada para comprobar un mensaje vacío necesita un patrón explícito.

¿Por qué Vitest 5 es más rápido?

Según el anuncio de Vitest 5, la mayoría de las configuraciones de los benchmarks del propio equipo de Vitest se ejecutan entre un 8 y un 25 % más rápido. Los pools de VM son los más beneficiados, con mejoras de hasta el 53 % en algunas configuraciones. No todas las configuraciones se aceleran: en las ejecuciones en las que la creación del entorno de test consume la mayor parte del tiempo, como forks con jsdom y aislamiento, la diferencia con Vitest 4.1 no supera el 3 %. Las cifras proceden de vitest-dev/benchmarks, donde el equipo generó aplicaciones de prueba de distintos tamaños, desde un pequeño paquete de 5 archivos hasta un monolito de 1280 módulos. En la publicación de lanzamiento de VoidZero, esto se resume como «pools de VM hasta un 53 % más rápidos, ~18 % de mejora general, incluido Browser Mode».

Según las notas de la versión, la mayor parte de la mejora se debe a cuatro cambios:

  • Servidor de Vite compartido. Los proyectos inline ahora comparten un único servidor de Vite en lugar de que cada uno arranque el suyo.
  • fsModuleCache. Ahora es una opción de primer nivel. Guarda en disco los módulos transformados, de forma que una nueva ejecución u otro proceso de Vitest puede ahorrarse ese trabajo.
  • Menos viajes de ida y vuelta. Los módulos ya transformados llegan ahora a un worker desde el proceso principal en un solo viaje.
  • Reutilización en los pools de VM. Los pools vmThreads y vmForks comparten código compilado entre contextos y cargan el grafo de módulos de forma anticipada.

Vitest también es compatible con la caché de compilación en disco de Node, aunque hay que activarla explícitamente.

¿Qué cambios de Vitest 5 requieren editar el código?

Seis cambios de Vitest 5 provocan un fallo de test o un error de configuración en la primera ejecución. La guía de migración los aborda uno por uno.

CambioSíntoma en la primera ejecuciónSolución
clearMocks: true por defectoLas aserciones de número de llamadas ven 0Provocar las llamadas dentro del test que hace la aserción, o establecer clearMocks: false
Aserción asíncrona sin awaitEl test fallaAñadir await
Llamada a vi elevada (hoisted) fuera del nivel superiorLanza una excepciónMoverla al ámbito del módulo
Eliminación de sequentialAPI eliminada{ concurrent: false }
Sin búsqueda de configuración en directorios padreNo se encuentra la configuraciónAñadir una configuración en la carpeta del paquete
API de bench reescritaEl código de bench antiguo deja de funcionarMigrar al modelo de fixtures

Limpieza y hoisting de mocks

En Vitest 5, clearMocks tiene true como valor por defecto, por lo que vi.clearAllMocks() se ejecuta antes de cada test. El historial de llamadas registrado en un archivo de setup, en un hook beforeAll o en un test anterior desaparece antes de que el siguiente test haga su aserción. Las implementaciones de los mocks se mantienen.

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

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

La solución consiste en provocar la llamada dentro del test que hace la aserción. Establecer clearMocks: false en la configuración test restaura el comportamiento anterior mientras revisas la suite.

Llamar a vi.mock, o a cualquier otra llamada elevada de vi, en cualquier lugar que no sea el nivel superior de un archivo ahora lanza una excepción. En cualquier caso, Vitest eleva estas llamadas al principio del módulo, así que el código dentro de un bloque describe nunca se ejecutaba donde estaba 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
  })
})

Si tus suites de Vue hacen mock de la capa de API, el mismo patrón de nivel superior se aplica al mocking de llamadas a la API en tests de Vue con Vitest.

Aserciones asíncronas sin await

Un test que deja una aserción asíncrona sin await ahora falla. Omitir el await antes de expect(...).resolves o .rejects pone el test en rojo.

// 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 los candidatos. Aun así, tendrás que comprobar en cada resultado si va precedido de await:

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

Concurrencia, búsqueda de configuración y bench

Las opciones sequential de tests y suites han desaparecido. Para desactivar la concurrencia, usa test('example', { concurrent: false }, ...) o describe('suite', { concurrent: false }, ...).

Vitest 5 ya no busca archivos de configuración en las carpetas superiores a la actual. Si ejecutas vitest desde una subcarpeta de un paquete, esa carpeta necesita su propia configuración.

La API de bench se ha reescrito. Ya no se importa bench al principio del archivo. En su lugar, se obtiene del contexto del test dentro de una llamada test() normal en un archivo de benchmark.

Las notas de la versión enumeran otros cambios incompatibles que conviene revisar por si te afectan:

  • expect.poll ahora falla cuando se agota el tiempo de espera.
  • Se han eliminado los puntos de entrada obsoletos.
  • @vitest/runner queda obsoleto, y vitest ya no depende de @vitest/expect, porque el código de aserciones ahora se incluye dentro del propio vitest.
  • El proveedor @vitest/browser-webdriverio se ha trasladado a la organización vitest-community y ahora lo mantiene la comunidad.
  • workerId ahora empieza en 1.

toThrow('') ahora coincide con cualquier error lanzado. Si realmente quieres comprobar un mensaje vacío, pasa en su lugar una expresión regular como /^$/.

¿Qué cambia silenciosamente en Vitest 5?

Seis cambios de Vitest 5 no lanzan ningún error. En su lugar, una ruta, un filtro o el resultado de una coincidencia cambian por debajo de tu configuración existente.

  • Rutas de salida. Los informes blob y --merge-reports usan por defecto .vitest/blob/. Los adjuntos pasan de .vitest-attachements/ a .vitest/attachments/. Los archivos de los reporters JSON, JUnit y HTML también se guardan por defecto en .vitest.
  • Filtros -t. El separador de los filtros por nombre de test es ahora >. Revisa los scripts de CI que filtren por la ruta de la suite.
  • Locators del navegador. locators.exact está activado por defecto en Browser Mode.
  • Coincidencia de texto. toHaveTextContent es ahora estricto. toMatchTextContent es la nueva alternativa.
  • Globs de cobertura. Los patrones include y exclude se comparan ahora con la ruta de cada archivo relativa a la raíz del proyecto, y un patrón sin comodines se interpreta como una carpeta completa. El conjunto de archivos que computan para la cobertura puede cambiar, así que revisa tus umbrales tras la primera ejecución.
  • Proyectos inline. Los proyectos inline heredan ahora la configuración raíz como si se hubiera establecido extends: true.

Un paso típico de artefactos cambia así:

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

Novedades de Vitest 5 que conviene conocer

vi.when permite que un spy devuelva un resultado distinto para cada conjunto de argumentos. calledWith acepta matchers asimétricos, y las llamadas cuyos argumentos no coinciden con nada recurren a la implementación original.

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

En Browser Mode, establecer test.browser.traceView: true activa la vista de trazas. Cada interacción, aserción y llamada a page.mark se guarda como una instantánea del DOM, de modo que puedes reproducir el test paso a paso en la interfaz.

Ahora se admiten proyectos anidados, lo que ayuda a los monorepos a agrupar proyectos relacionados.

Lista de comprobación para actualizar a Vitest 5

  1. Migra los entornos de CI y locales a Node.js 22.12.0+ y Vite 6.4.0+.
  2. Ejecuta el grep anterior y añade await donde falte.
  3. Mueve todas las llamadas a vi.mock y vi.hoisted al nivel superior de su archivo.
  4. Sustituye sequential por { concurrent: false } y añade configuraciones a las carpetas de paquetes que dependían de una configuración en un directorio padre.
  5. Ejecuta la suite. Si fallan las aserciones de número de llamadas, corrígelas o establece clearMocks: false como solución temporal.
  6. Actualiza las rutas de artefactos de CI a .vitest/ y revisa los filtros -t y los umbrales de cobertura.

¿Conviene actualizar a Vitest 5 ahora o esperar?

Actualiza a Vitest 5 en este sprint si tu CI ya ejecuta Node.js 22.12.0+ y Vite 6.4.0+. La mayoría de los cambios necesarios son mecánicos.

La excepción es una suite que hace aserciones sobre historiales de llamadas de mocks que se arrastran entre tests, ya sea desde archivos de setup, desde hooks beforeAll o porque un test depende de las llamadas de otro. Esos fallos no dan ninguna pista sobre su causa, así que revisa primero esas aserciones y actualiza después. Las suites de componentes también deberían volver a ejecutar sus aserciones de texto y de locators; los patrones de testing de componentes de Svelte 5 con Vitest muestran dónde suelen aparecer.

Vitest 5 es más rápido, y la mayor parte de lo que rompe es código de test que ya era incorrecto. Empieza por el grep y por mover los vi.mock en una rama, comprueba las rutas de artefactos de CI y deja que la primera ejecución en CI te indique el resto.

Preguntas frecuentes

¿Vitest 5 también activa mockReset o restoreMocks por defecto?

No. La guía de migración de Vitest 5 cambia el valor por defecto solo de clearMocks. clearMocks llama a vi.clearAllMocks() antes de cada test y reinicia mock.calls, mock.instances, mock.contexts y mock.results, pero conserva las implementaciones. mockReset va más allá: limpia el historial y restablece cada implementación a la original, de modo que un mock creado con vi.fn(impl) vuelve a impl. restoreMocks restaura las implementaciones originales de los spies creados con vi.spyOn.

¿Por qué mi filtro -t coincide con menos tests después de actualizar a Vitest 5?

En Vitest 5, testNamePattern (el flag -t) se compara con el nombre completo del test, que se construye insertando ' > ' entre cada nombre de suite y el nombre del test. Es el mismo texto que ves en la salida del reporter. Vitest 4 usaba un único espacio entre las partes, igual que Jest. Un patrón solo deja de funcionar si abarca más de una parte del nombre. Para solucionarlo, haz que coincida con una sola parte, como -t adds, o pon un comodín entre las partes, como -t 'math.*adds'.

¿Por qué Vitest 5 no puede resolver vite después de actualizar con Yarn?

En Vitest 5, vite ha pasado de ser una dependencia directa a una peer dependency obligatoria, de modo que Vitest se ejecuta con la versión de Vite que tenga instalada tu proyecto. npm, pnpm, Bun y Deno añaden las peer dependencies automáticamente. Yarn deja ese paso en tus manos. Añade vite en la versión 6.4.0 o posterior a tu package.json y vuelve a instalar; así Vitest podrá resolverlo de nuevo.

¿Cómo combino informes de tests fragmentados (sharding) en Vitest 5?

Ejecuta cada fragmento con el reporter blob, por ejemplo vitest run --reporter=blob --shard=1/3 en la primera máquina. Cada fragmento escribe sus resultados por defecto en .vitest/blob/, y el flag --outputFile.blob permite cambiar esa ubicación. Copia el directorio de cada máquina en un job final y ejecuta vitest --merge-reports. Si tus tests guardan adjuntos como archivos, lleva también la carpeta de adjuntos al job de combinación.

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.