⬆️ ⬇️

React-testing-library library overview

In the material that we are publishing today, Kent Dodds talks about the self-developed library for testing React applications, the react-testing-library , in which he sees a simple tool that can replace the enzyme and promote writing quality tests using advanced techniques in this area. .





The author of the material said that he had long thought about something similar, and as a result, around the middle of last month, he decided to start developing a library for testing that would suit him. In particular, in the enzyme he did not like the fact that most of the capabilities of this library incline the developer to not the best test preparation methods that can harm the project. As a result, he got a simple but self-contained set of tools for testing React DOM.



React-testing-library library overview



Suppose you are going to write tests for React components. You want these tests to be convenient to maintain. In addition, you need to ensure that the tests do not rely on the details of the implementation of the components and test the components in conditions close to the actual scenarios of their use. In addition, you strive to ensure that the tests would remain working in the long term, that is, you want to refactor components (that is, change their implementation, but not functionality) would not violate the testing system and not force you or your team constantly rewrite tests, slowing down the work on the project.



What to choose to achieve these goals? In our case, the answer to these questions was the react-testing-library , a minimalist solution designed for testing React components.

')



React-testing-library logo



This library gives the developer simple tools built on the basis of react-dom and react-dom/test-utild , and the library is designed so that the one who uses it, without any problems would apply in his work best testing practices. The react-testing-library is based on the following principle: the more the testing process resembles a real session with an application — the more confidently we can say that when an application gets into production, it will work as expected.



As a result, instead of working with instances of React's rendered components, tests will interact with real DOM nodes. The mechanisms provided by the library perform calls to the DOM in the same way that project users would do. The search for elements is carried out by the text of their tags (as users do), the search for links and buttons also occurs by their texts (and this is typical for users). In addition, here, as an “emergency exit”, it is possible to apply the search for elements by data-testid . This is a common practice that allows you to work with elements whose signatures are meaningless or impractical for a given purpose.



The considered library helps to increase the availability of applications, helps bring tests to real work scenarios.



The react-testing-library is a replacement for the enzyme . Using the enzyme , you can follow the same principles that are laid down in the library considered here, but in this case they are more difficult to adhere because of the additional funds provided by the enzyme (that is, everything that helps in the details of the test implementation). Details about this can be found here .



In addition, although the react-testing-library intended for react-dom , it is also suitable for React Native through the use of this small configuration file .



Immediately it should be said that this library is not a means for running tests or a framework. In addition, it is not tied to a certain framework for testing (although we recommend Jest, but this is just a tool that we prefer to use, in general, the library will work with any framework and even in CodeSandbox environment!).



Practical example



Consider the following code demonstrating a practical example of working with the react-testing-library .



 import React from 'react' import {render, Simulate, wait} from 'react-testing-library' //      import 'react-testing-library/extend-expect' // Mock-    __mocks__ import axiosMock from 'axios' import GreetingFetcher from '../greeting-fetcher' test('displays greeting when clicking Load Greeting', async () => { //  Arrange axiosMock.get.mockImplementationOnce(({name}) =>   Promise.resolve({     data: {greeting: `Hello ${name}`}   }) ) const {   getByLabelText,   getByText,   getByTestId,   container } = render(<GreetingFetcher />) //  Act getByLabelText('name').value = 'Mary' Simulate.click(getByText('Load Greeting')) //   mock- `get` //       ,      await wait(() => getByTestId('greeting-text')) //  Assert expect(axiosMock.get).toHaveBeenCalledTimes(1) expect(axiosMock.get).toHaveBeenCalledWith(url) //  ! expect(getByTestId('greeting-text')).toHaveTextContent(   'Hello Mary' ) //       DOM! expect(container.firstChild).toMatchSnapshot() }) 


The most important thing that can be learned from this example is that the tests resemble work with a real user application.



Continue to analyze this code.



GreetingFletcher can display some HTML code, for example, like this:



 <div> <label for="name-input">Name</label> <input id="name-input" /> <button>Load Greeting</button>  <div data-testid="greeting-text"></div> </div> 


When working with these elements, the following sequence of actions is expected: set a name, click on the Load Greeting button, which will cause a request to the server to load some text in which the specified name is used.



In the test, you will need to find the <input /> field, as a result, you can set its value parameter to a certain value. Common sense suggests that you can use the id property in the CSS selector: #name-input . But is the user doing this to find the input field? Definitely not so! The user looks at the screen and finds the field with the signature Name in which he enters the data. Therefore, this is exactly what our test with getByLabelText . It detects a control based on its label.



Often in tests created on the basis of the enzyme , to search for a button, for example, with the inscription Load Greeting , a CSS selector is used or a search is made on the displayName of the component constructor. But when the user wants to download some text from the server, he does not think about the details of the program’s implementation, instead he searches for the button labeled Load Greetings and clicks on it. This is exactly what our test does with the help of the getByText helper function.



In addition to this, the wait construct, again, simulates user behavior. Here organized waiting for the appearance of text on the screen. The system will wait as long as necessary. In our test, we use a mock object for this, so the text is output almost instantly. But our test doesn't care how long it takes. We do not need to use setTimeout or something similar in the test.



We simply inform the test: “Wait until the greeting-text node appears.” Note that in this case, the data-testid attribute is used; that same “emergency exit” used in situations where searching for elements using some other mechanism does not make sense. In such cases, data-testid definitely better than alternative methods.



API overview



At the very beginning, the library gave the developer only the queryByTestId method. Read about it here . However, due to the response to the above publication and this fantastic performance , additional methods were added to the library.



Details about the library and its API can be read in the official documentation . Here is a general overview of its capabilities.







The render function returns the following objects and utility functions:





Each of these helper getters produces an informative error message if the item cannot be found. In addition, there is a set of similar query methods (like queryByText ). They, instead of giving an error when there is no element, return null , which can be useful if you need to check the DOM for the absence of the element.



In addition, the following can be passed to these methods to search for the desired item:





It should be noted that thanks to Ento Ryan , the library has its own matchmakers for Jest.





Results



The main feature of the react-testing-library is that it does not have auxiliary methods that allow you to test the implementation details of components. It is aimed at developing tests that promote the application of best practices in the field of software testing and development. We hope the react-testing-library is useful for you.



Dear readers! Do you plan to use the react-testing-library in your projects?



Source: https://habr.com/ru/post/353076/



All Articles