Mocha + Enzyme with create-react-app

Published May 16, 2017Last updated Nov 13, 2017
Mocha + Enzyme with create-react-app

But I want to use Mocha!

Why Mocha?

Because I've been using mocha, and Jest is a scam. Facebook tries to market/paint Jest as better than mocha and that somehow mocha the claim is inferior or a pain. Complete Rubbish! They just want you to use everything FB. I think that's ridiculous when it comes to test tools. And create-react-app tries to lock you into only using Jest. That's bad and just lame on FB's part IMO. The problem is that many teams are using CRA in production apps.

One can easily say "Then don't use CRA", it's only meant to be a "toy" or for beginners. But that line is 100% complete BS. Why? beacuse you can't help but come across it, many teams feel like this is what you should use, the end all defacto "everyone's doing it this way now" bandwagon. The the problem then becomes the fact that FB purposely makes it hard to easily add other frameworks such as mocha. You can use mocha with out doing some major fiddling to either the CRA scripts or like I figured out...below. It's always been two easy steps applying any test framework to a custom React application:

1) npm install -D mocha
2) simply add a test script to package.json and you were done!

Well with CRA, you can't just do that. It's not custom, it's opinionated but surely FB should not make steps 1 & 2 for other testing frameworks no longer feasible just because they want you to use Jest.

I prefer to run mocha + enzyme to unit test and integration test my React applications.

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.

Tried to Add Mocha to CRA - FAIL

The team I'm working with wanted to use create-react-app (sigh) as much as possible without ejecting and least modifications needed (sigh again). 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 (ugh!!). Basically the Facebook team expects everyone to default to Jest and wnats you to use no other. 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. Prior to create-react-app (sigh) coming out, I was carrying along quite fine with my mocha + enzyme 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. I don't like them at all, and prefer the to stay far, far away from anything I'm working in.

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. Just please don't use them 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 - Has Always Been Easy with React

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.

Getting Mocha To Work With CRA - The Hack

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 - Steps

  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"
    ]
  }`

UPDATE (9/14/2017 per this issue)
Facebook:

Our Babel preset no longer includes CommonJS transform (since it’s unnecessary if ES6 modules are supported out of the box, as they are by Webpack)

Due to the continual changes made to babel-preset-react-app, the above, adding create-react-app's babel-preset-react-app to package.json no longer works with frameworks other than Jest. babel-preset-react-app discounts anything that works with it other than Jest which is why I found this problem after upgrading babel-preset-react-app. Which is precisely my rant with FB. This is also why you end up having to eject react-create-app inevitably or forking it (evenmore work) anyway because of little issues like this not with just testing but you'll find you are limited only by what FB allows in that canned framework.

So, now this becomes:

"babel": {
    "presets": [
      "react-app"
    ],
    "plugins": [
      "transform-es2015-modules-commonjs"
    ]
  }

For now, that'll work with mocha and probably Ava, Tape, etc. Who knows what the next hack will be if we don't want to use Jest. When our clients choose to use create-react-app (I'm not going to argue with my client) we shouldn't also be forced to use Jest just because that's the only framework that's going to be compatible with this. Where Facebook has failed here is their miscalculation on how test frameworks are very opinionated, and should be something you can just plug in without babel issues. Frameworks other than Just work and have workedjust fine if you simply used the es-2015 pugin in any other project! But FB thinks everyone's going to want to test the way they do, and testing is a huge liability if you're forced into only a certain framework due to the nature of magic within this create-react-app.

Setup Done! Now 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

Don't use babel-cli as the node interpreter and instead and run mocha using mocha options (babel-cli/babel-node is outdated and no longer supported by WebStorm):

  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

Reminder:

Jest is a scam. FB wants you to use everything in their ecosystem so they come up with outlandish claims! Don't fall for their claim that mocha sucks or is somehow inferior or hard to use. The Fact is Jest doesn't bring anything new to the table that mocha already does well. Mocha takes me no more no less to setup than any framework in JS.

Discover and read more posts from Dave Schinkel
get started
Enjoy this post?

Leave a like and comment for Dave

4