Learning JavaScript Testing Quickly with Mocha, Chai, and Sinon (and a Lot of Gaps)
Tags: javascript, mocha, testing, career
Published: 2019-08-04 23:15:06

---
title: Learning JavaScript Testing Quickly with Mocha, Chai, and Sinon (and a Lot of Gaps)
published: true
description: a short intro to basic mocha, chai, and sinon testing tools
tags: javascript, mocha, testing, career
series: "Junior JavaScript Jobhunting: Quick Tips for Technicals and Takehomes"
cover_image: https://thepracticaldev.s3.amazonaws.com/i/4olljtrz2tqd4y10y573.png
---

*Cover image credit: [**Hunter x Hunter** manga](https://en.wikipedia.org/wiki/Hunter_%C3%97_Hunter) by Yoshihiro Togashi, meme-ified by yours truly. <3*

**Update 8/9/19:** This article has been dubbed Part 1 of my new series, *Junior JavaScript Jobhunting: Quick Tips for Technicals and Takehomes*! Hope you enjoy and find some useful tips, and please feel free to contribute more in the comments!

![anime gif of suited man sipping tea with a satisfied look on his face](https://pa1.narvii.com/6901/da1eb99c537353c1e4ba18d888a4c72cb69e5d97r1-504-389_hq.gif)

Recently, I had the opportunity to complete a takehome coding challenge that required me to include JavaScript tests with my solution. I will freely admit that I am still learning the ins-and-outs of testing, and that a big part of the battle is knowing **what** to test. These notes are not intended as a primer on testing generally—instead, I wanted to share the commands and syntax needed to get up-and-running quickly, and get some unit tests written.



## So what are we testing here?

The challenge involved building a class, `FlavorRanker`, that takes in a text file to parse and returns a ranking of most popular flavors. The parsed rankings are stored in a property, `this.flavorObj`, that is initialized empty, and is filled after running the class function `parseTextFile()`. Here’s a snapshot of a simplified version:

```javascript
// FlavorRanker.js

class FlavorRanker {
    constructor() {
        this.flavorObj = {};
    }

    parseTextFile() {    
	// fill in this.flavorObj with pairs like “grape”: { “points”: 5 }
    }
}
exports.FlavorRanker = FlavorRanker;
```

With this class, there’s a few things we can test right away:

After an instance of `FlavorRanker` is created, does its `this.flavorObj` property exist?
At certain points, is `this.flavorObj` empty—or has `parseTextFile()` successfully added name-value pairs to it?
Has `parseTextFile()` been called—and has it been called exactly once?

Not the most robust tests, but they’ll introduce us to some essential JavaScript testing syntax from frameworks Mocha, Chai, and Sinon!



## Wait, why are we covering three things at once?

Short answer: because they work so well together! Briefly, here’s what each of them will do for us:

* [Mocha](https://mochajs.org/) - A JavaScript test runner and framework that provides a `describe()`/`it()` syntax for testing assertions. This will be the thing specified in your package.json file under `“scripts”: { “test”: “mocha” }`.

* [Chai](https://www.chaijs.com/) - A library that adds extra readability to JavaScript test assertions. Supplants the Node.js default `assert()` syntax with `expect().to.be`, and lots of chain-able options.

* [Sinon](https://sinonjs.org/) - A library that provides spies that “watch” functions and can detect when they’re called, what arguments are passed to them, what is returned, etc. (Sinon provides a lot more than that, but we’ll stick with just spies for this post.)



## Setup

To include these packages in your project, use the following commands:

`$ npm install -g mocha` - this will install Mocha globally (not just in your current project), and give you access to `$ mocha` commands in your terminal. (This guide won’t cover that.)

`$ npm install chai` - this will install Chai locally.

`$ npm install sinon` - this will install Sinon locally.

You will also want to create a `/test` directory, and a `test.js` file inside that directory:
```
test
|-- test.js
```

Finally, in your package.json file, check your “scripts” section to make sure “test” is set to “mocha”:
```javascript
// package.json

"scripts": {
  "test": "mocha"
},
```

Let’s write some tests!



### Importing

Let’s load some specific tools into our tests. We’ll be using Chai’s `expect`, Sinon’s `spy`, and the `FlavorRanker` class from above:

```javascript
// test.js 

const expect = require('chai').expect;
const spy = require('sinon').spy;
const FlavorRanker = require('../flavorRanker.js').FlavorRanker;
```


### Use describe() to organize tests and create contexts

Mocha allows us to write tests by nesting describe() functions within each other. [This StackOverflow discussion](https://stackoverflow.com/questions/19298118/what-is-the-role-of-describe-in-mocha) goes into some of the when/why/how of organizing tests, but here’s the gist:

`describe(“String with test description”, function() { … } )`

**NOTE:** [This article](https://remarkablemark.org/blog/2016/08/20/arrow-functions-in-mocha/) covers why you **DON’T** want to use arrow functions instead of function() {} in Mocha.

You can nest these as deeply as you want—just be aware that each one establishes a new context, and that variable scoping applies here as expected:

```javascript
describe('Generic test name', function() {
    // variable flavorRanker does NOT exist in this context.

    describe('FlavorRanker class', function() {
        const flavorRanker = new FlavorRanker;

        describe('flavorRanker instance', function() {
            // variable flavorRanker DOES exist in this context.
        });
    });
});

```


### Use it() to declare a single test

Within a describe() context, each it() function describes a single test. The syntax is:

`it(“String with test description”, function() { … } ) `

Here are two tests ensuring that a newly-created instance of FlavorRanker has a this.flavorObj property, and that it’s an empty object:

```javascript
describe('flavorRanker instance', function() {

            it('should have a flavorObj property that is an object', function() {
                // testable assertion
            });

            it('flavorObj should be empty', function() {
                // testable assertion
            });
```



### Chai: expect()

Chai shines because it makes writing readable tests so simple. Here’s the syntax for expect():

`expect(foo).to._____._____._____ … `

In the blanks, you can add a host of chain-able functions that create the testable assertion. Here’s how we can write expect() functions for the two tests above:

```javascript
describe('flavorRanker instance', function() {

            it('should have a flavorObj property that is an object', function() {
                expect(flavorRanker.flavorObj).to.be.an('object');
            });

            it('flavorObj should be empty', function() {
                expect(flavorRanker.flavorObj).to.be.empty;
            });
```

The tests will check exactly what they say: is flavorRanker.flavorObj an object, and is it empty? Here’s the terminal output from running `$ npm test`:

```
  Generic test name
    FlavorRanker class
      flavorRanker instance
        ✓ should have a flavorObj property that is an object
        ✓ flavorObj should be empty
```




### Sinon: spy()

Finally, we can use Sinon’s spy() function to assign a variable to “watch” for certain behaviors, like the function being called or returning a value. To create a spy:

`const spyName = spy(object, “functionName”)`

For our tests, we’ll create a spy for flavorRanker’s parseTextFile() method:

```javascript
        describe('flavorRanker instance', function() {
            const parseTextFile = spy(flavorRanker, "parseTextFile");
        });
```

And now, we can write tests using Chai’s syntax to check if it’s been called exactly once:

```javascript
describe('flavorRanker instance', function() {
    const parseTextFile = spy(flavorRanker, “parseTextFile");
    
    // spy detects that function has been called
    flavorRanker.parseTextFile();

    // checks that function was called once in this test’s context
    it('flavorRanker.parseTextFile() should be called once', function() {
        expect(parseTextFile.calledOnce).to.be.true;
    });

});
```

Now, when we run `$ npm test` again, our terminal shows:

```
  Generic test name
    FlavorRanker class
      flavorRanker instance
        ✓ should have a flavorObj property that is an object
        ✓ flavorObj should be empty
        ✓ flavorRanker.parseTextFile() should be called once
```

Perfect!


## Conclusion: This is only the beginning!

As I stated in the intro, this writeup is *NOWHERE NEAR* comprehensive—but for folks like me who are a little daunted by starting to learn JavaScript testing, having just a couple easy-to-use tools can help you get started! Please feel free to leave comments below sharing any other intro-level tips for someone who needs to learn some testing syntax quick!

### (More Comprehensive) Guides and Resources

[Excellent introductory guide to Mocha, with a lot more depth](https://blog.logrocket.com/a-quick-and-complete-guide-to-mocha-testing-d0e0ea09f09d/)

[Great tutorial to help you write your first tests](https://codeburst.io/how-to-test-javascript-with-mocha-the-basics-80132324752e)

[Excellent cheat-sheet of Mocha, Chai, and Sinon syntax](https://gist.github.com/yoavniran/1e3b0162e1545055429e#mocha)

[Mocha docs](https://mochajs.org/)

[Chai docs](https://www.chaijs.com/)

[Sinon docs](https://sinonjs.org/)