All articles
nodejs

Different Styles of Test Code Using Chai

Share this article

Share on LinkedIn Share on X (formerly Twitter)

When writing tests in Node.js, Chai is a popular BDD / TDD assertion library that can be paired with any JavaScript testing framework. One of the best features of Chai is that it provides multiple interfaces for writing assertions, allowing developers to choose the style that best fits their project's conventions and personal preferences.

Chai provides three main assertion styles: Assert, Expect, and Should.

Let's take a look at each of these styles and how they compare, using Node.js's built-in node:test runner as an example.

Setup

First, let's assume we have a simple math.js module that exports a sum function:

// math.js
export function sum(a, b) {
  return a + b;
}

Now, let's see how we can test this function using the different styles provided by Chai.

1. Assert Style

The Assert style is a traditional TDD (Test-Driven Development) style interface. It provides classic assert-dot notation, similar to that packaged with Node.js. It is well-suited for developers who prefer a more straightforward, functional approach to assertions.

import test from 'node:test';
import { assert } from 'chai'; // Using Assert style
import * as math from './math.js';
 
test('should return 4 when adding 2 and 2 using assert', function() {
  const result = math.sum(2, 2);
  
  // Traditional assert style
  assert.equal(result, 4);
});

2. Expect Style

The Expect style is a BDD (Behavior-Driven Development) style interface. It uses chainable language constructs that make the assertions read more like natural language. This is often preferred in modern JavaScript testing for its readability.

import test from 'node:test';
import { expect } from 'chai'; // Using Expect style
import * as math from './math.js';
 
test('should return 4 when adding 2 and 2 using expect', function() {
  const result = math.sum(2, 2);
  
  // Chainable BDD style
  expect(result).to.equal(4);
});

3. Should Style

The Should style is also a BDD style interface, very similar to expect. However, it extends Object.prototype to provide a single getter as the starting point for your language assertions. This means you call .should directly on the object you are testing.

Note: Since should modifies Object.prototype, it might not be suitable for all environments, especially those where modifying global prototypes is frowned upon. You must execute should() before using it.

import test from 'node:test';
import { should } from 'chai'; // Using Should style
import * as math from './math.js';
 
// Initialize should - modifies `Object.prototype`
should();
 
test('should return 4 when adding 2 and 2 using should', function() {
  const expected = 4;
  const result = math.sum(2, 2);
 
  // Directly chaining on the object
  result.should.equal(expected);
});

Summary

Choosing between Assert, Expect, and Should depends on your team's preference and the nature of your project:

  • Assert: Best if you prefer traditional, explicit function calls without chaining.
  • Expect: Great for readable, BDD-style assertions without modifying prototypes. (Highly recommended for most projects).
  • Should: Also great for readability, but modifies Object.prototype, which may cause issues in some environments or certain specific setups.

All three styles get the job done efficiently. Choose the one that makes your tests the most readable and maintainable!


Comments