Why is testing a React component so damn hard?
If your answer is “use Jest,” then see below, Why not Jest?.
Any given React component may include other components.
<SomeOtherComponent /> into a constructor call
React.createElement(SomeOtherComponent) (more about React's vDOM.) This render-time generation of renderable elements makes mocking difficult.
What we need is someway to make
SomeOtherComponent resolve to a factory for a mock component.
Modules to the Rescue
Testing components in isolation requires a module system, so that each test subject may be loaded in a clean state for each test.
After liberal experimentation, this solution was found using CommonJS modules with Rewire to swap-out actual dependencies for mocks.
The recipe is:
Example my-component.js from above becomes modular:
With the dependency
SomeOtherComponent declared as a variable in the top-level scope of the module, Rewire may be used to swap it out for a mock.
Example rewire-module.js, a Jasmine test helper to setup & teardown a rewired module:
Why not Jest?
My own attempts to use Jest failed, because it:
- Runs all specs against a virtual DOM (via JSDOM.) This prevents testing code that uses browser-native constructs like IndexedDB & Service Workers.
- Offers no support for running tests in a browser, so all those fantastic visual dev & debugging tools provided by browsers are unavailable for tests.
We burned days of time wrangling a React proof-of-concept into a neatly testable app and hope to save you frustration when developing with React.
Please tweet @marsi with any feedback.