Some thoughts about unit test in React

MING WU
4 min readSep 12, 2021

--

  1. Do not wrap fireEvent in “act” or “await waitFor”

If we are testing with fireEvent in react-testing library but found this error in the console

Warning: An update to Example inside a test was not wrapped in act(...)

It means that we did not wait for react to flush the new state to the dom. The app’s state is updated but we did not test it. There is a potential scenario we need to consider/test (that is the DOM is now changed as the state is changed, do you expect it to change?).

Here is an example that replicates this issue:

In this example, we fired a click event and immediately did the assertion. But the state will only be updated after 2s later. Even if the test is pass, we got the “not wrapped in act” warning in the console.

A wrong test that does not wait for react to update the state

The assertion is wrong. We are supposed to wait for react to flush the state and after the state is updated, then we do the assertion.

So in this example, ‘await waitFor’ is the rescue.

when to use wait waitFor

This time it passed without any warnings. Whenever we fired an event, ask ourselves will it trigger any react state updates. If the answer is YES, then always use “await waitFor” to wait for the state to update.

In this example, it is not best practice to really wait for 2s, which is too slow. We could manipulate the time by using jest.useFakeTimers and jest.advanceTimersByTime(2000).

2. fire event with userEvent instead of fireEvent

fireEvent cannot simulate users’ real behaviors. When you fire a click event with fireEvent.click(targetButton), it simply clicks that element, but the button is not focused. However, when the user clicks a button, the button should also be focused.

This example replicates this issue:

fireEvent.click vs userEvent.click

fireEvent.click only fires click event but the focus event is not fired, which is not correct in production environment. userEvent.click fixes this problem. It is just a wrapper of fireEvent but can better simulate users’ behaviors.

This focus issue is discussed here:

fireEvent.focus should be discouraged · Issue #350 · testing-library/user-event (github.com)

Considerations for fireEvent | Testing Library (testing-library.com)

Recommended to read:

Common mistakes with React Testing Library (kentcdodds.com)

Here is the example code from codesandbox:

Other things about unit testing:

1. Passing functions as parameters are better than call them directly in another function.

If you are familiar with dependency injection in angular or c#, you already know that the biggest benefit of Di is that it makes your code easier to test.

Let use check out this example:

example of passing function as dependencies

In this example, we have a ‘displayValueInCapital’ function that returns a capital value, a ‘findName’ function that returns the target object, and a ‘renderName’ function that accepts a list, target string, the findName function and displayValueInCapital function.

We pass findNameFunc and displayValueFunc as dependencies and call them in ‘renderName’. It is much better than directly call them inside of renderName and makes these three functions less coupled.

If we already have tests for ‘displayValueInCapital’ and ‘findName’, then it is unnecessary to test them again in renderName. So in renderName, we can just mock these two functions like this:

mock function dependencies

The first two tests already tested displayValueInCapital and findName functions. In the last test, we can easily mock the dependencies and only test the core logic that is related to renderName.

However, if we just call them directly in renderName like this:

a bad example of renderName

it makes the renderName2 too coupled with findName and displayValueInCapital and not that easy to mock these two functions.

2. Do not use Optional chaining(?.) all the time

By using optional chaining (?.), it means there are more branches to test. One branch is that the value exists, and other branch is that the value does not exist. Additionally, errors or issues could be hidden and hard to find.

--

--

MING WU

aws solution architect associate, developer associate, top 11% in stackoverflow, https://linktr.ee/mingw