Write a post

Enjoy this post? Give Dave Schinkel a like if it's helpful.

1

Run Mocha + Enzyme with create-react-app

Published May 16, 2017Last updated May 19, 2017
Run Mocha + Enzyme with create-react-app

But I want to use Mocha!

Why Mocha?

I prefer to run mocha + enzyme to unit test and integration test my React applications for many reasons vs running Jest.

Also, I practice Test Driven Development and I like to keep things simple. That means some test frameworks IMO add a lot of unecessary bloat and indirection and I often prefer not to use mock frameworks if possible and most the time I don't need to.

I also write more isolated unit tests than anything, not as many integration tests (ice cream cones are bad, test pryamids are good). I want my tests to be easy to read and maintain. And that's what I get as a result of using this combination.

Not so fast!

The team I'm working with wanted to use create-react-app as much as possible without ejecting and least modifications needed. And I wanted to honor their decision or desire to do so while still being able to run mocha.

However when trying to configure mocha, I was surprised to find that I wasn't able to simply add mocha in a create-react-app the way I normally would. Basically the Facebook team expects everyone to default to Jest. Well that's nice, and I get that it's opinionated but was surprised it was this restrictive without being forced to possibly eject it.

Good thing is, I've figured out a work around that I'd like to share that works, and it doesn't require you to eject your create-react-app !. Some day I'd also like to tr the ava test framework which I think would be the next test framework I'd use if I had to or wanted to change.

I thought ok, I'll probably either need to manually install babel-cli (because create-react-app does not and I need to be able to reference babel-cli/babel-node) OR just have to unfortunately add the babel-preset-es2015 manually via a .babelrc file if I wanted to get mocha working again both at the command-line and WebStorm test runner.

I found out neither of those ideas was recommended when Dan Abramov replied to my idea to install babel-cli or to install babel-preset-es2015 when I posted an issue in github. He recommended adding more magic/config to a portion of the underlying scripts that run create-react-app. But I did not want to get myself into a rabbit hole. While I'd love to help and contribute to add support for mocha, I like simple solutions first and foremost if possible. Adding that to react-sripts would not be trivial IMO...and I don't have time for that.

Custom React Projects from Scratch

I honestly don't mind setting up and customizing my React projects. Furthermore I don't use Gulp or Webpack, I simply create npm scripts which is not hard to do. Why have all that "magic" and have to learn that magic when you can simply create npm scripts.

So prior to create-react-app coming out, I was carrying along quite fine with my mocha + enzyme unit tests. I also create mocha + enzyme React integration based unit tests. So...I don't use Jest Snapshots for integration tests. And Snapshots are not unit tests..they don't isolate behavior or state issues.

For integration tests I simply create two kinds:

mocha + supertest - for testing over the network
mocha + enzyme (dive, mount) - for testing more than one level of my React App's Component tree instead of magic

When I test drive my code, I create isolated unit tests using:
mocha + enzyme (shallow)
these isloated unit tests cover a range of things:

  • state tests (props)
  • structural tests (again snapshots is not preferred here)
  • redux connected containers - behavior tests on mapStateToProps & mapDispatchToProps
  • redux actions
  • redux reducers

My TDD cycle (very rough list)
(subject to change but this is how I do it now via React-Redux):

  • Creating a redux connected container test. To make this test pass, it forces me to create a reducer test (and a few other tests below)
  • Create a reducer test. This test needs an action I haven't created yet. So Part of making that reducer test pass is create an action
  • Test drive the creation of that action by writing an action test. Then I implement that action. The action test passes
  • The action has been implemented so now my reducer test passes
  • Write a mapStateToProps test to force me to implement mapStateToProps. It'll now be able to get state from the store, after that reducer runs
  • Finally I create the corresponding dumb presentational component that the connected container will render. I create a test for that and that forces me to implement the presentational component
  • Part of getting the presentational component test to pass might mean adding events & making handler calls (or might not). If it does, then I'll write a test to force me to implement mapDispatchToProps
  • Somewhere in there I might need some component lifecycle methods to be created..

note: there are a few steps in here I'm not putting because it'd make this post too long.

