Some developers treat it like a religion, and others think it’s an unnecessary waste of time. I am talking about Test Driven Development and Unit Tests.
In this series of articles, I would like to introduce you to the test strategy I am using successfully in Living Design Systems. I will present why and how to test different areas in a React Component Library.
A little Disclaimer — even though this series uses React Code, some of the broader ideas will still apply to other libraries.
Find the other parts here:
“It takes me longer to write the test than to write the component”
I have heard this from many developers when I start talking and introducing the test-driven approach to them. So let me begin with why test-driven development is good for you.
Definition of Ready
In Scrum, there is a lot of fuzz about ‘definition of ready ’. Only when a story is well prepared and ready to work on, we can estimate it and fully implement without interruptions. In our team, part of the definition of ready is that we feel able to write a test, based on the acceptance criteria of the story.
Writing a test helps you to identify the problem before trying to implement the solution. You will get a more precise overview of what has to be done, and you are less likely to forget a functionality or an edge-case.
Writing tests is an excellent pair-programming exercise. One Person is writing the -test and the other person is implementing the functionality, based on the test. I also believe this is especially helpful for junior developers to work on both sides.
It’s almost impossible to write bug-free code, even with testing. But when you have most of your system covered with tests, you can use them while debugging to find the failing case and add a new one to prove that your bug is gone for good.
Why is frontend testing so special?
Let’s say you write an algorithm in python which should calculate an average from an array. Of course, you want to be sure it covers all your corner cases. To test it, you would write another function, that is calling your algorithm with the edge-case parameters, and then you can compare the result of your function with the correct result. While in frontend, you might not even know where to start, because you have a button that should turn yellow and then call another function, once the user clicked on it.
The areas you have to cover to test your button thoroughly would be: Accessibility, Functionality and Design
Plan of Attack
Now that I convinced you and your team to start writing tests — you still don’t know where to start. And we should find consent within our team. Because just aiming for 80% test coverage will not guarantee you to have a well-tested product.
1) What type of component should have a which kind of tests?
Not every component needs and can be tested in all areas. A rule of thumb is, the more complex a component, the more areas need to have tests. In my Team, accessibility tests are applied to all components. If a user can’t read the text on a card because your contrast is too low, or you don’t have an alt-text for an image, there is no point of even having it.
If there are circumstances under which your component changes its state, it’s a good hint that this should get tested within a functional test.
Another test we usually always apply is a snapshot design test, which makes it much easier to detect design bugs.
2) When should the tests run?
Wow, we made it, after three months hardcore refactoring you and your team reached a test-coverage of 75%! Life is glorious in this moment. 3 Weeks later, after an update of one of your components, a bug appears. You are furious because you are sure you have written a test for that. So you jump on the bug ticket and run this test — and it fails! But why did no one recognise? Well because no one did run this test before deploying to production.
To avoid such situations, you can pinpoint to places that these tests run automatically, depending on your setup and workflow
- as a Git hook — before pushing the tests have to run successfully
- in GitHub Actions — every time a pull request is opened, they only can be merged once your tests are green
- On your CI — before building and deploying the project, the tests have to run.
3) Which tools do you want to use?
As you might have asked yourself already, how can you write an automated unit test for a button? The answer is — you need to use some additional tooling. The duty of such a framework is.
- write assertions
- mock structures and data the component receives
- render the component in a virtual browser to enable inspecting it
- simulate user events like clicks
- manipulation of the components properties and states
If you are using create-react-app as your boilerplate, it already ships with Jest, which is why we will use Jest for all upcoming code examples.
In Part 2 of this series, we will start setting up our test environment and let it run automatically.