At LogRocket, nearly our entire code base is JavaScript. Over the years, we have learned a good amount about the lesser-known features of JavaScript testing libraries. In this series, I’ll go through the LogRocket testing stack and describe some of the tips and tricks that help make our tests faster and more robust.
- Part 1: Test Expectations — Chai
- Part 2: Test Mocks — Sinon
- Part 2: Test Frameworks — Jest and Mocha
- Part 3: Integration Testing — WebdriverIO and Selenium
Chai

Chai is a “test expectation” library: it helps you make assertions about code behavior. Chai itself comes in many syntactic flavors that you can choose between for making assertions.
For example, if you wanted to assert that foo
is a string
, there are a few different options:
// should chai.should(); foo.should.be.a(‘string’); // expect chai.expect(foo).to.be.a(‘string’); // assert chai.assert.typeOf(foo, ‘string’);
expect().to.throw()
As JavaScript engineers, we’re really good at making sure our code works when the inputs are correct. The biggest challenge — and one of the best reasons to write tests — is to make assertions for failing or unexpected inputs.
Chai comes with a handy helper that lets us assert that code should throw an exception. This is great for throwing inputs like -1
, ★★François★★
and function(){alert()}
at code that expects a user’s name.
Here’s an example usage:
expect(() => { callSomeFunction(); }).to.throw(/an error/);
equal() vs eql()
Chai comes with a number of built-in functions for determining equality.equal()
asserts that two arguments are referentially equal (ie. a === b)
. eql()
does a deep equality check between two arguments.
Example:
expect('rocket').to.equal('rocket') // true expect('rocket').to.eql('rocket') // true expect({ log: 'rocket' }).to.equal({ log: 'rocket' }) // false expect({ log: 'rocket' }).to.eql({ log: 'rocket' }) // true
Why use equal/eql at all instead of expect(foo === 'rocket').to.be.true
? We get beautiful test output that looks like this:

Instead of this:

dirty-chai
Chai can be extended with various plugins that provide additional functionality, such as chai-string
which adds handy string-testing functionality, chai-as-promised
which allows us to write assertions about Promises, and chai-datetime
which provides date assertions.
One handy, lesser-known plugin is dirty-chai
. Normally Chai assertions can only be made like so:
expect(foo).to.be.true
This can be brittle. If I accidentally make a typo, then the assertion will never be checked:
expect(foo).to.be.frue
Instead, we use dirty-chai
which extends chai with function calls like so:
expect(foo).to.be.true()
This way, if I ever make a syntax mistake, the test will throw an exception instead of passing silently.
sinon-chai
Sinon is an amazing library for writing test “spies” and “stubs” in JavaScript. With Sinon, we can mock functionality that doesn’t contribute to the test assertion. There are a number of reasons that you might want to use a stub or spy in a test:
- Fake a network interface to see how a component responds to certain network conditions
- Mock code that relies on interfacing with the DOM
- Assert that a certain callback is invoked by a test.
sinon-chai
allows us to make Sinon assertions with the Chai syntax:
const stub = sinon.spy(); expect(stub).to.be.calledOnce();
I’ll describe Sinon more thoroughly in another blog post this series.
eslint-plugin-chai-expect
If you’re using eslint
to lint your code, eslint-plugin-chai-expect prevents a few of the most common syntax errors:
expect(foo === bar).to.be.true(); // no-inner-compare expect(foo) // missing-assertion
Have any other lessons learned about assertions with Chai? Let me know in the comments!

LogRocket: Debug JavaScript errors more easily by understanding the context
Debugging code is always a tedious task. But the more you understand your errors the easier it is to fix them.
LogRocket allows you to understand these errors in new and unique ways. Our frontend monitoring solution tracks user engagement with your JavaScript frontends to give you the ability to find out exactly what the user did that led to an error.

LogRocket records console logs, page load times, stacktraces, slow network requests/responses with headers + bodies, browser metadata, and custom logs. Understanding the impact of your JavaScript code will never be easier!
Try it for free.