Yay, I just finished a feature!

Jest Snapshots
I'm personally not fond of them, but if you absolutely feel you want to use Jest Snapshots, then add them on top as an integration layer, but not as the main way to test or rely on as the sole way to cover yourself with tests. I TDD so they do not even make sense nor can I use them in my TDD flow because I can't TDD with magic and unit tests must be isolated and decoupled. And I'm not really happy that Facebook seems to tell everyone that Snapshots is a way to get rid of the "pain" of having to write unit tests TBH.

I think that the community should be practicing how to write tests rather than run away from them ("I got burnt", "they take too long", "we don't need them" etc. - lets cut to the chase and reveal the truth: that's because we don't try practice and become better and faster at writing them!). We need developers becoming better at writing first class tests.

Running Mocha
So when I usually create custom React projects, usually I simply adde a .babelrc file, added whatever ES6 presets I need and mocha always ran just fine. I've done it so many times that it's no longer "painful" to setup my ES6 presets TBH 😃. Furthermore I run my tests with a much better test runner than the command-line, and that is, I use the WebStorm test runner.

For WebStorm to find babel and run mocha via its built-in test runnner, you can do one of two things:

Use babel-node as the Node Interpreter

  1. add a .babelrc with the required ES6 presets
  2. Add a new WebStorm mocha test config and change the Node interpreter from using plane Node to using babel-cli/bin/babel-node instead (then no need for specifying --compilers js:babel-core/register) option anymore.

Use mocha command-line options in WebStorm's Test Config

  1. add a .babelrc with the required ES6 presets
  2. then add this to mocha options: --compilers js:babel-core/register

Either way, it has always been piece of cake and always has been to get WebStorm to talk to a Node project (React or not)...unless you're using create-react-app.

With create-react-app

create-react-app is Facebook's attempt to provide a zero-config bootstrapped React project.

Some teams want to use create-react-app to "make things easier". I've found it however to be a bit restrictive TBH. By easier they feel it keeps upgrades consistent and allows you to get producive quicker. Fair enough.

Personally I prefer to simply write my build automation via npm scripts rather than use Gulp or Webpack. I feel those tools introduce complexity and bloat. I feel writing npm scripts is not hard, and is a much cleaner way to automate building, minifiying and all that jazz.

But... if a team wants to use create-react-app, and if I being the only one writing this greenfield app don't not want to get locked into having to use only Jest, well I needed to find a way to get mocha working without ejecting this boostrap config. Once you eject, you can't go back.

Getting Mocha to work again!

  1. yarn add -D babel-preset-react-app
    note: you cannot use the babel-preset-es2015 preset as create-react-app ignores it
  2. add a .babelrc to the root of your project and add this preset to it:
    { "presets": ["react-app"] }
    or
    forget the .babelrc and add the preset to your package.json:
    "babel": { "presets": [ "react-app" ] }
    `

Next Setup How You Prefer to Run Mocha

Run via Command-line via npm script

  1. add this script to your package.json: scripts: { 'test': NODE_ENV=development mocha --compilers js:babel-core/register src/test/unit/**/*.spec.js} (your test path might be different)

Run via WebStorm's awesome test runner

You can set this up one of two ways:

  1. install babel-cli: `yarn add babel-cli'
  2. set Node interpreter to: [full path to project]/node_modules/babel-cli/bin/babel-node.js
  3. Add this to Environment variables: NODE_ENV=development (create-react-app looks for this)

Screen Shot 2017-05-16 at 12.48.01 AM.png

Screen Shot 2017-05-16 at 1.09.09 AM.png

OR

Don't use babel-cli (don't install it) and run mocha using mocha options:

  1. set Node interpreter to: user/bin/local/node
  2. add --compilers js:babel-core/register to mocha options
  3. Add this to Environment variables: NODE_ENV=development (create-react-app looks for this)
    Screen Shot 2017-05-16 at 11.20.10 AM.png
Discover and read more posts from Dave Schinkel
get started
Enjoy this post?

Leave a like and comment for Dave

1
Be the first to share your opinion

Subscribe to our weekly newsletter