Mocha
01 / 02

Test Structure, Hooks & Async

Test Structure, Hooks & Async

Basic Structure

const { expect } = require('chai'); // Mocha ships no assertions — pair with Chai

describe('Calculator', () => {
  let calculator;

  before(() => console.log('runs once before all tests in this describe'));
  beforeEach(() => { calculator = new Calculator(); });  // runs before EVERY test
  afterEach(() => { calculator = null; });
  after(() => console.log('runs once after all tests'));

  it('adds two numbers', () => {
    expect(calculator.add(2, 3)).to.equal(5);
  });

  describe('division', () => {
    it('throws on division by zero', () => {
      expect(() => calculator.divide(10, 0)).to.throw('Cannot divide by zero');
    });
  });
});

// npx mocha                          — run tests/ by default glob
// npx mocha test/**/*.spec.js        — custom glob
// npx mocha --grep "division"        — filter by test name

Async Tests

// Modern style — return (or await) a Promise, no `done` needed
it('fetches a user', async () => {
  const user = await getUser(1);
  expect(user.name).to.equal('Alice');
});

// Callback style — must call done() in EVERY code path, including errors
it('reads a file', (done) => {
  fs.readFile('data.txt', (err, data) => {
    if (err) return done(err);   // forgetting this branch hangs until timeout
    expect(data.toString()).to.include('hello');
    done();
  });
});

// DON'T mix both styles in one test — accepting `done` AND returning a
// Promise leaves Mocha unsure which signal actually means "finished".

// Regular function (not arrow!) needed to use this.timeout()/this.skip()
it('a slow integration call', function () {
  this.timeout(5000);  // arrow functions don't get Mocha's test-context `this`
  return callSlowApi();
});

Only, Skip & Retries

describe.only('focus here while debugging', () => { /* ... */ }); // easy to forget to remove!

it.skip('not implemented yet', () => { /* ... */ });

it('flaky external API call', function () {
  this.retries(2); // re-runs up to 2 more times before a real failure — use sparingly,
  return callThirdPartyApi();  // overuse masks real race conditions instead of fixing them
});

Keep your own version of these notes — editable, searchable, and organised by your stack.

Start free