_
__HTML_TAG_66_Mocha - Pruebas de JavaScript sencillas, flexibles y divertidas
Mocha es un marco de prueba JavaScript rico en funciones que funciona en Node.js y en el navegador, haciendo pruebas asincrónicas simple y divertida. Las pruebas de Mocha se ejecutan en serie, lo que permite la presentación de informes flexibles y precisos, mientras se registran excepciones no traídas a los casos de prueba correctos.
__HTML_TAG_71_
__HTML_TAG_72_ Todos los comandos_HTML_TAG_73__
# Initialize new projectmkdirmy-mocha-project
cdmy-mocha-project
npminit-y
# Install dependenciesnpminstall--save-devmochachai
# Create test directorymkdirtest# Create first test filetouchtest/test.js
// lib/calculator.jsfunctionadd(a,b){returna+b;}functionsubtract(a,b){returna-b;}functionmultiply(a,b){returna*b;}functiondivide(a,b){if(b===0){thrownewError('Division by zero');}returna/b;}module.exports={add,subtract,multiply,divide};
// test/calculator.test.jsconst{expect}=require('chai');const{add,subtract,multiply,divide}=require('../lib/calculator');describe('Calculator',function(){describe('Addition',function(){it('should add two positive numbers',function(){expect(add(2,3)).to.equal(5);});it('should add negative numbers',function(){expect(add(-2,-3)).to.equal(-5);});it('should add zero',function(){expect(add(5,0)).to.equal(5);});});describe('Division',function(){it('should divide positive numbers',function(){expect(divide(10,2)).to.equal(5);});it('should throw error for division by zero',function(){expect(()=>divide(10,0)).to.throw('Division by zero');});});});
# Run all testsnpmtest# Run specific test filenpxmochatest/calculator.test.js
# Run tests with patternnpxmochatest/**/*.test.js
# Run tests with grepnpxmocha--grep"Addition"# Run tests in watch modenpxmocha--watch
# Run tests with reporternpxmocha--reporterjson
// Test suitedescribe('Feature Name',function(){// Test caseit('should do something',function(){// Test implementation});// Pending testit('should do something else');// Skipped testit.skip('should skip this test',function(){// This won't run});// Only run this testit.only('should only run this test',function(){// Only this test will run});});
describe('User Management',function(){describe('User Creation',function(){it('should create a new user',function(){// Test implementation});it('should validate user data',function(){// Test implementation});});describe('User Authentication',function(){it('should authenticate valid user',function(){// Test implementation});it('should reject invalid credentials',function(){// Test implementation});});});
describe('API',function(){describe('Users Endpoint',function(){describe('GET /users',function(){it('should return all users',function(){// Test implementation});it('should return 200 status',function(){// Test implementation});});describe('POST /users',function(){it('should create new user',function(){// Test implementation});it('should return 201 status',function(){// Test implementation});});});});
describe('User Service',function(){context('when user exists',function(){it('should return user data',function(){// Test implementation});it('should update user successfully',function(){// Test implementation});});context('when user does not exist',function(){it('should return null',function(){// Test implementation});it('should throw error on update',function(){// Test implementation});});});
describe('Database Tests',function(){// Runs once before all tests in this describe blockbefore(function(){console.log('Setting up database connection');// Setup code here});// Runs once after all tests in this describe blockafter(function(){console.log('Closing database connection');// Cleanup code here});// Runs before each test in this describe blockbeforeEach(function(){console.log('Preparing test data');// Setup for each test});// Runs after each test in this describe blockafterEach(function(){console.log('Cleaning up test data');// Cleanup after each test});it('should save user',function(){// Test implementation});it('should find user',function(){// Test implementation});});
describe('Async Setup',function(){before(asyncfunction(){this.timeout(5000);// Increase timeout for setup// Async setupthis.database=awaitconnectToDatabase();this.server=awaitstartServer();});after(asyncfunction(){// Async cleanupawaitthis.database.close();awaitthis.server.stop();});beforeEach(asyncfunction(){// Clear database before each testawaitthis.database.clear();// Seed test dataawaitthis.database.seed({users:[{name:'John',email:'john@example.com'},{name:'Jane',email:'jane@example.com'}]});});it('should find users',asyncfunction(){constusers=awaitthis.database.findAll('users');expect(users).to.have.length(2);});});
describe('Conditional Setup',function(){before(function(){if(process.env.NODE_ENV==='test'){// Only run in test environmentthis.mockServer=startMockServer();}});beforeEach(function(){// Skip setup for specific testsif(this.currentTest.title.includes('integration')){this.skip();}});it('should run unit test',function(){// This will run});it('should run integration test',function(){// This will be skipped by beforeEach});});
const{expect}=require('chai');describe('Chai Assertions',function(){it('should test equality',function(){expect(2+2).to.equal(4);expect({name:'John'}).to.deep.equal({name:'John'});expect([1,2,3]).to.deep.equal([1,2,3]);});it('should test truthiness',function(){expect(true).to.be.true;expect(false).to.be.false;expect(null).to.be.null;expect(undefined).to.be.undefined;expect('hello').to.exist;});it('should test types',function(){expect('hello').to.be.a('string');expect(42).to.be.a('number');expect([]).to.be.an('array');expect({}).to.be.an('object');expect(()=>{}).to.be.a('function');});it('should test properties',function(){constobj={name:'John',age:30};expect(obj).to.have.property('name');expect(obj).to.have.property('age',30);expect(obj).to.have.all.keys('name','age');});it('should test arrays',function(){constarr=[1,2,3,4,5];expect(arr).to.have.length(5);expect(arr).to.include(3);expect(arr).to.include.members([2,4]);expect(arr).to.have.ordered.members([1,2,3,4,5]);});it('should test strings',function(){expect('hello world').to.contain('world');expect('hello world').to.match(/^hello/);expect('hello world').to.have.length(11);});});
const{expect}=require('chai');// Extend Chai with custom assertionchai.use(function(chai,utils){chai.Assertion.addMethod('validEmail',function(){constobj=this._obj;constemailRegex=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;this.assert(emailRegex.test(obj),'expected #{this} to be a valid email','expected #{this} not to be a valid email');});});describe('Custom Assertions',function(){it('should validate email addresses',function(){expect('user@example.com').to.be.validEmail;expect('invalid-email').to.not.be.validEmail;});});
constshould=require('chai').should();describe('Should Style',function(){it('should use should syntax',function(){constuser={name:'John',age:30};user.should.be.an('object');user.should.have.property('name','John');user.age.should.equal(30);constnumbers=[1,2,3];numbers.should.have.length(3);numbers.should.include(2);});});
constassert=require('chai').assert;describe('Assert Style',function(){it('should use assert syntax',function(){constuser={name:'John',age:30};assert.isObject(user);assert.property(user,'name');assert.equal(user.name,'John');assert.equal(user.age,30);constnumbers=[1,2,3];assert.lengthOf(numbers,3);assert.include(numbers,2);});});
describe('Promise Testing',function(){it('should resolve promise',function(){returnfetchUser(1).then(user=>{expect(user.name).to.equal('John');});});it('should reject promise',function(){returnfetchUser(-1).catch(error=>{expect(error.message).to.equal('User not found');});});it('should use async/await',asyncfunction(){constuser=awaitfetchUser(1);expect(user.name).to.equal('John');});it('should handle async errors',asyncfunction(){try{awaitfetchUser(-1);thrownewError('Should have thrown');}catch(error){expect(error.message).to.equal('User not found');}});});
describe('Timeout Testing',function(){// Set timeout for entire suitethis.timeout(5000);it('should complete within timeout',function(done){// Set timeout for specific testthis.timeout(2000);setTimeout(()=>{expect(true).to.be.true;done();},1000);});it('should handle slow operations',asyncfunction(){this.timeout(10000);constresult=awaitslowOperation();expect(result).to.exist;});it('should disable timeout',function(done){this.timeout(0);// Disable timeout// Very slow operationsetTimeout(done,30000);});});
describe('Retry Testing',function(){// Retry failed teststhis.retries(3);it('should retry flaky test',function(){// This test might fail randomlyif(Math.random()<0.7){thrownewError('Random failure');}expect(true).to.be.true;});it('should retry specific test',function(){this.retries(5);// Test implementation});});
// test/helpers/setup.jsprocess.env.NODE_ENV='test';process.env.DATABASE_URL='mongodb://localhost:27017/test';process.env.API_URL='http://localhost:3001';// Load environment-specific configif(process.env.CI){// CI-specific setupprocess.env.TIMEOUT='10000';}else{// Local development setupprocess.env.TIMEOUT='5000';}
// reporters/file-reporter.jsconstfs=require('fs');constpath=require('path');functionFileReporter(runner,options){constreportPath=options.reporterOptions?.output||'test-results.json';constresults={stats:{},tests:[],failures:[]};runner.on('start',function(){results.stats.start=newDate();});runner.on('pass',function(test){results.tests.push({title:test.title,fullTitle:test.fullTitle(),duration:test.duration,state:'passed'});});runner.on('fail',function(test,err){results.tests.push({title:test.title,fullTitle:test.fullTitle(),duration:test.duration,state:'failed',error:err.message});results.failures.push({title:test.fullTitle(),error:err.message,stack:err.stack});});runner.on('end',function(){results.stats.end=newDate();results.stats.duration=results.stats.end-results.stats.start;results.stats.passes=runner.stats.passes;results.stats.failures=runner.stats.failures;fs.writeFileSync(reportPath,JSON.stringify(results,null,2));console.log(`Report written to ${reportPath}`);});}module.exports=FileReporter;
<!-- test/browser/index.html --><!DOCTYPE html><html><head><title>Mocha Browser Tests</title><linkrel="stylesheet"href="https://unpkg.com/mocha/mocha.css"></head><body><divid="mocha"></div><!-- Mocha --><scriptsrc="https://unpkg.com/mocha/mocha.js"></script><!-- Chai --><scriptsrc="https://unpkg.com/chai/chai.js"></script><!-- Setup --><script>mocha.setup('bdd');constexpect=chai.expect;</script><!-- Your code --><scriptsrc="../lib/calculator.js"></script><!-- Your tests --><scriptsrc="calculator.test.js"></script><!-- Run tests --><script>mocha.run();</script></body></html>
Archivo de prueba de exploradores
// test/browser/calculator.test.jsdescribe('Calculator (Browser)',function(){it('should add numbers',function(){expect(add(2,3)).to.equal(5);});it('should work with DOM',function(){constdiv=document.createElement('div');div.textContent='Hello World';document.body.appendChild(div);expect(div.textContent).to.equal('Hello World');document.body.removeChild(div);});it('should test localStorage',function(){localStorage.setItem('test','value');expect(localStorage.getItem('test')).to.equal('value');localStorage.removeItem('test');});});
// test/browser/puppeteer.test.jsconstpuppeteer=require('puppeteer');const{expect}=require('chai');describe('Browser Tests with Puppeteer',function(){letbrowser,page;before(asyncfunction(){browser=awaitpuppeteer.launch();page=awaitbrowser.newPage();});after(asyncfunction(){awaitbrowser.close();});it('should run tests in browser',asyncfunction(){awaitpage.goto('file://'+__dirname+'/index.html');// Wait for tests to completeawaitpage.waitForFunction(()=>{returnwindow.mochaResults&&window.mochaResults.complete;});constresults=awaitpage.evaluate(()=>window.mochaResults);expect(results.failures).to.equal(0);});});
constsinon=require('sinon');const{expect}=require('chai');describe('Mocking with Sinon',function(){afterEach(function(){sinon.restore();});it('should mock functions',function(){constcallback=sinon.fake();constproxy=sinon.fake.returns(42);callback('hello','world');expect(callback.calledWith('hello','world')).to.be.true;expect(proxy()).to.equal(42);});it('should stub methods',function(){constuser={getName:()=>'John',setName:(name)=>{this.name=name;}};conststub=sinon.stub(user,'getName').returns('Jane');expect(user.getName()).to.equal('Jane');expect(stub.calledOnce).to.be.true;});it('should spy on methods',function(){constuser={getName:()=>'John'};constspy=sinon.spy(user,'getName');user.getName();user.getName();expect(spy.calledTwice).to.be.true;});});
# Install parallel testingnpminstall--save-devmocha-parallel-tests
# Run tests in parallelnpxmocha-parallel-tests
# Specify max parallel processesnpxmocha-parallel-tests--max-parallel4
# Run tests matching patternnpxmocha--grep"should add"# Run tests NOT matching patternnpxmocha--grep"should add"--invert
# Run tests in specific filesnpxmochatest/unit/**/*.test.js
# Run tests with tagsnpxmocha--grep"@slow"
// Tag tests with commentsdescribe('Calculator',function(){it('should add quickly @fast',function(){// Fast test});it('should handle complex calculations @slow',function(){// Slow test});});
// test/helpers/utils.jsconst{expect}=require('chai');functionexpectAsync(promise){return{toResolve:async()=>{try{constresult=awaitpromise;returnresult;}catch(error){thrownewError(`Expected promise to resolve, but it rejected with: ${error.message}`);}},toReject:async(expectedError)=>{try{awaitpromise;thrownewError('Expected promise to reject, but it resolved');}catch(error){if(expectedError){expect(error.message).to.include(expectedError);}returnerror;}}};}functioncreateUser(overrides={}){return{id:Math.floor(Math.random()*1000),name:'Test User',email:'test@example.com',...overrides};}module.exports={expectAsync,createUser};
constchai=require('chai');constchaiAsPromised=require('chai-as-promised');constchaiHttp=require('chai-http');constchaiString=require('chai-string');chai.use(chaiAsPromised);chai.use(chaiHttp);chai.use(chaiString);const{expect}=chai;describe('Chai Plugins',function(){it('should test promises',asyncfunction(){awaitexpect(Promise.resolve('success')).to.eventually.equal('success');awaitexpect(Promise.reject(newError('fail'))).to.be.rejected;});it('should test HTTP',function(){returnchai.request(app).get('/api/users').then(res=>{expect(res).to.have.status(200);expect(res).to.be.json;expect(res.body).to.be.an('array');});});it('should test strings',function(){expect('Hello World').to.startWith('Hello');expect('Hello World').to.endWith('World');expect('Hello World').to.equalIgnoreCase('hello world');});});```_### Custom Plugin Development```javascript// chai-custom-plugin.jsmodule.exports=function(chai,utils){chai.Assertion.addMethod('validEmail',function(){constobj=this._obj;constemailRegex=/^[^\s@]+@[^\s@]+\.[^\s@]+$/;this.assert(emailRegex.test(obj),'expected #{this} to be a valid email','expected #{this} not to be a valid email');});chai.Assertion.addMethod('between',function(min,max){constobj=this._obj;this.assert(obj>=min&&obj<=max,'expected #{this} to be between #{exp1} and #{exp2}','expected #{this} not to be between #{exp1} and #{exp2}',`${min} and ${max}`);});};// Usageconstchai=require('chai');chai.use(require('./chai-custom-plugin'));describe('Custom Plugin',function(){it('should validate emails',function(){expect('user@example.com').to.be.validEmail;});it('should check ranges',function(){expect(5).to.be.between(1,10);});});
// Good: Clear test structuredescribe('UserService',function(){describe('#createUser',function(){context('with valid data',function(){it('should create user successfully',function(){// Test implementation});it('should return user with ID',function(){// Test implementation});});context('with invalid data',function(){it('should throw validation error',function(){// Test implementation});});});});// Good: Descriptive test namesit('should return 404 when user does not exist',function(){// Test implementation});it('should update user email when valid email provided',function(){// Test implementation});
// Good: Use factories for test dataconstUserFactory=require('./factories/user-factory');describe('User Tests',function(){it('should validate user',function(){constuser=UserFactory.create({email:'invalid-email'});expect(()=>validateUser(user)).to.throw();});});// Good: Clean up after testsdescribe('Database Tests',function(){afterEach(asyncfunction(){awaitcleanupDatabase();});});
# Run with debug outputDEBUG=mocha*npmtest# Run specific test with debugnpxmocha--grep"specific test"--inspect-brk
# Debug with VS Code# Add to launch.json{"type":"node",
"request":"launch",
"name":"Mocha Debug",
"program":"${workspaceFolder}/node_modules/.bin/mocha",
"args":["--timeout","999999","--colors","${workspaceFolder}/test"],
"console":"integratedTerminal",
"internalConsoleOptions":"neverOpen"}
describe('Error Debugging',function(){it('should provide detailed error info',function(){try{constresult=complexOperation();expect(result.value).to.equal(42);}catch(error){console.error('Test failed with error:',error);console.error('Stack trace:',error.stack);throwerror;}});});
// Optimize test setupdescribe('Performance Tests',function(){// Use before/after for expensive setupbefore(asyncfunction(){this.database=awaitsetupDatabase();});after(asyncfunction(){awaitthis.database.close();});// Avoid unnecessary work in testsit('should be fast',function(){// Minimal test implementationexpect(true).to.be.true;});});
// .mocharc.jsmodule.exports={// Optimize for memory usagetimeout:5000,bail:true,// Stop on first failureexit:true,// Force exit after tests// Cleanup after testsrequire:['test/helpers/cleanup.js']};
Mocha es un marco de prueba de JavaScript flexible y potente que proporciona:
Flexible Structure: Soporte para BDD, TDD y interfaces personalizadas
Async Support: Apoyo nativo para promesas, callbacks y async/await
Rich Ecosystem: Extensivo ecosistema de plugins e integraciones
Multiple Environments: Runs in Node.js and browsers
Informe completo*: múltiples reporteros incorporados y soporte de reportero personalizado
Características avanzadas: Pruebas paralelas, filtración de pruebas y generación dinámica de pruebas
CI/CD Listo Excelente integración con sistemas de integración continua
Debugging Support: Rich debugging capabilities and error reporting
Mocha destaca al proporcionar una base sólida para la prueba de JavaScript con su flexibilidad, amplio conjunto de características y ecosistema maduro. Su enfoque sin columna permite a los equipos construir flujos de trabajo de pruebas que se ajusten a sus necesidades específicas, manteniendo una excelente experiencia de desarrollador y una ejecución de prueba confiable.