Tutorial on Testing React with TDD — Part 1
By Lawton Spelliscy
Over the past few years, React has been widely adopted for new web applications. The benefits of React are numerous, including the ease of testing your basic UI elements. In this blog post, I’ll be showing you some basic examples for testing your code.
Test Driven Development (TDD)
At TribalScale, we use a TDD approach when writing our tests. This method basically means we write the tests for a piece of functionality prior to writing the code that implements said functionality. Now, I will admit that this can feel unintuitive and cumbersome at times, but there are numerous benefits. Because code is written to pass tests, instead of tests written to pass code, the code tends to be more modular and easier to test. TDD also forces you to define the purpose of each function more concretely.
All the code used in this example are available here.
If you’d like to follow along with the example, I created a branch that has the initial code setup prior to my example.
For the base of this project I used TribalScale’s React Starter Kit and tried to minimize the requirements for the simplest React application.
React, of course!
Mocha: Testing Framework, used to run tests and show the results.
Chai: Assertion Library, used to determine under what conditions a test will pass.
Sinon: Mocking Utility, used to mock functions to isolate code and mimic test scenarios.
Enzyme: React Testing Utility, used to mount React components on a virtual DOM, which allows you to interact with the React component without actually rendering the component in a browser.
I chose to use Mocha, Chai, and Sinon instead of Facebook’s Jest. I’ve used both approaches and personally, I found Jest a bit too slow and the auto-mocking feature a tad overkill. Furthermore, I find having to manually mock functions and objects with Sinon forces you to think more on how you will mimic a test scenario.
I chose Enzyme over React Test Utils because the API is a lot cleaner.
Babel: Convert ES6 to ES5 syntax
Webpack: JS bundler
React-Dom: A dependency library for Enzyme used to manually render a React component into DOM
React-test-renderer: Dependency library for Enzyme
For this testing example, I used a very basic web application for simulating a calculator application. The basics of the UI have already been created: a user can type into the input field and there’s an ‘=’ button, but there‘s no functionality behind them. The first functionality that we will be adding with TDD is as follows:
Given: Numerical values separated by ‘+’ symbols are entered in the equation field
When: User clicks the ‘=’ button
Then: Sum of all numerical values should display to the right of the ‘=’ button
Test # 1:
First, let’s start with the functionality behind the UI. The input is a string with numerical values and ‘+’ symbols separating them. Our first step is to make the utility function that takes that input and returns the sum of the numeric values.
Using the Chai expect library and Mocha’s describe/it syntax, we are testing whether our utility function parseEquation returns 2 when we input ‘1+1’. Before implementing the functionality, we run the test to confirm if the test is actually failing. This helps us avoid false positives.
Implementation # 1:
The project has already set up a package.json script to run Mocha. The command runs all files ending with ‘_test’ with the extension ‘.js’ or ‘.jsx’. It also uses Babel compiler to allow for ES6 syntax. To run, simply run the command ‘npm test’. As you can see, our test is currently failing as we have not yet implemented the function. Here is a basic implementation:
Now if we run our tests, we can see that they are still not passing.
The issue is that we are trying to add strings together, resulting in concatenations instead of a summation. Let’s try again.
If we run our test again, we can see it’s starting to pass.
Test # 2:
After we implemented the logic, the next step is to attach the UI element. Since we already confirmed that the parseEquation function works, we need to verify if the input will send to our new parseEquation function when a user selects the ‘=’ button.
Here I am using Sinon to mock the parseEquation function in my math utility library. I mock the function in beforeEach and restore it in afterEach. These functions are provided by Mocha and take a description and a callback function that will be executed before and after each it inside of my describe. This assures that each of my mock implementations will be reinitialized and not affect any other test scenarios. It is very important to restore the mocked function. Otherwise, it will be mocked in other test suites as well.
I then use shallow from the Enzyme library to initialize my calculator component in a virtual DOM. I then simulate clicking the one button in the component and assert that my parseEquation was called with the correct input.
Again, we will run the tests to confirm they are failing.
Implementation # 2:
We then implement the fix.
When we click the ‘=’ button, we are now calling the parseEquation and passing the equation’s contents to our parseEquation function. Running the tests again should result in a pass.
Test # 3:
We are passing the value. Now we need to make sure we display the result of parseEquation.
Here I am using Sinon to set what the parseEquation will return. The reason I confidently can mock parseEquation is because I already tested its functionality previously. I simulate the click and confirm that my new result field is now displaying the same value. When we run the test for the first time, we’ll get an error like this:
Enzyme cannot find the result label because it doesn’t exist. Let’s add the label and attach it to our parseEquation output.
Implementation # 3
Note: this in calculateValue needs to be bound in the component constructor to access React’s setState.
I split off the onClick event into its own function, calculateValue. It takes the result of parseEquation, updates the React state, and displays that value inside a label with the class ‘result’. If we run our tests they should now pass.
We have successfully implemented the first tasks implementation. You can run the application by running ‘npm run dev’ and open localhost:8080 on a browser. Try it out!
I just walked you through the basics of creating tests with React. You should now feel more comfortable with writing an initial test for a React application. I hope you also see some of the value in using TDD. In part 2, I’ll build on our user story, show you how to implement more complex tests, and introduce more features from our test libraries. If you have any questions or thoughts, leave me a comment below!
One of TribalScale’s first employees, Lawton Spelliscy, is a Lead Agile Software Engineer at TribalScale. He’s currently helping TribalScale’s Transformation Services through defining and running the Engineering component with some of the biggest brands. A love of all things nerdy has led him down the dark path to programming. An oddball at heart, his interests also include hiking, travelling, musicals, board games, and what he calls ‘dancing’.