Mocha es un marco de pruebas de JavaScript altamente flexible y rico en características que se ejecuta tanto en Node.js como en el navegador. Su función principal es actuar como un ejecutor de pruebas, organizando y mostrando los resultados, mientras que la vlaidación real de los datos se delega a bibliotecas de aserciones externas como Chai.
Configuración del Entorno
Para comenzar a escribir pruebas, es necesario inicializar un proyecto e instalar las dependencias requeridas. Asegúrate de tener Node.js instalado en tu sistema.
mkdir mocha-testing-project
cd mocha-testing-project
npm init -y
npm install --save-dev mocha chai
Para facilitar la ejecución, puedes agregar un script en tu archivo package.json:
{
"scripts": {
"test": "mocha"
}
}
Estructura de los Scripts de Prueba
Los archivos de prueba generalmente siguen la nomenclatura del archivo original, añadiendo sufijos como .spec.js o .test.js. Mocha utiliza las funciones describe para agrupar suites de pruebas y it para definir casos de prueba individuales.
Consideremos un módulo matemático simple en geometry.js:
// geometry.js
const calculateArea = (width, height) => width * height;
module.exports = { calculateArea };
El script de prueba correspondiente, geometry.spec.js, se vería así:
// geometry.spec.js
const { expect } = require('chai');
const { calculateArea } = require('./geometry');
describe('Operaciones Geométricas', () => {
it('debería calcular el área de un rectángulo correctamente', () => {
const result = calculateArea(5, 10);
expect(result).to.equal(50);
});
});
Aserciones con Chai
Mocha no incluye un motor de aserciones integrado. Chai es una de las opciones más populares, ofreciendo un estilo expect que se lee de manera similar al lenguaje natural.
const { expect } = require('chai');
// Verificación de igualdad estricta
expect(2 * 4).to.equal(8);
expect({ id: 1 }).to.not.equal({ id: 1 }); // Diferente referencia
expect({ id: 1 }).to.deep.equal({ id: 1 }); // Igualdad profunda
// Tipos de datos
expect('cadena de texto').to.be.a('string');
expect([1, 2, 3]).to.be.an('array');
// Contenido y estados
expect({ name: 'Alice', role: 'admin' }).to.have.property('role');
expect([]).to.be.empty;
expect('framework de pruebas').to.match(/pruebas/);
Ejecución y Parámetros de CLI
Por defecto, al ejecutar npx mocha, el framework buscará archivos en el directorio test/. Sin embargo, puedes personalizar el comportamiento mediante argumentos de línea de comandos.
Para ejecutar pruebas en subdirectorios anidados, se requiere el indicador recursivo:
npx mocha --recursive
Otros parámetros útiles incluyen:
--watcho-w: Mantiene el proceso activo y vuelve a ejecutar las pruebas cuando se guardan cambios en los archivos.--bailo-b: Detiene la ejecución inmediatamente después del primer fallo.--grepo-g: Filtra y ejecuta únicamente las pruebas cuyo título coincida con el patrón proporcionado.--inverto-i: Invierte el filtro de--grep, ejecutando las pruebas que no coincidan.
Patrones de Coincidencia (Globbing)
Puedes utilizar patrones glob para apuntar a múltiples archivos específicos. Es recomendable envolver los patrones entre comillas para evitar que la shell los interprete prematuramente.
npx mocha "src/**/*.spec.js"
npx mocha "tests/unit/{auth,user}.test.js"
Configuración Moderna del Proyecto
En versiones recientes de Mocha, el archivo obsoleto mocha.opts ha sido reemplazado por archivos de configuración estructurados como .mocharc.json o .mocharc.js en la raíz del proyecto.
{
"spec": "tests/**/*.spec.js",
"recursive": true,
"reporter": "dot",
"timeout": 5000
}
Soporte para ES6+ y Transpilación
Si tu código fuente o tus pruebas utilizan módulos ES (import/export) u otras características modernas, necesitas transpilar el código sobre la marcha utilizando Babel.
npm install --save-dev @babel/core @babel/preset-env @babel/register
Crea un archivo .babelrc:
{
"presets": ["@babel/preset-env"]
}
Ejecuta Mocha requiriendo el hook de Babel:
npx mocha --require @babel/register "src/**/*.spec.js"
Manejo de Operaciones Asíncronas
Mocha maneja la asincronía de manera nativa. El tiempo de espera predeterminado es de 2000ms, pero puede ajustarse con --timeout o -t.
Usando Callbacks:
it('debería completar una operación retardada', (done) => {
let status = 'pending';
setTimeout(() => {
status = 'resolved';
expect(status).to.equal('resolved');
done(); // Indica a Mocha que la prueba ha finalizado
}, 3000);
});
Usando Promesas y Async/Await:
Si se retorna una promesa, Mocha esperará a que se resuelva o rechace. No es necesario invocar done.
it('debería procesar datos de manera asíncrona', async () => {
const fetchData = () => Promise.resolve({ code: 200 });
const response = await fetchData();
expect(response).to.have.property('code', 200);
});
Ciclo de Vida y Hooks
Los hooks permiten ejecutar lógica de configuración y limpieza en momentos específicos dentro de un bloque describe.
before(): Se ejecuta una vez antes de todas las pruebas del bloque.after(): Se ejecuta una vez después de todas las pruebas del bloque.beforeEach(): Se ejecuta antes de cada caso de prueba individual.afterEach(): Se ejecuta después de cada caso de prueba individual.
describe('Gestión de estado de base de datos', () => {
let dbConnection;
before(() => {
dbConnection = { connected: true };
});
beforeEach(() => {
dbConnection.records = [];
});
it('debería insertar un registro', () => {
dbConnection.records.push('item1');
expect(dbConnection.records).to.have.lengthOf(1);
});
after(() => {
dbConnection.connected = false;
});
});
Filtrado de Casos de Prueba
Durante el desarrollo, es común querer aislar pruebas específicas. Puedes agregar el método .only a un describe o it para ejecutar exclusivamente ese bloque.
it.only('esta será la única prueba ejecutada', () => {
expect(true).to.be.true;
});
it('esta prueba será ignorada temporalmente', () => {
expect(false).to.be.false;
});
De manera inversa, .skip permite omitir pruebas que son inestables o están pendientes de implementación.
Ejecución en el Navegador
Mocha puede ejecutarse directamente en el navegador sin necesidad de un entorno Node.js. Utiliza el comando de inicialización para generar la estructura base:
npx mocha init browser-tests
Esto genera un archivo index.html. Debes enlazar tu biblioteca de aserciones y tus scripts de prueba de la siguiente manera:
<div id="mocha"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/chai.js/4.3.4/chai.min.js"></script>
<script src="app.js"></script>
<script src="tests.js"></script>
<script>
mocha.setup('bdd');
mocha.checkLeaks();
mocha.run();
</script>
Generación de Reportes de Documentación
Mocha incluye generadores de reportes que pueden transformar los resultados de las pruebas en formatos legibles. Utilizando el reportero markdown, puedes crear documentación técnica basada directamente en las especificaciones de tus pruebas.
npx mocha --recursive --reporter markdown > API_SPECIFICATION.md