Testing a react application with Jest
this is the second part of my post about web development using React, Redux stacks with docker and automated testing. You can find my first episode here
In the previous post, I already explained the stacks including docker, express, mongodb, mongoose, ES6 for developing backend. Docker, eslint with AirBnB rules, swagger were utilized to enforce the application. The logic of the application was ensured by tests running on Jest. On the other hand, front-end side was equipped with a wide using framework React and its famous accompany Redux. In addition, some middlewares are Redux Thunk, Redux Promise, were chosen to enhance the power. client side logic is also ensured by tests written on Jest. At the last mile stone, I was having some problems with testing at client side.
The first problem I had was testing redux integration. I found a very good library to mockup redux store, redux-mock-store. With this library, I could easily test redux actions, redux reducers with mocking a store. But later I decided to test the whole application without testing separately redux.
The most headache problem I was having is testing ajax requests. In my application, there are several components fetched content from server asynchronously by dispatching redux thunk actions. this is quite common technique when working with react and redux. However, it leads to headache matters when running tests without real browser environments. I managed to solve all problems related to ajax testing steps by steps. I will make a separate session for explaining detail about problems and the solutions.
Problem 1: mockup ajax requests,
there are many posts on internet and each of them present a different way to solve this problem. I also have a solution myself. I start my solution with nock which provides abilities to inject into the request process. The limitation in my opinion of nock is that it hijacks only full domain requests which means your relative requests are not modified by nock. I overcome this matter by using axios to make ajax requests and axios provides a way to specify a domain by default. this line of code axios.defaults.baseURL = … will make the trick. And I have spent 2 days to realize that I need this assignment axios.defaults.adapter = httpAdapter where httpAdapter from ‘axios/lib/adapters/http’. The previous code will help jest running axios without any network exceptions.
Nock helps me to interrupt http requests. the next step is to prepare data for mocked up requests. At this step, I used super tests requests to fetch test data made from server tests. Responses from super tests requests will be injected into nock requests. In the end I have mocked requests with real responses from server. Now, it is the time for problem 2
Problem 2: verifying the application after having data fetched through ajax requests.
this matter was really tough since I did not have any clue when ajax requests finish and when redux updates react components. I have thought of several alternatives such as basing on store subscribe or delay verification. In the end, I decided to use a delay technique. Basically, delay technique uses setTimeout as essential. However, jest does not work well with setTimeout if you do not have some tricks. And a function that returns a promise within its is a setTimeout will do the trick.
Finally my tests look like that, Render App => delay 100ms => trigger some actions => delay 100ms => getState => verify Components and state.
Problem 3: test rendering React Component and events on React Component
this problem was pretty easily solved by using Enzyme to render React Components and trigger events. Along the time working with the project, I have suffered some issues when interacting with React Components that I needed to add some console logs to know what extra data needed when triggering events. In almost cases, Enzyme does all the job for you.
Conclusion
wrapping up, I shared a story of my own experience on building a web application using the following stacks
- Mongo DB, mongoose — database
- Express — web server
- Webpack, Gulp — preprocess js, css
- Nodemon — for development
- Eslint, AirBnB rules— consistent coding
- Jest — test runner
- Docker — sandbox hosting
- Swagger — api explanation
- SuperTest — mockup requests at server
- React — essential clientside business
- Redux — maintain states at clientside
- Redux-Router — routing at clientside
- Redux-thunk — enhancing power to action creators
- Axios — making requests.
- Nock — mocking requests at clientside.
- Delay to verify React Components
