Let's understand all aspects of testing React components in isolation. We'll write basic tests for edge cases and basic usage.
Let's try to test the behavior of the button component based on the passed parameters.
Understanding tests for React components
Firstly, we need to create Button component which will be fully customizable. We'll use approach called types first - first interfaces, implementation later:
Inside consts.ts file we'll store constants. We want to limit options for better type-safety.
Take a look at implementation for Button component:
You can choose shape, size and other aspects. This is how it looks like in storybook:
We need to think before creating the tests. What should be tested? Component takes several props and creates className for styling purposes. In addition, there are other native button properties injected which comes from ButtonProps interface. So it's good to test:
So let's write first test - the easiest one:
The method getByText allows you to get the HTML node by text. This method is using expect inside. If the element is not found - the test will not pass (a slight shortening).
In React we use jest and react-testing-library on daily basis. First one is responsible for faking DOM behavior and test execution.
The second one is simple lib that allows you to write tests from user perspective. Instead of searching by id or className we should select by text, role or something what is visible for user (placeholder, input value).
Adding missing tests
Let's add tests for:
First test checks implementation details. If we change order of classes or we'll add new class - this test will fail. Failure in this case doesn't mean bug. It means the order of classes changed. This is called false negative and should be avoided if possible.
In second we passed role property to check native button properties injection.
Dealing with ugly tests
How can I fix previous test? You can cover this case with other type of test - visual test (we'll explain it in another lesson).
Another option is to leave it as it is. In this case you need to remember that it may fail and it's fragile to change in implementation.
Sometimes you need to test implementation, we'll cover it in next lessons.
Unfortunately, nothing is perfect. Such a test has value, but it carries risks. It's worth to highlight it somehow, so developers won't be surprised that the test fails after class names order change. In such situations I always add [FRAGILE] before the test description, so later it's easy to find these and replace them. After change our fragile test description will be:
As a developer you decide which suites are valuable for you. Tests should save you from bugs and regression instead of being perfect and pretty. It's is not a fashion revue.
You can find full implementation on this branch.
As you saw - React components testing can be tricky. Some areas are hard to cover with qualitative unit tests. These areas requires other type of tests or practices which we'll cover in next lessons.
If you enjoyed it, be sure to visit us on Linkedin where we regularly upload content from programming.
- 1. Basics
Grouping the tests
The usage of describe and it
The best practices for naming tests
Navigating the different types of software tests
- 2. Mastering unit testing
Project and tests setup
Unit tests review
React component testing
Snapshot testing in React
Understanding stubs in testing
Understanding mocks in testing
Creating testing fixtures
Using spies in React and Typescript
Mocking environment variables
Using dependency injection pattern to improve fixtures
- 3. Mastering integration testing
Understanding the integration tests
Using MSW library to remove implementation details from tests
Creating fixture for MSW to reduce boilerplate and setup
- 4. Mastering e2e tests