Better test structuring using Mocha's context()
Tags: node, testing
Published: 2022-11-04 18:18:14

---
title: Better test structuring using Mocha's context()
published: true
date: 2022-11-03 00:00:00 UTC
tags: node,testing
canonical_url: https://www.coreycleary.me/better-test-structuring-using-mochas-context
---

<em><strong>Originally published at <a href="https://www.coreycleary.me/better-test-structuring-using-mochas-context">coreycleary.me</a></strong>. This is a cross-post from my content blog. I publish new content every week or two, and you can <a href="https://www.coreycleary.me/about/">sign up to my newsletter</a> if you'd like to receive my articles directly to your inbox! I also regularly send cheatsheets and other freebies.</em>

Sometimes when working on adding or modifying unit tests within a test suite, you may not be sure what the best way to structure the tests within that suite is.

The tests may be getting cluttered, out of control, and you may have repetition.

But better organization will lead to making writing tests less painful (and even enjoyable) because they're easier to maintain.
And since you're usually working on code within a team, it will make it easier for everyone on that team to maintain, understand what the tests are testing, and to add new tests as well.

If you're using <Link text='Mocha' href='https://mochajs.org/' /> for your tests, one way to do this is by using the `context()` function. You're almost definitely already using `describe()` to group your test cases, but `context()` will provide for more explicit grouping of tests within your suite.

## Example

Take a look at the example below, that is only using `describe()` for grouping tests:

```javascript
describe('Array', () => {
  describe('indexOf()', () => {
    it('should not throw an error when the array item is not present', () => {
      (() => {
        [1, 2, 3].indexOf(4)
      }.should.not.throw())
    })

    it('should return -1 when the array item is not present', () => {
      [1, 2, 3].indexOf(4).should.equal(-1)
    })

    it('should return the index where the element first appears in the array', () => {
      [1, 2, 3].indexOf(3).should.equal(2)
    })
  })
})
```

You'll notice that the phrase "when the array item is not present" is repeated twice, in the 1st and 2nd tests.

It was kind of annoying to type that twice, and from reading these tests you don't immediately pick up on the fact that those tests are related. If you have business requirements for a feature you're building, you might even have requirements like "when X is not present, do Y" and "when X is not present and A, do B".

Instead it would be great if we could group these together. Now, we could use another `describe()` to do this, like so:

```javascript
  describe('indexOf()', () => {
    describe('when not present', () => {
      it('should not throw an error when the array item is not present', () => {
        (() => {
          [1, 2, 3].indexOf(4)
        }.should.not.throw())
      })

      it('should return -1 when the array item is not present', () => {
        [1, 2, 3].indexOf(4).should.equal(-1)
      })
    })

    it('should return the index where the element first appears in the array', () => {
      [1, 2, 3].indexOf(3).should.equal(2)
    })
  })
```

But then it sort of begs the question... what is the difference between the nested `describe()` block and the other individual `it()` blocks within the same "parent" `describe('indexOf()', () => {})`?

This is where the `context()` function comes in. We can instead use it to group the contextually similar test cases, and have them still be within our "parent" unit test `describe()` block.

Take a look at the example above, rewritten below using it:

```javascript
describe('Array', () => {
  describe('indexOf()', () => {
    context('when not present', () => {
      it('should not throw an error', () => {
        (() => {
          [1, 2, 3].indexOf(4)
        }.should.not.throw())
      })

      it('should return -1', () => {
        [1, 2, 3].indexOf(4).should.equal(-1)
      })
    })

    context('when present', () => {
      it('should return the index where the element first appears in the array', () => {
        [1, 2, 3].indexOf(3).should.equal(2)
      })
    })
  })
})
```

`context()` is just an alias for `describe()`, so it works exactly the same and is the same function.
From a _test runner_ perspective this doesn't do anything - it doesn't change the way the tests are run, the order they're run in, etc.

But BDD-style tests are designed to be readable to even non-developers (like QA and business analysts/product managers).
So having an "extra" function we can use to make it clearer how the tests are grouped and what a given "test block" is testing is a huge boost for readability.

## When to use context?

A good heuristic for when to use `context()` over `describe()` is when you repeat yourself across tests.
That's a key indicator that what you're dealing with is, in fact, a contextual set of tests, and that they can likely be grouped together.

Not _everything_ needs to be grouped using it, I certainly don't do that. But when you have the following:
- you're repeating the same language in your test cases
- you're starting to have *many* test cases within a single "parent" unit, and that starts getting out of control, and can group some into contextually similar sub-groups

...`context()` can come in very handy.

It will make your test suites easier to read, your teammates will understand what the intent of the tests are, and it can help the tests better serve as documentation of requirements/functionality.

Love JavaScript but still getting tripped up by unit testing, architecture, etc? I publish articles on JavaScript and Node every 1-2 weeks, so if you want to receive all new articles directly to your inbox, <a href="https://www.coreycleary.me/about/">here's that link again</a> to subscribe to my newsletter!