Notas prácticas: El ejecutor de pruebas nativo de Node frente a Jest y Vitest: una suite, tres opciones
Guía práctica paso a paso: el ejecutor de pruebas nativo de Node frente a Jest y Vitest: una suite, tres opciones —contratos, verificaciones y espacios para código adicional— para los equipos que implementan este patrón.
Úselo como una versión reestructurada dirigida a los operadores de las ideas presentadas en “Node’s Native Test Runner vs Jest vs Vitest: One Suite, Three Runners, Real Timings”: etapas claras, secciones de código ordenadas y notas de recuperación que perduran tras la transferencia de tareas. La etapa de Resumen funciona mejor cuando se considera una superficie medible. Capture una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace completaciones parciales silenciosas.
Los tres ejecutores, honestamente
Para los tres escenarios de ejecución, defina primero las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso desde un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el flujo pasa de entornos de demostración a entornos compartidos. Coloque el estado junto al componente que es responsable de la mutación; llevar todo a un almacén global hace que los errores relacionados con los tiempos de ejecución sean más difíciles de detectar.
1. node:test, la opción aburrida pero efectiva
Para la prueba de 1 nodo, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben encontrarse en un único lugar que los operadores puedan auditar sin necesidad de leer todo el sistema. Coloque el estado junto al componente que gestiona la mutación. Al llevar todo a un almacén global, resulta más difícil detectar errores relacionados con los tiempos de ejecución.
// node-test/test/string-utils.test.js
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
assert.equal(slugify('Hello World'), 'hello-world');
});
it('strips diacritics', () => {
assert.equal(slugify('Café résumé'), 'cafe-resume');
});
it('throws TypeError on non-string input', () => {
assert.throws(() => slugify(123), TypeError);
});
});
# Run it, no install step
node --test node-test/test/*.test.js
# Watch mode
node --test --watch node-test/test/*.test.js
# Coverage (still experimental, but the numbers are real V8 counts)
node --test --experimental-test-coverage \
--test-coverage-include='src/**/*.js' \
node-test/test/*.test.js
2. Jest, la opción predeterminada que ha estado utilizando
En la etapa predeterminada de 2 Jest, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Coloque el estado junto con el componente que gestiona la mutación. Elevar todo a un almacén global hace que los errores de sincronización sean más difíciles de detectar. En la etapa predeterminada de 2 Jest, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
// jest/test/string-utils.test.js
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
expect(slugify('Hello World')).toBe('hello-world');
});
it('strips diacritics', () => {
expect(slugify('Café résumé')).toBe('cafe-resume');
});
it('throws TypeError on non-string input', () => {
expect(() => slugify(123)).toThrow(TypeError);
});
});
// jest/jest.config.js, minimal. Run it with NODE_OPTIONS=--experimental-vm-modules
export default {
rootDir: '.',
testMatch: ['<rootDir>/test/**/*.test.js'],
testEnvironment: 'node',
verbose: true,
};
# Run (the flag is required for native ESM)
NODE_OPTIONS=--experimental-vm-modules npx jest --config jest/jest.config.js
# Watch
NODE_OPTIONS=--experimental-vm-modules npx jest --config jest/jest.config.js --watch
3. Vitest, la nueva opción predeterminada, con una contrapartida
Al trabajar en la nueva etapa de 3 Vitest, anote primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación ayuda a mantener honestas las futuras modificaciones del código. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando se pasa de entornos de demostración a entornos compartidos. Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.
// vitest/test/string-utils.test.js
import { describe, it, expect } from 'vitest';
import { slugify } from '../../src/string-utils.js';
describe('slugify', () => {
it('converts a basic sentence', () => {
expect(slugify('Hello World')).toBe('hello-world');
});
it('strips diacritics', () => {
expect(slugify('Café résumé')).toBe('cafe-resume');
});
it('throws TypeError on non-string input', () => {
expect(() => slugify(123)).toThrow(TypeError);
});
});
// vitest/vitest.config.mjs
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
include: ['test/**/*.test.js'],
environment: 'node',
coverage: { provider: 'v8', include: ['../src/**/*.js'] },
},
});
# Run
cd vitest && npx vitest run
# Watch (this is the killer feature)
cd vitest && npx vitest
# Coverage
cd vitest && npx vitest run --coverage
La metodología, para que pueda llamarla tontería
Al trabajar con la metodología, escribe primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación garantiza que los cambios posteriores en el código sean transparentes. Mantén la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el código. Considera los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.
# Reproduce on your own machine
git clone https://github.com/manisuec/techinsights-tutorials
cd techinsights-tutorials/nodejs-test-runner
npm install
bash shared/bench.sh 5 # cold runs
WARM=1 bash shared/bench.sh 5 # warm runs
Los números reales
Al trabajar en la etapa de los números reales, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Documente tanto el camino óptimo como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no de mejoras posteriores. Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización. Al trabajar en la etapa de los números reales, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
=== node:test (Node v24.14.0) [cold] ===
run 1: 91 ms
run 2: 93 ms
run 3: 89 ms
run 4: 90 ms
run 5: 90 ms
median: 90 ms
=== Jest (30.4.1) [cold] ===
run 1: 817 ms
run 2: 689 ms
run 3: 718 ms
run 4: 711 ms
run 5: 685 ms
median: 711 ms
=== Vitest (4.1.11) [cold] ===
run 1: 548 ms
run 2: 648 ms
run 3: 534 ms
run 4: 531 ms
run 5: 535 ms
median: 535 ms
Matriz de funcionalidades, 2026, última vez que la revisó
La matriz de características de la última etapa de 2026 funciona mejor cuando se trata como una superficie medible. Capture un transcripte ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto a los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos. Mantenga los procesos de renderizado económicos y posponga las derivaciones costosas a la memorización solo después de realizar mediciones. La memorización prematura puede ocultar errores en los valores utilizados.
Cuándo elegir cada uno
La decisión sobre qué etapa elegir funciona mejor si se trata como una superficie medible. Capture una transcripción ejemplar, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Haga que el proceso de renderizado sea económico y posponga las derivaciones costosas a la memorización solo después de realizar mediciones. Una memorización prematura puede ocultar errores en los propios.
Migrando de Jest a Vitest en 30 minutos
Migrar de Jest a stage funciona mejor cuando se trata como un área medible. Capture una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino exitoso como el de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Mantenga los procesos de renderizado económicos y posponga las derivaciones costosas a la memorización solo después de realizar mediciones; una memorización prematura puede ocultar errores en los propios. Migrar de Jest a stage funciona mejor cuando se trata como un área medible. Capture una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Considere esta etapa como un contrato entre las entradas y las salidas validadas. Asigne nombres a los artefactos, defina verificaciones de éxito y evite completaciones parciales silenciosas.
# 1. Install
npm install -D vitest
# 2. Add a config (or piggyback on vite.config.ts if you have one)
# vitest.config.ts
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
globals: true, // makes describe/it/expect global
environment: 'jsdom', // or 'node' for backend
setupFiles: ['./tests/setup.ts'],
},
});
# 3. Swap imports, find/replace in your editor
# jest.mock → vi.mock
# jest.fn → vi.fn
# jest.spyOn → vi.spyOn
# require('@jest/globals') → require('vitest')
# jest.useFakeTimers() → vi.useFakeTimers()
# 4. Swap npm scripts
# "test": "jest" → "test": "vitest run"
# "test:watch": "jest --watch" → "test:watch": "vitest"
# 5. If you used babel-jest, delete it and babel.config.js
# 6. Run. Fix the 3-5 things that fail. Drink coffee.
Qué no debería hacer
Para lo que no se ejecutaría en producción, defina las entradas, el responsable de la etapa y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la etapa desde un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. La visibilidad temprana del costo evita facturas inesperadas cuando el flujo pasa de entornos de demostración a entornos compartidos. Asocie el estado al componente que es responsable de la mutación; llevar todo a un almacén global hace que los errores relacionados con los tiempos de ejecución sean más difíciles de detectar.
El veredicto
En la fase de veredicto, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido, sin tener que adivinar el estado oculto. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin necesidad de leer todo el sistema. Coloque el estado junto al componente que es responsable de la mutación. Al llevar todo a un almacén global, resulta más difícil detectar errores relacionados con los tiempos de ejecución.
Apéndice: cómo interpretar las cifras en esta publicación
En el Apéndice sobre cómo leer la etapa, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Asocie el estado al componente que es responsable de la mutación. Levantar todo a un almacenamiento global hace que los errores de sincronización sean más difíciles de detectar. En el Apéndice sobre cómo leer la etapa, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Trate esta etapa como un contrato entre las entradas y los resultados validados. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
Lista de verificación operativa
Al trabajar en la fase de lista de verificación operativa, anote primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista mantiene honestas las futuras modificaciones del código.
Prefiera unidades pequeñas y verificables a scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.
Fije las versiones de las dependencias y registre el resumen de la imagen que se utilizó en la demostración. La reproducibilidad es mejor que el conocimiento tribal.
Considere esta fase como un contrato entre los datos de entrada y las salidas validadas. Asigne nombres a los artefactos, defina comprobaciones de éxito y rechace las completaciones parciales silenciosas.
Trate los efectos como una sincronización con el mundo exterior, y no como un sustituto de los valores derivados durante la renderización.
Antes de promover la pila, congele las versiones, capture una transcripción de referencia para el camino crítico y confirme los pasos de reversión. Los entornos compartidos necesitan límites de velocidad, verificaciones de tenencia y un propietario claro para la rotación de secretos. Prefiera una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.
Nota por lotes para b78b143fb7a9: mantenga las claves del proveedor fuera del repositorio, establezca un límite máximo para tokens por sesión y almacene las transcripciones junto a los fixtures de evaluación para que los cambios posteriores en el modelo sigan siendo comparables.
Lecturas relacionadas
- Sustituyendo Jest por el ejecutor de pruebas nativo de Node en Node 24 — Una migración real muestra cómo el ejecutor de pruebas integrado en Node 24 y el soporte nativo para TypeScript reducen el tiempo de CI al mismo tiempo que se eliminan cuatro dependencias.
- Notas prácticas: MTG Bench: Por qué probar LLMs en Magic: The Gathering es un — Una guía detallada de las Notas prácticas: MTG Bench: Por qué probar LLMs en Magic: The Gathering es un: contratos, verificaciones y espacios de código listos para usar para los equipos que implementan este patrón.