Jasmine
``
- Testing
- docs
-
Your_first_suite-your_first_suite
🧪 Introducción
-
Jasmine es un framework de testing behavior-driven development (BDD) para JavaScript, diseñado para realizar pruebas unitarias de manera sencilla, legible y sin dependencias externas. Es muy utilizado junto con Karma y otros entornos de integración continua dentro de flujos DevOps.
Su enfoque se basa en describir comportamientos esperados de una aplicación mediante bloques de código expresivos que facilitan la lectura y el mantenimiento de los tests.
⚙️ Características Principales
- Sintaxis clara y natural basada en describe / it.
- No requiere DOM ni dependencias externas.
- Permite mocks, spies y aserciones integradas.
- Compatible con frameworks como Angular o librerías puras de JavaScript.
- Integración con entornos de CI/CD y pipelines de DevOps.
- Soporta pruebas asincrónicas mediante callbacks, Promises y async/await.
🧩 Estructura Básica de un Test
Cada test en Jasmine sigue una estructura jerárquica de descripciones (suites) y especificaciones (specs).
📄 Ejemplo Básico
describe("Calculadora", () => {
it("debería sumar correctamente", () => {
const resultado = 2 + 3;
expect(resultado).toBe(5);
});
it("debería restar correctamente", () => {
const resultado = 10 - 4;
expect(resultado).toBe(6);
});
});
`
🧠 Conceptos Clave
describe(): agrupa un conjunto de pruebas relacionadas.it(): define un test individual.expect(): define la expectativa o aserción.- Matchers: expresan la condición esperada (
toBe,toEqual,toContain,toThrow, etc.).
🔍 Matchers Comunes
| Matcher | Descripción |
|---|---|
toBe(value) |
Compara por identidad (===). |
toEqual(value) |
Compara por valor. |
toBeTruthy() / toBeFalsy() |
Evalúa valores booleanos. |
toContain(item) |
Verifica si un array o string contiene un elemento. |
toThrow() |
Espera una excepción. |
toBeCloseTo(number, precision) |
Compara números flotantes. |
🧰 Spies y Mocks
Los spies permiten interceptar y observar llamadas a funciones, sin alterar su comportamiento original (a menos que se especifique).
describe("Spies en Jasmine", () => {
it("debería espiar una función", () => {
const usuario = {
saludar: (nombre) => `Hola ${nombre}`,
};
spyOn(usuario, "saludar");
usuario.saludar("Eduardo");
expect(usuario.saludar).toHaveBeenCalled();
expect(usuario.saludar).toHaveBeenCalledWith("Eduardo");
});
});
Los spies se pueden combinar con métodos como and.returnValue(), and.callFake() o and.throwError() para simular distintos comportamientos.
⏳ Tests Asincrónicos
Jasmine soporta tests con Promises, async/await o callbacks mediante la función done().
it("debería resolver una promesa correctamente", async () => {
const resultado = await Promise.resolve("ok");
expect(resultado).toBe("ok");
});
it("debería ejecutar callback async", (done) => {
setTimeout(() => {
expect(true).toBeTrue();
done();
}, 100);
});
🧮 Configuración y Ejecución
Los tests de Jasmine se pueden ejecutar en navegador o en Node.js.
- En entornos de frontend, suele integrarse con Karma.
- En Node.js, se puede instalar globalmente:
npm install --save-dev jasmine
npx jasmine init
npx jasmine
Esto genera un archivo spec/support/jasmine.json con la configuración base.
🧩 Integración con DevOps y CI/CD
- Puede integrarse en pipelines para ejecutar pruebas automáticamente antes de despliegues.
- Compatible con entornos como GitHub Actions, Jenkins, GitLab CI o CircleCI.
- Los reportes pueden exportarse en formatos JUnit, JSON o HTML para análisis continuo.
🔄 Pruebas de Componentes y Servicios (ejemplo con Angular)
En Angular, Jasmine se utiliza junto a TestBed para pruebas unitarias de componentes y servicios.
import { TestBed } from "@angular/core/testing";
import { UsuarioService } from "./usuario.service";
describe("UsuarioService", () => {
let service: UsuarioService;
beforeEach(() => {
TestBed.configureTestingModule({});
service = TestBed.inject(UsuarioService);
});
it("debería crearse correctamente", () => {
expect(service).toBeTruthy();
});
});
🌐 Recursos
- Your_first_suite
- Documentación Oficial de Jasmine
- Testing: conceptos y patrones generales
- Karma: integración y ejecución de tests
- DevOps: automatización de pipelines de testing
- JavaScript: fundamentos del lenguaje en entorno de pruebas
Jasmine - Conceptos Avanzados y Mejores Prácticas
A continuación se amplían los temas no tratados en profundidad: hooks del ciclo de vida, patrones de testing, configuración avanzada y estrategias de mantenimiento.
🔁 Ciclo de Vida de los Tests
Jasmine ofrece hooks que permiten preparar y limpiar el entorno antes y después de cada test o suite.
describe("Gestor de Usuarios", () => {
let usuarios;
beforeAll(() => {
// Se ejecuta una vez antes de todos los tests
usuarios = [];
});
beforeEach(() => {
// Se ejecuta antes de cada test
usuarios.push("nuevo");
});
afterEach(() => {
// Limpieza tras cada test
usuarios.pop();
});
afterAll(() => {
// Se ejecuta una vez al finalizar todos los tests
usuarios = null;
});
it("debería agregar un usuario", () => {
expect(usuarios.length).toBe(1);
});
});
`
Estos hooks son esenciales en pruebas con datos temporales, mocks o configuración global.
🧱 Estructura Escalable de Carpetas
Una estructura modular facilita el mantenimiento de test suites grandes.
/tests
/specs/
usuario.spec.js
auth.spec.js
utils.spec.js
/helpers/
mock-data.js
custom-matchers.js
/setup/
jasmine.json
setupEnv.js
Recomendaciones:
- Mantén un archivo
helpers/con funciones o datos reutilizables. - Crea matchers personalizados en
custom-matchers.js. - Centraliza la configuración del entorno de test (variables, spies globales, etc.) en
setupEnv.js.
🧩 Creación de Matchers Personalizados
Jasmine permite extender su sistema de aserciones con matchers propios.
beforeEach(() => {
jasmine.addMatchers({
toBeEven: () => ({
compare(actual) {
const pass = actual % 2 === 0;
return {
pass,
message: pass
? `Esperaba que ${actual} no fuera par`
: `Esperaba que ${actual} fuera par`,
};
},
}),
});
});
it("valida números pares", () => {
expect(4).toBeEven();
});
Esto resulta útil para dominios específicos (p. ej., validaciones de fechas, estructuras JSON, respuestas HTTP, etc.).
⚡ Optimización de Pruebas Asincrónicas
1. Uso combinado de done y setTimeout
Evitar el bloqueo o falsos positivos.
it("maneja retrasos en respuestas", (done) => {
fetch("/api/usuario").then((res) => {
expect(res.status).toBe(200);
done();
});
});
2. Promises y async/await
Más legibles y sin necesidad de done().
it("valida respuesta API", async () => {
const res = await fetch("/api/usuario");
const data = await res.json();
expect(data.nombre).toBeDefined();
});
🧮 Patrón “Arrange, Act, Assert” (AAA)
Organiza cada test en tres fases claras:
it("debería calcular la suma correctamente", () => {
// Arrange
const a = 5;
const b = 3;
// Act
const resultado = a + b;
// Assert
expect(resultado).toBe(8);
});
Ventajas:
- Claridad en la intención del test.
- Facilita refactorización y lectura del código.
🧰 Mocks y Spies Combinados con CallThrough
Para observar una función sin anular su comportamiento original:
const servicio = {
guardar: (item) => `Guardado: ${item}`,
};
spyOn(servicio, "guardar").and.callThrough();
it("ejecuta y espía simultáneamente", () => {
const resultado = servicio.guardar("dato");
expect(servicio.guardar).toHaveBeenCalled();
expect(resultado).toBe("Guardado: dato");
});
🧠 Tests Parametrizados
Puedes iterar sobre múltiples escenarios en una sola suite:
[
{ input: 2, output: 4 },
{ input: 3, output: 9 },
{ input: 4, output: 16 },
].forEach((caso) => {
it(`debería calcular el cuadrado de ${caso.input}`, () => {
expect(caso.input ** 2).toBe(caso.output);
});
});
🔬 Cobertura de Código con Istanbul (nyc)
Para medir qué partes del código están cubiertas por tests:
npm install --save-dev nyc
npx nyc jasmine
Esto genera un reporte en /coverage, útil en pipelines DevOps.
🧩 Integración con Karma + Navegadores
karma.conf.js puede usar Jasmine como framework base:
frameworks: ["jasmine"],
files: ["src/**/*.js", "tests/**/*.spec.js"],
browsers: ["ChromeHeadless"],
reporters: ["progress", "kjhtml"],
Esto permite ejecutar los tests en entornos de navegador reales o headless (sin UI).
🧱 Buenas Prácticas
- Usa nombres descriptivos:
it("debería mostrar error si el email es inválido"). - Mantén los tests independientes entre sí.
- Evita lógica compleja dentro de los tests.
- Reutiliza fixtures o factories para generar datos de prueba.
- Desactiva funciones de red o base de datos real mediante mocks.
🧠 Estrategias de Escalabilidad
En proyectos grandes:
- Agrupa suites por dominio funcional.
- Automatiza la ejecución con watchers (
npm run test:watch). - Integra en pipelines de despliegue continuo.
- Configura reportes HTML o JUnit para análisis visual o integración con herramientas como SonarQube.
🌐 Recursos Adicionales
- Testing: Patrones y arquitecturas de pruebas.
- Karma: Ejecución distribuida de tests en navegadores.
- DevOps: Automatización e integración en pipelines.
- JavaScript: Patrones modernos aplicados al testing.
- Custom Matchers - Jasmine Docs
- Best Practices for Jasmine Testing
Jasmine - Casos Reales, Integraciones y Patrones Avanzados
$= dv.current().file.tags.join(“ “)
🧩 Temas Pendientes y Expansión
En esta nota se profundiza en aspectos no cubiertos previamente:
patrones avanzados, integración con frameworks modernos, pruebas de eventos, time mocking, seguridad en tests, depuración y uso en entornos híbridos (browser + Node.js).
⚙️ Integración con Frameworks Modernos
🔹 Angular
Ya se mostró un ejemplo básico, pero en entornos reales se combinan Jasmine + TestBed con spy providers:
import { TestBed } from "@angular/core/testing";
import { HttpClientTestingModule, HttpTestingController } from "@angular/common/http/testing";
import { UsuarioService } from "./usuario.service";
describe("UsuarioService", () => {
let service: UsuarioService;
let httpMock: HttpTestingController;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [HttpClientTestingModule],
providers: [UsuarioService],
});
service = TestBed.inject(UsuarioService);
httpMock = TestBed.inject(HttpTestingController);
});
it("debería obtener lista de usuarios", () => {
const mockUsuarios = [{ nombre: "Eduardo" }];
service.obtenerUsuarios().subscribe((data) => {
expect(data).toEqual(mockUsuarios);
});
const req = httpMock.expectOne("/api/usuarios");
expect(req.request.method).toBe("GET");
req.flush(mockUsuarios);
});
});
`
Esto demuestra cómo Jasmine puede integrarse profundamente en entornos de testing de componentes y servicios.
🔹 React
Aunque no es el estándar (donde se usa Jest), Jasmine puede funcionar con herramientas como Enzyme o Testing Library si se configura el entorno manualmente.
import React from "react";
import { render, screen } from "@testing-library/react";
import App from "./App";
describe("App Component", () => {
it("renderiza el título principal", () => {
render(<App />);
expect(screen.getByText(/Bienvenido/i)).toBeTruthy();
});
});
🕒 Time Mocking y Control del Tiempo
Jasmine permite simular y manipular temporizadores, útil para probar delays, intervalos y funciones dependientes de tiempo.
describe("Timers con Jasmine", () => {
beforeEach(() => {
jasmine.clock().install();
});
afterEach(() => {
jasmine.clock().uninstall();
});
it("controla el tiempo con jasmine.clock()", () => {
const callback = jasmine.createSpy("callback");
setTimeout(callback, 1000);
jasmine.clock().tick(1000);
expect(callback).toHaveBeenCalled();
});
});
🔍 Tests de Eventos y DOM (sin navegador real)
En entornos de navegador simulado (por ejemplo con jsdom), Jasmine puede validar eventos sin depender de Karma:
describe("Eventos DOM", () => {
it("detecta click en botón", () => {
const button = document.createElement("button");
let clicked = false;
button.addEventListener("click", () => (clicked = true));
button.click();
expect(clicked).toBeTrue();
});
});
🧱 Pruebas de Integración entre Módulos
Jasmine también puede orquestar pruebas entre diferentes capas (controladores, servicios, utilidades).
import { obtenerUsuario, formatearUsuario } from "../src/usuario";
describe("Integración de módulos", () => {
it("debería formatear el nombre del usuario correctamente", async () => {
const usuario = await obtenerUsuario(1);
const nombre = formatearUsuario(usuario);
expect(nombre).toMatch(/^[A-Z]/);
});
});
Estas pruebas no son unitarias, pero garantizan coherencia entre funciones interdependientes.
🔒 Testing y Seguridad
1. Validación de Inputs
describe("Validación de inputs", () => {
it("debería rechazar valores inseguros", () => {
const input = "<script>alert('xss')</script>";
const resultado = sanitizar(input);
expect(resultado).not.toContain("<script>");
});
});
2. Mock de Tokens o Sesiones
beforeEach(() => {
spyOn(localStorage, "getItem").and.returnValue("fake-token");
});
Evita exponer credenciales o datos reales en los tests.
🧠 Patrón Given-When-Then (Behavior-Driven)
Una extensión del AAA, útil para documentación y claridad:
describe("Login de usuario", () => {
it("debería autenticar con credenciales válidas", () => {
// Given
const credenciales = { user: "admin", pass: "1234" };
// When
const resultado = login(credenciales);
// Then
expect(resultado).toBeTrue();
});
});
Esto alinea los tests con el lenguaje del dominio y mejora la comunicación con equipos no técnicos.
🧩 Mocking de Módulos Externos
Si tu código usa APIs o librerías externas, Jasmine puede reemplazarlas temporalmente:
import * as api from "../api";
describe("Mock de módulos externos", () => {
it("intercepta llamada externa", async () => {
spyOn(api, "fetchData").and.returnValue(Promise.resolve({ ok: true }));
const data = await api.fetchData();
expect(data.ok).toBeTrue();
});
});
🔎 Depuración y Logs
Durante el desarrollo de tests complejos:
- Usa
console.log()dentro de bloquesit()(Jasmine no los bloquea). - Usa
fit()para ejecutar solo un test. - Usa
fdescribe()para ejecutar solo una suite. - Usa
xit()oxdescribe()para ignorar temporalmente tests.
fdescribe("Debugging activo", () => {
it("solo este test se ejecuta", () => {
console.log("Test en foco");
expect(true).toBeTrue();
});
});
⚡ Integración con Node.js y ESM
Jasmine 5+ soporta módulos ECMAScript nativamente:
npm install jasmine --save-dev
npx jasmine --esm
Y permite import/export directamente:
import { sumar } from "../src/utils.js";
describe("Suma con ESM", () => {
it("funciona con import/export", () => {
expect(sumar(2, 2)).toBe(4);
});
});
📦 Ejecución Paralela y Optimización de Suites
En entornos grandes, Jasmine puede dividir suites en ejecuciones paralelas con herramientas externas (p. ej., karma-parallel o jest-worker):
- Mejora el rendimiento en pipelines CI.
- Reduce tiempos de feedback para los desarrolladores.
- Permite balancear la carga entre procesos o contenedores Docker.
🧮 Integración con DevOps Metrics y Reportes
- Generación automática de reportes HTML, JSON o JUnit.
- Integración con dashboards de calidad de código (SonarQube, Codecov, GitHub Actions).
- Configuración de thresholds de cobertura mínima:
npx nyc --check-coverage --lines 80 --functions 85 --branches 70 jasmine
Esto obliga a mantener una cobertura mínima en el proyecto antes del merge.
🧭 Estrategias de Migración
De Jasmine a Jest (o viceversa)
- Los matchers y estructura son casi idénticos.
- Spies →
jest.fn() - Jasmine → mejor para entornos legacy o Angular.
- Jest → preferido en ecosistemas modernos y monorepos.
Ejemplo de conversión rápida:
// Jasmine
spyOn(servicio, "getData").and.returnValue(of("ok"));
// Jest
jest.spyOn(servicio, "getData").mockReturnValue(of("ok"));
🧰 Recomendaciones Finales
- Mantén suites cortas (<50 tests por archivo).
- Evita mocks excesivos (solo cuando sea necesario).
- Mide la flakiness (tests intermitentes) en CI.
- Documenta los matchers personalizados.
- Usa Jasmine no solo como herramienta de validación, sino como especificación viva del sistema.
🌐 Recursos Relacionados
- Testing – Estrategias de diseño y mantenimiento.
- Karma – Ejecución distribuida y reporter plugins.
- DevOps – Integración continua y monitoreo de calidad.
- JavaScript – Buenas prácticas y patrones.
- Jasmine Clock API Docs
- Testing Library Integration
¿Te gusta este contenido? Suscríbete vía RSS