If you're looking for more examples on how to test react hooks, I recommend you take a look at the usage section of the react hooks testing library documentation. They have excellent documentation on how to deal with other use cases like errors and asynchronous updates. Thanks toreact-testing-libraryour tests are free of implementation details, so when we refactor components to hooks we generally don't need to make any changes to our tests.
However,useEffectis slightly different fromcomponentDidMountin that it's actually executed asynchronouslyafterthe render has taken place. So all of our query tests which relied on the HTTP requests being sent immediately after render are failing. Let's use theflushEffectsutility fromreact-testing-libraryto ensure that the pending effect callbacks are run before we make assertions.
In order to unit test with React version 16, my team at Uber ATG with used Enzyme to create wrappers around shallow renderings and Jest to mock variables and hooks. The Preact Testing Library is a lightweight wrapper around preact/test-utils. It provides a set of query methods for accessing the rendered DOM in a way similar to how a user finds elements on a page. This approach allows you to write tests that do not rely on implementation details. Consequently, this makes tests easier to maintain and more resilient when the component being tested is refactored. Another approach is to use react hooks testing library.
Today, we'll briefly discuss why it's important to write automated tests for any software project, and shed light on some of the common types of automated testing. We'll build a to-do list app by following the Test-Driven Development approach. I'll show you how to write both unit and functional tests, and in the process, explain what code mocks are by mocking a few libraries. I'll be using a combination of RTL and Jest — both of which come pre-installed in any new project created with Create-React-App . Our app structure is made up of a single component Name, with a test file name.test.js.
Not every testing library is created equally though, and there is significant complexity within React applications that are just too difficult to test easily with jest. This is where Enzyme bridges the gap, as an alternative JavaScript testing utility for React, developed by Airbnb. The library aims to make testing your components easier, by allowing the developer to manipulate, traverse and simulate runtime events, and work with the results. In practice, it works better than it does on paper. Unlike your react components, your tests are not executed in the browser.
Jest is the test runner and testing framework used by React. Jest is the environment where all your tests are actually executed. This is why you do not need to import expect and describe into this file. These functions are already available globally in the jest environment. The last thing we are going to cover for how to test custom react hooks, is about how we can test a custom hook that is using fetch. Now let's dive into how we can update and test custom react hooks with TypeScript.
To properly test stateful functional components, it would be good to start with mocking the useState hook along with the setState function. The SearchReposInput component's purpose is to handle text entered by the user and pass it to the Redux action on button press. When we render the component, the functional component function Students will be executed. The rendering of the component ends with returning the list markup we want to show to the user. The renderHook will return an object, we can get result from the object, and result.current is the state of custom hooks currently. So the unit test use the expect method check the result.current.count if to be zero.
As you know, the hooks can only be used inside a functional component, and it makes us write a dummy component to call a testing hook. Quite often you'll end up with a component which depends on shared context state. Common Providers typically range from Routers, State, to sometimes Themes and other ones that are global for your specific app. This can become tedious to set up for each test case repeatedly, so we recommend creating a custom render function by wrapping the one from @testing-library/preact. So when everyone's upgraded we can remove the Counter function component right? You may be able to do that, but I would actually move it to the __tests__because that's how I like testing custom hooks!
I prefer making a render-prop based component out of a custom hook, and actually rendering that and asserting on what the function is called with. So if you were to refactor the Accordion component to a function component, those tests would break. So what can we do to make sure that our codebase is ready for hooks refactoring without having to either throw away our tests or rewrite them? You can start by avoiding enzyme APIs that reference the component instance like the test above. You can read more about this inmy "implementation details" blog post.
Now that we have covered some ways in which you can test custom react hooks in JavaScript, it is time to look at how we can do the same with TypeScript. Now we have covered the base scenario of how to test custom react hooks and why, we now need to look into how we can apply providers to our hooks. As per usual with all of my blog posts, I will aim to explain how to test custom react hooks without any technical jargon so everyone can understand and get testing. In this post we are going to aim to cover everything about testing custom react hooks that you need to know. Above code snippet is a custom hooks name useCounter, the useCounter would manage the logic about counter. The return object include a current count and method of increase current count.
Just as it is important to test our project as a whole before shipping it to end-users, it's also essential to keep testing our code during the lifetime of a project. We may make updates to our application or refactor some parts of our code. A third-party library may undergo a breaking change. Even the browser that is running our web application may undergo breaking changes. In some cases, something stops working for no apparent reason — things could go wrong unexpectedly.
Thus, it is necessary to test our code regularly for the lifetime of a project. React-testing-library is a very light-weight solution for testing React components. It extends upon react-dom and react-dom/test-utils to provide light utility functions.
It encourages you to write tests that closely resemble how your react components are used. In the hooktest.js file, an additional test block is added. We are testing using the shallow method imported from Enzyme. The shallow method or rendering is used to test components as a unit. It is a simulated render of a component tree that does not require a DOM.
While implementing functional components with hooks, our team noticed a lack of documentation on React version 16 unit testing available online. In the process, we determined various best practices for unit testing functional components with hooks. Let's briefly go over how we can test custom react hooks that uses apollo client with graphql. And now you can see we have a working custom react hook in TypeScript along with our TypeScript unit tests with jest. As you can see, the renderHook function from @testing-library/react-hooks is returning an object with a field called result.
In this post you will learn everything you need to be able know how to test custom react hooks with confidence. Usually, we don't need async API calls to be executed when testing a component, as the act wrapper doesn't wait for it to be completed. In the same way as we mock the context module , we can mock all of the API call functions that are being used in the component.
Then, depending on what behavior we need to test, before rendering the component we need to tell the test what we need to get from the resolved or rejected promise. Once all mocks are prepared, it is time for a thunk action test. This test will check if all asynchronous actions were called in the correct order and carried an expected payload. It will also ensure that the axios get method was called before any Redux action.
Example code for the thunk action is displayed in the image below. Once the user presses the details button on one of the repositories in the repositories list, a modal opens, displaying the selected repository details. One of the sections displays other repositories linked to the selected repository owner. Those "extra" repositories are fetched after the modal mounts, to be ready when users press the additional user repositories dropdown panel. To test if components behave as expected, some preparations are required.
First, mock the fetchAdditionalUserRepos function from the networkActions module along with its response, as shown in the image below. Once the mock is correctly set up, it is time to write some tests. For this component, testing should start by finding an input. It's also a good practice to find input or any other interactive element by value seen by the user like placeholder text, button name, etc.
An example of the test can be found in the image below. Enzyme is a JavaScript Testing utility built for React that makes it easier to test your React Components' output. Enzyme's main role is to prepare React components for testing by mount, shallow, or render methods and to provide various methods for selecting desired components. It also provides a series of APIs used to examine the component's properties. For more details please follow this link to check the Enzyme docs directly.
Enzyme needs a testing library to provide a foundation for the tests it generates. Modern React applications are made by stateless functional components with hooks. In this article I won't focus on testing class-based components which are displaced by functional ones.
Before rendering the component for testing, we create a constant 'setStateMock' and mock it with a jest function jest.fn(). Then we create a mock for useState as shown on line #13. It will accept any value and return a tuple containing the state and our 'setStateMock' function. In our experience, testing class components with React version 16 is relatively simple. We simply ensure that internal functions operate as expected by retrieving the instance of a wrapper's underlying class component.
Because we're using the browser built in fetch library, we're going to have to mock it. We won't initialise the component in our beforeEach because we need to wrap the asynchronous calls in act to ensure that the react lifecycle events and hooks are correctly called. While there are limitations for what we can achieve for hook testing with shallow, those limitations don't exist with mount. Mounting a component is equivalent to render() in react-testing-library; it performs a full dom render. This is ideal for use cases where you have components that may interact with an API, have deferred actions, interact with hooks, or are wrapped in higher order components. Next let's create a basic custom react hook that uses useQuery to request data from an apollo graphql server.
The main thing to do now is to separate some of the functions and functionality from the custom react hook. So first things first, we need to have a custom hook to be able to test, so let's re-use the simple example custom react hook we created before. Firstly, we will need a custom react hook that contains a state, and if we are testing it the hook should already be exposing a way to update the state somehow. The image below displays code for a snapshot test. The renderer creates the method that returns a component snapshot which can be further transformed to a JSON object.
The JSON object format is required by the toMatchSnapshot function which, under the hood, compares the current component tree to the historical snapshot saved in the snapshot file. The code below, also taken from SearchReposInput.test, shows how to mock functions from external modules. It can be useful when a test needs specific conditions like a mocking response from a function calling an external API. In this example, along with Jest's spy on a mocked function, it was necessary to mock function output. Mocked values should be close to the original response to make the testing case more realistic. When the expected response is a promise, the mockResolvedValue method should be used instead.
We first spread the actual react-router-dom, then replace the useParams hook with a Jest function. Since this function is a Jest function, we can modify it anytime we want. Keep in mind that we're only mocking the part we need to because if we mock everything, we'll lose the implementation of MemoryHistory which is used in our render function. When the test starts, Jest automatically finds this mocks folder and instead of using the actual Axios from node_modules/ in our tests, it uses this one. At this point, we're only mocking the get method using Jest's mockImplementation method. Similarly, we can mock other Axios methods like post, patch, interceptors, defaults etc.
Right now they're all undefined and any attempt to access, axios.post for example, would result in an error. Every new React project bootstrapped with CRA comes with RTL and Jest configured. The React docs also recommend it as the testing library of choice. Lastly, the guiding principle makes a lot of sense — functionality over implementation details. It's typically better to make more specific assertions than to use snapshots. These kinds of tests include implementation details so they break easily, and teams can get desensitized to snapshot breakages.
Selectively mocking some child components can help reduce the size of snapshots and keep them readable for the code review. I don't want to write tests to check that AG Grid works. I want to write tests that assert AG Grid renders the expected data, and any cell renderers I have created display the underlying data as I expect.
When I began as an intern, the Web Tools Platform team had just finished adding to and refactoring various components in an application to visualize autonomous vehicle data. We needed to test those alterations and new pieces of logic to ensure particular components still worked as expected. During this evaluation, we compiled best practices and procedures for testing React version 16 components. Enzyme provides us with the dive() utility on the ShallowWrapper API, which allows us to render child nodes one at a time. Be careful though, because this can, and does trigger effects, lifecycle events and other deferred and asynchronous actions contained within that component.
By using dive, you're also expanding the boundary of what a component unit test is as well. The shallow api provides us with useful helper functions that allow us to query the rendered DOM in a jQuery-like way. We can query on direct references of the component, an id, a class, an element, and even more complex query strings. The difference between react-testing-library and enzyme is that enzyme isn't designed to override the testing environment, it's a tool that you can use alongside jest. React testing library can serve the same purpose, but it also provides functionality to fundamentally alter the testing runtime environment.
Jest with snapshops is the React recommended way of working, but they also suggest that you look at trying out React testing library. There's the old-school way of testing, pre-jest, which is to invoke events on elements wrapped in act() and then asserting changes to the dom. We won't be advocating that approach in this post. You wrap your mount in an asynchronous act statement, then write your expectations as usual. This gets a little more complicated if there are other state changes in the component you need to test.
No comments:
Post a Comment
Note: Only a member of this blog may post a comment.