Skip to content

Karma with Chai

Chai is the assertion library most commonly paired with Mocha in a Karma setup. This lesson covers karma-chai, and Chai's three distinct assertion styles.

Setting Up karma-chai

karma-chai injects Chai's global assertion interfaces into the browser page, the same way karma-jasmine injects Jasmine's. It's typically listed in frameworks alongside mocha, since Chai provides assertions but not the test runner structure itself.

npm install --save-dev karma-chai chai

// karma.conf.js
config.set({
  frameworks: ['mocha', 'chai'],
  files: ['src/**/*.spec.js']
});

With both frameworks listed, every spec file gets Mocha's describe/it plus Chai's expect as browser globals.

Chai's Three Assertion Styles

// expect style (most common)
expect(user.name).to.equal('Ada');

// should style (extends Object.prototype)
user.name.should.equal('Ada');

// assert style (closest to Node's built-in assert)
assert.equal(user.name, 'Ada');
  • expect is the most widely used style and the one most Karma+Chai projects standardize on.
  • should reads fluently but modifies Object.prototype, which some teams avoid for that reason.
  • assert most closely resembles traditional assertion libraries and Node's built-in assert module.
  • Pick exactly one style per project; mixing all three makes specs inconsistent to read.

Chai expect() Cheat Sheet

The most common Chai assertions in the expect style.

Assertion Checks
expect(x).to.equal(y) Strict equality (===)
expect(x).to.deep.equal(y) Deep equality for objects/arrays
expect(x).to.be.true / .false Boolean value checks
expect(x).to.be.null / .undefined Exact null/undefined checks
expect(x).to.include(y) Array/string contains a value
expect(x).to.have.length(n) Array/string length
expect(fn).to.throw() Function throws when called
expect(x).to.have.property('key') Object has a given property

Chai's Chainable, Readable Language

Chai's defining feature is its chainable, English-like assertion syntax. Words like to, be, have, and deep exist purely for readability — they don't perform checks themselves, only the final method or property in the chain does.

expect([1, 2, 3]).to.be.an('array').that.includes(2);
expect({ role: 'admin' }).to.have.property('role').that.equals('admin');

Chainable language words make assertions read closer to natural English, at the cost of a steeper initial learning curve than simpler assertion styles.

Combining Chai with Sinon for Mocking

Chai itself provides no mocking. sinon-chai extends Chai with assertions specifically for Sinon spies and stubs, giving Mocha+Chai projects mocking-aware assertions similar to Jasmine's .toHaveBeenCalledWith().

npm install --save-dev sinon sinon-chai

// setup file loaded before specs
chai.use(sinonChai);

// in a spec:
const spy = sinon.spy();
doSomething(spy);
expect(spy).to.have.been.calledWith('expected-arg');

Common Mistakes

  • Mixing expect, should, and assert styles inconsistently across the same test suite.
  • Using .to.equal() for deep object comparison instead of .to.deep.equal(), causing unexpected failures.
  • Forgetting chai.use(sinonChai) before trying to use Sinon-specific Chai assertions.
  • Assuming Chai's chainable words (to, be, have) perform assertions themselves rather than just improving readability.

Key Takeaways

  • karma-chai injects Chai's assertion interfaces as browser globals, typically alongside Mocha.
  • Chai supports three styles — expect, should, and assert — pick one consistently per project.
  • Chai's chainable language (to, be, have, deep) improves readability without performing checks itself.
  • sinon-chai bridges Sinon's mocking with Chai's assertion syntax for a Jasmine-spy-like experience.

Pro Tip

If your team is deciding between Chai styles for a new suite, default to expect. It reads nearly as naturally as should without modifying built-in prototypes, and it maps most intuitively for developers coming from Jasmine or Jest.