The testing library is a family of packages that help you test UI components in a user-centric way.
The more your test resembles the way your software is used, the more confidence they can give you.
What problems does Testing Library solve?
- You want to write tests that tell you your components are working for users.
- You want your tests to avoid including implementation details so changes on components do not break your tests or slow down the team.
So why pick Testing Library?
- The core library Dom Testing Library is a lightweight solution for testing pages by querying and interacting with DOM nodes.
- The main utilities it provides include querying the DOM for nodes in a way that's similar to how the user finds elements on the page.
- The core library has been wrapped to provide ergonomic APIs for several frameworks including React, Angular, Vue and also for React Native.
DOM Testing Library works with any environment that provides DOM APIs such as Jest, Mocha + JSDOM or a real browser.
What this library is not :(
- A test runner or framework - RTL is different from Jest(I'll explain later)
- Specific to a testing framework
What should you avoid with Testing Library?
Avoid testing implementation details like:
- Internal state of a component
- Internal methods of a component
- Lifecycle methods of a component
- Child components
for the sake of this write up, I'll introduce React Testing Library
React Testing Library(RTL)
React Testing Library builds on top of DOM Testing Library by adding APIs for working with React components
CRA projects have out-of-the-box support for RTL.
You can also install it vianpm
oryarn
npm install --save -dev @testing-library/react
Why do tests with React Testing Library?
- Catch bugs - allows you to catch bugs easily.
- Increases confidence in application - if all your tests pass, means all the parts of your applications are working correctly hence increasing the confidence in your application. This also translates to an increase customer satisfaction.
- Speeds up QA time - if we were running a huge application and we implement a new feature, we'd have to manually test. If we write tests then all we have to do is run tests.
- Tests can serve as documentation - if you're working with larger teams, sometimes code can be very confusing especially to new developers and by looking at tests, new devs can easily understand what the team is trying to accomplish.
Types of Tests
Before we continue, lets understand the different types of tests that there are.
- Static tests - catch typos and type errors as you write code. Usually how a linter works e.g ESlint, TSlint
- Unit tests - they test a piece of code/component in complete isolation. Basically testing a single unit works as expected.
- Integration tests - test how different units/components interact.
- E2E(End to End) tests - They simulate what the user flow would be like. It tests beginning to end. > RTL does not test end to end. For that you can use Puppeteer or Cypress.
Structure of Tests
To better understand tests, we need to know what goes into a test; describe blocks, test blocks, and assertions.
describe block - is a test suite that specifies a larger component or function. A test suite can have multiple test cases.
test block - (also called it block since its defined by an
it
function) is a test case.
-
assertions - assertions are basically what we put in the test block. They can be successful or erroneous. In the above example we use the
expect
function.
before we continue, lets see how we run tests and how RTL works alongside jest
If you're using create-react-app, React Testing Library and Jest come installed out-of-the-box. However if you're using another react framework or you've built your app with custom react and webpack configuration, you'll need to install jest and react testing library yourself.
Under the hood, jest test-runner will match all files with suffix test.js
or spec.js
or as per your own configuration.Jest then runs the tests in these files once you run the command npm run test
or yarn test
(again, or whatever test script you may have in your package.json)
Like I mentioned earlier, Jest is a test-runner, which gives you ability to run tests with Jest in the command line. On the other hand React Testing Library is a testing library to test react components, just like Enzyme.
While Jest provides us with a whole lot of functions; test suites, test cases and assertions, RTL provides more functionality that is geared towards DOM testing for react components e.g render, screen, query methods, assertion methods, and many more.
To better understand this, lets use some of my code and see a real-life example.
Lets dive into the above test suite;
render - inside the test suite we first render the component we want to test. We use
{ render }
method from@testing-library/react
.screen - then we find the elements we want to interact with. Again we use
{ screen }
method from@testing-library/react
.the next step is to interact with these elements.
assert - then we assert the results as expected. we use
expect()
method.
Query methods
okay now, lets look at some of those Query methods I mentioned earlier, some of which I have used in the figure above
getBy | findBy | queryBy | getAllBy | findAllBy | queryAllBy | |
---|---|---|---|---|---|---|
0 match | error | error | null | error | error | array |
1 match | return | return | return | array | array | array |
1+ match | error | error | error | array | array | array |
Await | no | yes | no | no | yes | no |
getBy, findBy, and queryBy - these methods get only one element. If they get more than one element, they throw an error.
getAllBy, findAllBy, and queryAllBy - Always return an array if they get multiple elements they return all elements.
findBy, findAllBy - we can use these methods if we are rendering items asynchronously.
queryBy - does not work with async, returns only one element and if no match it still passes.
Prioritising attributes
In react-testing library, we want to mimic the user interactions as much as possible inside of our tests.
- so we utilize the attributes that follow that e.g:
Attributes accessible by everyone - getByRole (e.g. button, heading), getByLabelText, getByPlaceholderText, getByText.
Semantic Queries attributes - these are for when we have implemented certain a11y accessibility rules - getByAltText, getByTitle
Using TestID - in react sometimes we may need to test a specific component that has a unique testId. in such instances we use getByTestId.
This is already getting too long. I'll stop it here for now. I'll attach some links to certain articles that helped me prepare and improve my testing skills.
This cool article
This other article
These official docs
This youtube playlist
That's all for now, till next time, have a great time testing your applications. One more thing before I go, here's a sample implementation of how I use Testing Library with react-native.
Top comments (0)