Writing React Test with react recommended libraries — & for complete beginners. Jest React Testing Library From https://reactjs.org/docs/test-utils.html#overview ust like most of the people start to create React app using , I would start with it as well. This article is intended to who just start to learn React and wonder how to write some simple tests with their React applications. And j create-react-app First, let's start with the default example. Default Dependencies with create-react-app (2020/05/22) : { : , : , : , : , : , : } "dependencies" "@testing-library/jest-dom" "^4.2.4" "@testing-library/react" "^9.3.2" "@testing-library/user-event" "^7.1.2" "react" "^16.13.1" "react-dom" "^16.13.1" "react-scripts" "3.4.1" There is one test already written to help you to start. React ; { render } ; App ; test( , () => { { getByText } = render( // src/App.test.js import from 'react' import from '@testing-library/react' import from './App' 'renders learn react link' const ); //render is from @testing-library/react const linkElement = getByText(/learn react/i); expect(linkElement).toBeInTheDocument(); //expect assertion is from Jest }); < /> App If you run the command , you will see a similar result as following: $ yarn test App With default create-react-app setting, you can start to write a test without install or configure anything. From the example above, we should learn - - as you can see file is put next to file in the same folder, and it put suffix after App component name as its filename. It is the default conventions suggested by team ( ). Where and how I can put my test files? App.test.js App.js .test.js create-react-app link here and are the tools chain behind the test, they both are ship with create-react-app by default. Jest React Testing Library ; // setupTests.js // Jest is importing from a global setup file if you wonder import '@testing-library/jest-dom/extend-expect' Second, write a test for NavBar component. I am creating a NavBar component that contains links and logo in it. First, I would start writing test without writing the actual component (Test Drive Development). React ; { render, screen } ; NavBar ; test( , () => { render( import from 'react' // screen newer way to utilize query in 2020 import from '@testing-library/react' import from './navBar' // component to test 'render about link' ); expect(screen.getByText(/about/)).toBeInTheDocument(); }) < /> NavBar The test will fail first since I didn't write any code in navBar.js component yet. With code below in navBar.js, the test should pass now. React ; NavBar = ( <a href="#"> about </a> ); NavBar; // navBar.js import from 'react' const => () < = > div className "navbar" </ > div export default For now, you should learn: assertion is from Jest. expect( ... ).toBeInTheDocument() and is from Testing Library. render(<NavBar />); screen.getByText(/about/) Jest and React Testing Library work together to make writing tests in React easy. use "getByText" instead of select by class name is because React Testing Library adapting the mindset of focus on User experiences over implementation detail. screen.getByText(/about/) To learn more to expand and alter the test, you can check out following resources: Jest Testing with React App Tutorial React Testing Library syntax cheatsheet Now let’s expand the test and component to make it more real - React ; { render, screen } ; NavBar ; links = [ { : , : }, { : , : }, { : , : }, { : , : }, ]; test.each(links)( , (link) => { render( <NavBar /> // navBar.test.js import from 'react' import from '@testing-library/react' import from './navBar' // include as many test cases as you want here const text 'Home' location "/" text 'Contact' location "/contact" text 'About' location "/about" text 'Search' location "/search" // I use test.each to iterate the test cases above "Check if Nav Bar have %s link." ); //Ensure the text is in the dom, will throw error it can't find const linkDom = screen.getByText(link.text); //use jest assertion to verify the link property expect(linkDom).toHaveAttribute("href", link.location); } ); test('Check if have logo and link to home page', () => { render( < /> NavBar ); // get by TestId define in the navBar const logoDom = screen.getByTestId(/company-logo/); // check the link location expect(logoDom).toHaveAttribute("href", "/"); //check the logo image expect(screen.getByAltText(/Company Logo/)).toBeInTheDocument(); }); This is what a NavBar component usually look like (maybe need add some styles). React ; NavBar = ( <a href="/" data-testid="company-logo"> <img src="/logo.png" alt="Company Logo" /> </a> <ul> <li> <a href="/"> Home </a> </li> <li> <a href="/about"> About </a> </li> <li> <a href="/contact"> Contact </a> </li> <li> <a href="/search"> Search </a> </li> </ul> </div> // navBar.js import from 'react' const => () < = > div className "navbar" ); export default NavBar; Third, write a signup form component test. After writing a test for static content, let's write a test for more dynamic content - a signup form. First, let's think in TDD way - what we need in this signup form (no matter how it look): An input field for name, which only allows string between 3 to 30 long. An input field for email, which can check whether it is a valid email address. An input field for the password, which can check its complexity (at least 1 number, 1 string in lower case, 1 string in upper case, 1 special character) A submit button. All 3 inputs above are required, can’t be empty. Now, let's write the test. entries = [ { : , : , : }, { : , : , : }, { : , : , : }, { : .repeat( ), : , : }, { : , : , : }, ] /* Prepare some test cases, ensure 90% edge cases are covered. You can always change your test cases to fit your standard */ const name 'John' email 'john_doe@yahoo' password 'helloworld' name 'Jo' email 'jo.msn.com' password 'pa$$W0rd' name '' email 'marry123@test.com' password '123WX&abcd' name 'kent' 10 email 'kent@testing.com' password 'w%oRD123yes' name 'Robert' email 'robert_bell@example.com' password 'r&bsEc234E' Next, build up the skull of the test. describe( , () => { test.each(entries)( , (entry) => { ... }) }) // signupForm.test.js // this mostly a input validate test 'Input validate' /* I use test.each to iterate every case again I need use 'async' here because wait for validation is await function */ 'test with %s entry' async Now, let building the block inside the test. ... test.each(entries)( , (entry) => { render( <https://kentcdodds.com/blog/fix-the-not-wrapped-in-act-warning> */ await act(() => Promise.resolve()); }) ... // signupForm.test.js 'test with %s entry' async //render the component first (it will clean up for every iteration ); /* grab all the input elements. I use 2 queries here because sometimes you can choose how your UI look (with or without Label text) without breaking the tests */ const nameInput = screen.queryByLabelText(/name/i) || screen.queryByPlaceholderText(/name/i); const emailInput = screen.getByLabelText(/email/i) || screen.queryByPlaceholderText(/email/i); const passwordInput = screen.getByLabelText(/password/i) || screen.queryByPlaceholderText(/password/i); /* use fireEvent.change and fireEvent.blur to change name input value and trigger the validation */ fireEvent.change(nameInput, { target: { value: entry.name } }); fireEvent.blur(nameInput); /* first if-statement to check whether the name is input. second if-statement to check whether the name is valid. 'checkName' is a utility function you can define by yourself. I use console.log here to show what is being checked. */ if (entry.name.length === 0) { expect(await screen.findByText(/name is required/i)).not.toBeNull(); console.log('name is required.'); } else if (!checkName(entry.name)) { // if the name is invalid, error msg will showup somewhere expect(await screen.findByText(/invalid name/i)).not.toBeNull(); console.log(entry.name + ' is invalid name.'); }; // With a similar structure, you can continue building the rest of the test. ... /* Remember to add this line at the end of your test to avoid act wrapping warning. More detail please checkout Kent C.Dodds's post: (He is the creator of Testing Library) < /> SignupForm For complete Testing code, please find them . here Ok, now the test is done (maybe we will come back to tweak a bit, but let's move on for now), let's write the component. React ; { Formik } ; { checkName, checkEmail, checkPassword, } ; SignupForm = ( <h1>Anywhere in your app!</h1> <Formik initialValues={{ name: '', email: '', password: '' }} validate={values => { const errors = {}; if (!values.name) { errors.name = 'Name is Required' } else if (!checkName(values.name)) { errors.name = `invalid name`; } if (!values.email) { errors.email = 'Email is Required'; } else if (!checkEmail(values.email)) { errors.email = 'Invalid email address'; } if (!values.password) { errors.password = 'Password is Required'; } else if (!checkPassword(values.password)) { errors.password = 'Password is too simple'; } return errors; }} onSubmit={(values, { setSubmitting }) => { setTimeout(() => { alert(JSON.stringify(values, null, 2)); setSubmitting(false); }, 400); }} > {({ values, errors, touched, handleChange, handleBlur, handleSubmit, isSubmitting, /* and other goodies */ }) => ( <form onSubmit={handleSubmit}> <label> Name: <input type="text" name="name" placeholder="Enter your name here" onChange={handleChange} onBlur={handleBlur} value={values.name} /> </label> <p style={{ 'color': 'red' }}> {errors.name && touched.name && errors.name} </p> <label> Email: <input type="email" name="email" placeholder="Your Email Address" onChange={handleChange} onBlur={handleBlur} value={values.email} /> </label> <p style={{ 'color': 'red' }}> {errors.email && touched.email && errors.email} </p> <label> Password: <input type="password" name="password" placeholder="password here" onChange={handleChange} onBlur={handleBlur} value={values.password} /> </label> <p style={{ 'color': 'red' }}> {errors.password && touched.password && errors.password} </p> <button type="submit" disabled={isSubmitting}> Submit </button> </form> )} </Formik> </div> ); export default SignupForm; // signupForm.js import from 'react' /* I borrow the sample code from formik library with some adjustments <https://jaredpalmer.com/formik/docs/overview#the-gist> */ import from 'formik' /* For validation check, I wrote 3 custom functions. (I use the same functions in test) */ import from '../utilities/check' const => () < > div And the form will look similar like below (no much style, but good enough for our purpose), And with wrong input, the error message will show below the input: If you finished the test above, now the test should all pass, run , with the verbose option and console.log message, you can see how each case is being tested and which one is a good case and which one is not. yarn test --verbose For more testing code examples and different cases, please check out my repo . here Final words. It is difficult for a beginner to learn all of it once so just slow down if it's overwhelming. It took me at least an entire week to learn the basics, and this is just the beginning of writing tests for React applications. It is a hard topic to grasp, but I believe it is worthy to spend some time on it if you want to become a Front-end developer. And the good news is, you have a good start, you should now know how to leverage and to write a test around your react components, and you can start to explore other libraries and solutions out there with this good foundation. Jest React Testing Library I am planning to write another article to cover more advance examples if I got positive feedback on this article, Thanks again for your time. Resources I have referenced to writing this article by Common Mistakes with React Testing Kent C. Dodds by Fix the not wrapped act warning Kent C. Dodds (Opinion about the which library to use for React Testing) My experience moving from Enzyme to react-testing-library (Many good resources to learn more about the Library) Testing Library Recipes By (I started to learn React Test with this article, but it is much more advance, I will write more about it later) Inside a dev’s mind — Refactoring and debugging a React test Johannes Kettmann Special Thanks to and ooloo.io Johannes Kettmann For someone who wants to become a job-ready FrontEnd developer, I would recommend trying a course from . It introduces concepts such as - Creating pixel-perfect design, Planning and implementing a complex UI component, Debugging inside IDE, and , which are not necessary would see from most of the online tutorials or courses. And Yes, I got a lot of inspiration from this course which helped me write up this article eventually. ooloo.io Writing integration tests