{..."scripts": {..."test": "jest","test:watch":"npm test -- --watch" },...}
and run npm test to run it once, or npm run test:watch to test on every file change.
Action Creators
In Redux, action creators are functions which return plain objects. When testing action creators, we want to test whether the correct action creator was called and also whether the right action was returned.
Example
exportfunctionaddTodo(text) {return { type:'ADD_TODO', text }}
can be tested like:
import*as actions from'../../actions/TodoActions'import*as types from'../../constants/ActionTypes'describe('actions', () => {it('should create an action to add a todo', () => {consttext='Finish docs'constexpectedAction= { type:types.ADD_TODO, text }expect(actions.addTodo(text)).toEqual(expectedAction) })})
Async Action Creators
For async action creators using Redux Thunk or other middleware, it's best to completely mock the Redux store for tests. You can apply the middleware to a mock store using redux-mock-store. You can also use fetch-mock to mock the HTTP requests.
A nice thing about React components is that they are usually small and only rely on their props. That makes them easy to test.
First, we will install Enzyme. Enzyme uses the React Test Utilities underneath, but is more convenient, readable, and powerful.
npm install --save-dev enzyme
We will also need to install Enzyme adapter for our version of React. Enzyme has adapters that provide compatibility with React 16.x, React 15.x, React 0.14.x and React 0.13.x. If you are using React 16 you can run:
npm install --save-dev enzyme-adapter-react-16
To test the components we make a setup() helper that passes the stubbed callbacks as props and renders the component with shallow rendering. This lets individual tests assert on whether the callbacks were called when expected.
In a unit test, you would normally import the App component like this:
import App from'./App'
However, when you import it, you're actually holding the wrapper component returned by connect(), and not the App component itself. If you want to test its interaction with Redux, this is good news: you can wrap it in a <Provider> with a store created specifically for this unit test. But sometimes you want to test just the rendering of the component, without a Redux store.
In order to be able to test the App component itself without having to deal with the decorator, we recommend you to also export the undecorated component:
import { connect } from'react-redux'// Use named export for unconnected component (for tests)exportclassAppextendsComponent { /* ... */ }// Use default export for the connected component (for app)exportdefaultconnect(mapStateToProps)(App)
Since the default export is still the decorated component, the import statement pictured above will work as before so you won't have to change your application code. However, you can now import the undecorated App components in your test file like this:
// Note the curly braces: grab the named export instead of default exportimport { App } from'./App'
And if you need both:
import ConnectedApp, { App } from'./App'
In the app itself, you would still import it normally:
import App from'./App'
You would only use the named export for tests.
A Note on Mixing ES6 Modules and CommonJS
If you are using ES6 in your application source, but write your tests in ES5, you should know that Babel handles the interchangeable use of ES6 import and CommonJS require through its interop capability to run two module formats side-by-side, but the behavior is slightly different. If you add a second export beside your default export, you can no longer import the default using require('./App'). Instead you have to use require('./App').default.
Middleware
Middleware functions wrap behavior of dispatch calls in Redux, so to test this modified behavior we need to mock the behavior of the dispatch call.
Example
First, we'll need a middleware function. This is similar to the real redux-thunk.
We need to create a fake getState, dispatch, and next functions. We use jest.fn() to create stubs, but with other test frameworks you would likely use sinon.
The invoke function runs our middleware in the same way Redux does.
Shallow rendering: Shallow rendering lets you instantiate a component and effectively get the result of its render method just a single level deep instead of rendering components recursively to a DOM. Shallow rendering is useful for unit tests, where you test a particular component only, and importantly not its children. This also means that changing a child component won't affect the tests for the parent component. Testing a component and all its children can be accomplished with Enzyme's mount() method, aka full DOM rendering.