I have a really big application with react(lot of pages, modals, tables,etc) and I'm using redux-saga for managing the state. I have a lote of stores and almost in all the components I use the useSelector method for getting the data from the store and many hooks inside them because of logic.
I want to start testing the application, specially to avoid that the app crashes when there is data undefined, invalid, etc. What library do you recommend me to apply in this case ?
React Testing Library and Jest both have different responsibilities "react testing library" is not a test runner meaning when u enter command npm test or npm run test
it is jest responsibility that collect all the files ending with .test.js and runs each test case and show pass and fail results in your console like below
react testing library provides you function to catch dom element and perform some action below are some of its function
render, fireEvent, waitFor, screen
you can also use Enzyme(another popular testing library) for such function to access dom element
EXTRA: developer often confuse among
jest
react-testing-library
Enzyme
Here Enzyme and react-testing-library are two similar things and alternatives to each other means you can use
enzyme with jest or
react-testing-library with jest
you can also use all three i.e react-testing-library+Enzyme with jest
but you can not use Enzyme and react-testing-library without jest or any other test runner eg: Mocha
where jest(testing-framework) will collect all .test.js files execute all the test cases and put the output in console with detail like how many pass and fail and react-testing-library or enzyme(both are testing library) will help you to perform event and accessing dom element
Common Questions/Confusions for React Developers
What is React Testing Library?
Provides virtual DOMs for tests - Any time we are running tests without a browser, we need to have a virtual DOM so we can do things like click elements and we can see if virtual DOM behaves like it should do (like changing colour of a div on a button click and so on).
How Jest is related to React Testing Library?
Jest is a Javascript testing library(not only for React, but for any JS related framework or library).Jest is a test runner and is responsible for
Finding Tests
Running the tests
Determining whether the tests pass or fail
Both React Testing Library and Jest work together (look at the below image to understand this point
Create-React-App comes with React-Testing-Library by default which also includes Jest, so you don't need to install anything else
What is Enzyme and Mocha?
Enzyme (developed by Airbnb) is an alternative to React-Testing-Library (but not Jest).
Remember from the above screenshot that React-Testing-Library was used to provide virtual DOM. Similar thing in some variations will be done by Enzyme. Enzyme, like RTL is also not a Test Runner, so it might need a runner like Jest.
Mocha is an alternative to Jest
Below combinations are possible
React Testing Library + Jest (React's recommended combination, inbuilt into Create-React-App)
Enzyme + Jest
React Testing Library + Mocha
Enzyme + Mocha
What are the different type of Tests?
Unit Testing
Tests one unit of code at a time. May be a single function or a component without depending on other units
Integration Testing
Tests how multiple units work together. Testing interaction between different functions/units/components
Functional / Behavioural Testing
Functional testing means testing the behaviour of a function/software. We might be testing if the software does the right thing with the particular set of data. That might be an integration test as it might have to interact with different units. So the functional test can be an integration test as well
The functional test can also be a simple unit test. Let's say on a button click, the div turns red. This might be a simple unit test but still it can also be considered as a functional test as it tests for a particular behaviour of CLICK TURNS RED OR NOT
So, the functional test means, not testing the code but testing the behaviour. React-Testing-Library encourages functional tests
Acceptance/End-to-End(E2E) test
This is an End-to-End testing where we need a browser and might also need the server
Popular tools for E2E testing are Cypress and Selenium
Cypress supports only Javascript whereas Selenium supports all popular languages like Java, Python, Ruby, C#, Php, etc. Check - Cypress Vs Selenium
React-Testing-Library doesn't support E2E testing
What is Mocking or Stubbing?
Let me explain this with a scenario. Let's say you have made a website for checking the climate of different cities. This app goes and gets the data (using fetch or axios library) from an external source called Weather-API. You can search for any city and it gives you proper climatic conditions.
Now we need to test this app. Let's say we are writing a unit test to test the function that has this functionality where, when a city is passed as a param it makes a call to an external API (Weather-API in this case), fetches the data and then you can write an expect statement to test if the expected value is equal to the fetched value.
If you take a closer look here, we are actually calling Weather-API in our test as well every time we run the unit test. The disadvantages of this approach are:
We are testing the external API in our app (which is not required)
If we do this, we are wasting our API calls (which are billed in most cases)
We don't need to test external API as Weather-API developers might have already tested it and we need to worry about testing only our app and not the external service
So what's the solution here? The solution is to mimic the response from the external API and use it in our test as the actual value and we can test this against the expected value. This is called Mocking. The reason we are doing this is we already know what the external service gives us back and we don't have to call that API anymore but simply hardcode the values as the actual values.
Reference: Testing React with Jest and React Testing - Bonnie Schulkin
Resources:
To understand the testing and mocking those tests, these are some good free youtube videos
JavaScript Testing - Unit, Integration & e2e - Max, Academind
JavaScript Testing - Mocking Async Code - Max, Academind
React Testing Library Crash Course - Laith Academy
Stackoverflow - What is mocking
To understand in more depth, these are some paid udemy courses
The React Testing Library Bootcamp - Laith Harb
Testing React with Jest and React Testing - Bonnie Schulkin
React Testing Library is not an alternative to Jest, because they need each other and every one of them has a clear task.
Jest is a test runner, which gives you the ability to run tests with Jest from the command line. In addition, Jest offers you functions for test suites, test cases, and assertions.
React Testing Library, in contrast to Jest, is one of the testing libraries to test React components.
If you are using create-react-app, Jest (and React Testing Library) comes by default with the installation. If you are using a custom React setup, you need to install and set up Jest (and React Testing Library) yourself.
You might want to look for more on: https://jestjs.io/docs/en/tutorial-react & https://testing-library.com/docs/react-testing-library/intro/. Also you can follow up for more on issues and disscusions on github channels of the libraries.
JEST
"Jest is a delightful JavaScript Testing Framework with a focus on
simplicity. It works with projects using: Babel, TypeScript, Node,
React, Angular, Vue, and more!"
src: jest
TLDR: Jest allows you to test any of the above without much boilerplate quickly. As a framework, the framework's code calls your test code. Jest looks for changes made to the code to run specific test cases etc. You can write test's for React just using Jest (react documentation)
React Testing Library
"The React Testing Library is a very light-weight solution for testing React components. It provides light utility functions on top of react-dom and react-dom/test-utils, in a way that encourages better testing practices".
src: RTL
TLDR: It is a library (i.e., you call the code). It provides some utilities on top of just using Jest and the default react-dom/jest-utils that help us write tests quickly and with less boilerplate (using multiple act() calls etc.) and closer to real-life use (accessibility)
Use RTL with mock server workers to make your life easier for large projects.
I'm evaluating widget toolkits for a new project, and I want to be sure that I can write unit tests for them first. So I've created a simple component using Material-UI based on react-autosuggest using axios to query a simple API. The component works just fine, but I can't seem to get it to work with React Testing Library.
The test is failing with this: "Cannot read property 'px' of undefined"
It almost seems as though Material-UI isn't loading fully, so the component can't be tested until it is. I have no previous experience with unit testing React components, but shouldn't it load in all the dependencies at the top of my component when it renders?
Here's a demo of my failure in Code Sandbox:
https://codesandbox.io/s/testing-material-ui-problem-ndn9f
I'm trying to test a component that uses a custom hook. That hook uses context with the useContext hook.
My problem is that the context persists between two consecutive tests. I've tried mocking the context, but that doesn't help.
You can see the code in this codesandbox: https://codesandbox.io/s/l0192w68z though I couldn't get the tests to run there...
I also uploaded it to github where the tests actually run: https://github.com/uriklar/react-testing-library-with-use-context
I'd appreciate any pointers! How can I get a fresh context on every test run.
Thanks!
The problem is that your <MenuItem /> components are using the same (default) store between tests. There were a few issues actually and I talked about them all in this livestream and here's a pull request showing what things you can do to improve things.
I hope that's helpful!
Besides render uses "traversal library Cheerio"..
I've just replaced all my mount's with render's and it works the same.
They look similar to me.
What should I choose? Is API of those two is somehow not identical?
What are particular recommendations when to use render over mount?
Render doesn't need a global DOM to be available. So it allows the tests to be run outside of an environment like a browser. In your case, if your test cases were working before it would seem you are running the tests in a browser (since mount worked) and you wouldn't need to use render. If however, your tests were failing because there was no global DOM available, then render might be a good solution
http://airbnb.io/enzyme/docs/api/render.html
Mount is FullDom rendering. Take a look at the official documentation for examples. From my understanding if you want to test lifecycle events such as componentDidMount you should use mount.
Docs: http://airbnb.io/enzyme/docs/api/mount.html
I can't tell if my two issues are related, but I figured there might be a chance so here goes.
I'm playing around with React (using webpack / commonjs) and I'm having a basic level of success. Components render on the page successfully.
Unfortunately, no events are working (even testing simple click handlers) and also my React dev tools do not load my hierarchy at all, just showing <Top Level></Top Level>. I've tried the expose-loader (for handling the dev tools issue) to no avail.
Any ideas at all much appreciated!
edit: It's probably worth mentioning that I know my event handlers are being loaded (if i pass as a handler a reference to a function which logs to the console, for instance, the messages appears). The events themselves simply aren't firing/being directed to the handlers.
edit 2: Also worth noting (based on the commonly suggested solutions for this problem) that I have also tried just exposing React to the window for the dev tools, and that if I go somewhere like the React homepage my react dev tools work just fine.
I had this exact same problem. In my case, I was using browserify, bower, and debowerify. My React app was spread across several modules. In one of the modules, I was importing react/react-with-addons, while in the other modules I was just importing vanilla react. Once I updated all my imports to use react/react-with-addons, the problem went away. For example, I initially had something like:
// module1.js
var React = require("react");
// module2.js
var React = require("react/react-with-addons");
When I changed it to the following, everything started working again:
// module1.js
var React = require("react/react-with-addons");
// module2.js
var React = require("react/react-with-addons");