Vitest como test runner moderno
Vitest es un test runner construido sobre Vite que ejecuta directamente TypeScript y ESM sin paso de compilación previo. Hereda la configuración de Vite si existe, lo que permite reutilizar alias, plugins y transformadores del mismo pipeline que sirve la aplicación.
La instalación es mínima:
npm install -D vitest
El comando vitest arranca en watch mode por defecto y recorre ficheros con extensiones *.test.ts o *.spec.ts. Para una sola pasada se usa vitest run.
{
"scripts": {
"test": "vitest",
"test:run": "vitest run",
"test:coverage": "vitest run --coverage"
}
}
La API de Vitest replica deliberadamente la de Jest: describe, it, expect y los hooks beforeEach, afterEach, beforeAll y afterAll tienen el mismo comportamiento, facilitando la migración.
Estructura de un test con Vitest
Un test describe un escenario, ejecuta código y comprueba el resultado con un matcher. Los helpers clave se importan desde vitest.
// src/carrito.ts
export type Articulo = { id: string; precio: number; cantidad: number }
export function totalCarrito(articulos: Articulo[]): number {
return articulos.reduce((suma, a) => suma + a.precio * a.cantidad, 0)
}
// src/carrito.test.ts
import { describe, it, expect } from "vitest"
import { totalCarrito } from "./carrito"
describe("totalCarrito", () => {
it("suma correctamente precios por cantidad", () => {
const resultado = totalCarrito([
{ id: "a", precio: 10, cantidad: 2 },
{ id: "b", precio: 5, cantidad: 3 }
])
expect(resultado).toBe(35)
})
it("devuelve 0 con carrito vacio", () => {
expect(totalCarrito([])).toBe(0)
})
})
El watch mode ejecuta únicamente los tests afectados por el último cambio, lo que reduce drásticamente la latencia en proyectos grandes.
Hooks y fixtures tipadas
Vitest permite compartir estado entre tests con hooks y, desde versiones recientes, con test.extend para definir fixtures tipadas al estilo Playwright.
import { beforeEach, describe, expect, test as base } from "vitest"
type Contexto = {
carrito: Articulo[]
}
const test = base.extend<Contexto>({
carrito: async ({}, use) => {
const items: Articulo[] = [
{ id: "a", precio: 10, cantidad: 1 }
]
await use(items)
}
})
describe("carrito", () => {
test("empieza con un articulo", ({ carrito }) => {
expect(carrito).toHaveLength(1)
})
})
Mocking con vi
El objeto vi agrupa utilidades de mocking. Las más usadas son vi.fn para crear funciones espía y vi.mock para sustituir un módulo entero.
import { describe, it, expect, vi } from "vitest"
vi.mock("./correo", () => ({
enviar: vi.fn().mockResolvedValue({ ok: true })
}))
import { enviar } from "./correo"
import { registrarUsuario } from "./registro"
describe("registrarUsuario", () => {
it("envia correo de bienvenida", async () => {
await registrarUsuario({ email: "u@ejemplo.com" })
expect(enviar).toHaveBeenCalledWith(expect.objectContaining({
destino: "u@ejemplo.com"
}))
})
})
La cobertura se activa con la bandera --coverage y por defecto usa el motor v8, integrado en Node.js. Los informes se generan en coverage/ con formato HTML navegable.
Biome como linter y formateador unificado
Biome es una cadena de herramientas escrita en Rust que reemplaza a ESLint y Prettier con un único binario. Ofrece un formateador opinado, un linter con reglas para JavaScript, TypeScript, JSX y JSON, y un modo de organización automática de imports.
npm install -D --save-exact @biomejs/biome
npx biome init
El comando init genera un biome.json con la configuración por defecto:
{
"$schema": "https://biomejs.dev/schemas/latest/schema.json",
"files": {
"includes": ["**/*.ts", "**/*.tsx", "**/*.json"]
},
"formatter": {
"enabled": true,
"indentStyle": "space",
"indentWidth": 4,
"lineWidth": 100
},
"linter": {
"enabled": true,
"rules": {
"recommended": true
}
},
"assist": {
"actions": {
"source": {
"organizeImports": "on"
}
}
}
}
El binario expone comandos concisos para cada fase del ciclo:
npx biome format --write .
npx biome lint .
npx biome check --write .
El subcomando check combina lint, formato y organización de imports en una sola pasada, y es la orden recomendada para hooks de pre-commit y pipelines de integración continua.
Ventajas frente a ESLint + Prettier
La propuesta de Biome no es aportar más reglas, sino aportar la misma función con otras propiedades operativas:
- Ejecución en Rust, varios órdenes de magnitud más rápida que cadenas basadas en Node.js
- Configuración con un único fichero, sin conflictos entre linter y formateador
- Instalación con una sola dependencia, sin gestión de plugins
- Compatibilidad creciente con reglas equivalentes a
typescript-eslint
Biome cubre el 80 por ciento de los casos del día a día. Proyectos con reglas muy específicas de ESLint pueden necesitar complementarlo. Muchos equipos ejecutan Biome para formato y lint básico y reservan ESLint para reglas personalizadas o para las heurísticas type-aware más elaboradas.
Oxlint como alternativa enfocada en linting
Oxlint es otro linter en Rust, más reciente, centrado exclusivamente en análisis estático. Se integra cómodamente junto a Prettier o junto a Biome en modo solo formateador. Oxlint se posiciona como un acelerador del flujo actual: ejecuta miles de reglas en milisegundos y no requiere migración de configuración. Los proyectos lo adoptan como primer filtro y dejan las reglas complejas de ESLint para una segunda pasada.
Integración en un proyecto TypeScript
Un proyecto típico combina Vitest para pruebas y Biome para calidad:
{
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"test": "vitest",
"test:run": "vitest run",
"lint": "biome check --write .",
"format": "biome format --write ."
}
}
El bucle de desarrollo queda corto: al guardar un fichero, el IDE con LSP de TypeScript avisa de errores de tipo, Vitest ejecuta los tests afectados y Biome formatea y corrige lo corregible. La cadena clásica de Jest más ESLint más Prettier se reduce a dos herramientas con configuración mínima.
Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, TypeScript es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de TypeScript
Explora más contenido relacionado con TypeScript y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
Configurar Vitest para proyectos TypeScript sin compilación previa. Escribir tests unitarios con expect, describe y fixtures. Aplicar mocking con vi.fn y vi.mock. Configurar Biome como alternativa unificada a ESLint y Prettier. Entender las ventajas en velocidad y ergonomía respecto a las cadenas clásicas.