Read More
đCelebrating 25 Years of Tech Excellence and Trust - Learn More
Quick Overview: Snapshot testing is an important aspect of testing React applications that ensures the stability and consistency of user interfaces. In this article, we will explore the concept of snapshot testing using React Testing Library. We will delve into what snapshot testing is, how it works, and why it is a valuable tool for React developers. By the end, you will clearly understand how to leverage snapshot testing to enhance your testing suite and improve the reliability of your React applications.
Testing is a double-edged sword. On the one hand, a robust test suite simplifies code refactoring and instills confidence in its intended functionality; on the other hand, it comes at the expense of writing and maintaining tests, like any other code.
However, testing automation has become an integral process in large applications with many components. Itâs very important to understand and learn about several methods of testing software applications in order to deliver a seamless user experience for your project.
In an ideal realm, we could effortlessly validate our code's correctness with minimal additional code.
And snapshot testing comes out to be the visionary for every developer who has to validate code with less effort. If you are a React developer unfamiliar with one such testing technique, âSnapshot Testingâ, itâs time to understand it well.
This detailed guide on Snapshot testing for React components with Jest will give you a basic introduction to testing management and how to start using them with React development.
Put RTL into Practice by Implementing It in Real-World Scenarios
Ask Us How
Snapshot testing for React library helps you determine whether the output continues to behave as expected or not. This is a very useful testing method as there are higher chances that something will break as you revisit your code to make updates over time.
Snapshot testing adopts a different strategy from strict Test Driven Development (TDD), where the standard practice is to write failed tests first and then write the code to make the tests pass.
You require working code before writing snapshot tests for a React component. Then, create a snapshot of the expected output considering the given data. The component is committed along with the snapshot tests. The rendered output for the test will be compared to the snapshot using the testing framework Jest.
A failed test can indicate two things. If the test results are unexpected, you may need to fix an issue with your component. If the test results are as expected, it might be necessary to update the snapshot tests to accommodate the changed output.
Snapshot testing is a powerful testing technique used in React Testing Library to ensure that every React component behaves as expected over time. React snapshot testing verifies that a React componentâs rendered output remains aligned with a previously stored âsnapshotâ of the expected outcome.
The primary goal of snapshot testing is to identify unexpected changes in the UI by comparing the existing outcome with the stored snapshot. Generally, snapshot testing happens during the test automation of front end development. Hence, it allows you to verify that your React components are rendering correctly in your React project without any issues.
When conducting snapshot testing on a React component, the testing library renders the component and stores a serialized version of the rendered output. This output is generally saved in an HTML or JSON file. This snapshot file is stored alongside the test suite.
The library compares the recently rendered output with the stored snapshot during subsequent test runs. If it finds any differences, the test fails. This shows an error that componentâs UI has changed unexpectedly. Now, itâs you who has to examine and verify whether changes are intended or not. You can update the snapshot to reflect the updated output, thus "approving" the modifications if the changes are indeed intentional.
In this tutorial, we will show you how to create snapshots for testing a simple React.js web application using Jest, a JavaScript testing framework. You will simulate changes in a React.js application using the snapshots you produce using Jest. You may discover that snapshot testing is a powerful remedy for uncomfortable, continually changing text assertions.
Here are some prerequisites you will need in order to perform React snapshot testing.
In case, if you have the latest version of NodeJS â Node.js 20 and React 18, you can seamlessly execute this test with Jest.
Snapshot testing doesnât entirely replace other testing libraries and techniques. You can utilize ReactTestUtils and Enzyme. Also, you can separately test Redux components (actions, reducers, etc.).
Letâs go through step-by-step process to create a snapshot test with Jest for React components.
Well, you must have something to test. Hence, you need to create a React App using Create React App.
We will name this project â snapshot-testing-project
.
Open your terminal and execute the below command:
$ npx create-react-app snapshot-testing-project
Now change your directory path into the newly created app directory:
$ cd snapshot-testing-project
Now is the time to start the app:
$ npm start
By this time, you should have a React application running. Now, you have to create a component to test. The component you'll be creating for this tutorial renders the item props it gets.
Create a components subdirectory under src in your terminal.
$ mkdir src/components
Now, create a listings.js
component.
$ nano src/components/listings.js
Add the following code to listings.js
.
import React from 'react';
import PropTypes from 'prop-types';
/**
*Render a list of items
*
*@radixweb {Object} props â Items list
*/
function listings(props) {
const { items = [] } = props;
// A single item in the list, render a span.
if (items.length === 1) {
return <span>{items[0]}</span>;
}
// Multiple items on the list, render a list.
if (items.length > 1) {
return (
<ul>
{listings.map(item => <li key={item}>{item}</li>)}
</ul>
);
}
// No items on the list, render an empty message.
return <span>Found no items in list</span>;
}
listings.propTypes = {
items: PropTypes.array,
};
listings.defaultProps = {
items: []
};
export default listings;
The code will render listings props based on the amount:
<span>
element.<ul>
).Now update App.js
to render our component:
$ nano src/App.js
Write down the below code and replace it with content of App.js
:
import React, { Component } from 'react';
import listings from './components/listings';
class App extends Component {
render() {
const items = [
'Web Development',
'App Development',
'Mobile Development'
];
return (
<listings items={items} />
);
}
}
export default App;
Now you will see the values in the app browser.
Output:
*Web Development
*App Development
*Mobile Development
However, it will show an unordered list as there were multiple items.
Now is the time to add your snapshot tests.
Test Apps to be More Accessible and Ensure Your Tests Will Work with Actual DOM Nodes
Get Your React App Tested Now
The first thing you need to do is to delete the App.test.js file, which you created using Create React App.
$ rm src/App.test.js
It isnât required for this tutorial.
You have to install react-test-renderer
â a library that allows you to render React components as JavaScript objects without using a DOM.
$ npm install react-test-renderer
Now add the first test once you create a listings.test.js
file.
$ nano src/components/listings.test.js
Create a test that displays the listings component without any props being passed down:
import React from 'react';
import renderer from 'react-test-renderer';
import Items from './listings';
it('renders correctly when there are no items', () => {
const tree = renderer.create(<listings />).toJSON();
expect(tree).toMatchSnapshot();
});
Let's execute the testing now. Create React App performed all initialization for creating tests:
$ npm test
The test for "renders correctly when there are no items" should be passed:
While executing a snapshot test for the first time, you will see a new file created inside a _snapshot_
directory. Since we have created a listings.test.js
file, the file is appropriately named listings.test.js.snap
.
The content of listings.tests.js.snap
should be:
// Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing
exports[`renders correctly when there are no items 1`] = `
<span>
No items in list
</span>
`;
This snapshot is the exact match of the componentâs output.
Jest makes the snapshot files human-readable with pretty-format
.
The tests for the two additional scenariosâone with a single item and one with several itemsâcan now be created.
Open listings.test.js
:
$ nano src/components/listings.test.js
Add the following lines of code:
// ...
it('renders correctly when there is a single item', () => {
const items = ['one'];
const tree = renderer.create(<listings items={items} />).toJSON();
expect(tree).toMatchSnapshot();
});
it('renders correctly when there are multiple items', () => {
const items = ['one', 'two', 'three'];
const tree = renderer.create(<Items items={items} />).toJSON();
expect(tree).toMatchSnapshot();
});
Now there are three tests written: one for no items, one for a single item, and another for multiple items.
Run the test again:
$ npm test
Once these three tests pass successfully, you will find them in _snapshots_
directory.
The next move is to address a failing test by updating a snapshot test.
Build Rock-solid, Well-tested Web Apps with React and Redux
Hire Our Experts
You will need to modify the listings
component and re-run the tests to understand why you need snapshot testing. This will serve as a simulation of what might occur if changes were made to a project in the development stage.
Open listings.js
file.
$ nano src/components/listings.js
Add class names to the span
and li
elements:
...
/**
*Show a list of items
*
*@radixweb {Object} props - List of items
*/
function listings(props) {
const { items = [] } = props;
// A single item in the list, show a span.
if (items.length === 1) {
return <span className="item-message">{items[0]}</span>;
}
\
// Multiple items on the list, show a list.
if (items.length > 1) {
return (
<ul>
{items.map(item => <li key={item} className="item-message">{item}</li>)}
</ul>
);
}
// No items on the list, show an empty message.
return <span className="empty-message">No items in list</span>;
}
listings.propTypes = {
items: PropTypes.array,
};
listings.defaultProps = {
items: [],
};
export default listings;
Letâs run the test again:
$ npm test
You will see the failing test results:
Jest attempted to match the displayed component with the updated changes against the existing snapshot but failed since your component has some additions. The modifications made to the snapshot tests are then displayed in a diff.
If the changes are not what you expected, you discovered the issue before the change was implemented, and you may now fix it. Then you need to update your snapshot tests to get them to pass correctly.
Well, you can consider this change as expected for the tutorial. You wanted to give the component class name. Update the snapshot tests after that.
When Jest is in interactive mode, you can press u and choose from the following choices to update the snapshot tests:
Pro Tip: You have to execute jest --updateSnapshot
or jest -u
if you have installed Jest globally.
Your tests will succeed since this will update the snapshots to reflect the updates you made.
The previous snapshot test for no items is shown here:
// ...
exports[`renders correctly when there are no items 1`] = `
<span>
There are no items in list
</span>
`;
// âŠ
Here you can find an updated snapshot test for no items:
// ...
exports[`renders correctly when there are no items 1`] = `
<span
className="empty-message"
>
There are no items in list
</span>
`;
// ...
Once the test is updated, they will pass:
You must now pass tests once more. If this was a work-in-progress, you could release the code with confidence that the changes you intended would be recorded for later development.
React Testing Library is the finest choice as its alternative to Enzyme, as it encourages testing the applicationâs behavior from the userâs perspective instead of testing the internal implementation details.
However, React Testing Library focuses on the result of an action rather than testing the implementation details. This makes the test more resilient and less likely to break when modifications occur.
This results in tests that are easier to read, maintain, and less fragile. But if your project extensively relies on the JSX snapshots, or in other words, if you are too lazy to create explicit assertions for your React components and just use expect(component).toMatchSnapshot()
in all of your tests, React Testing Library can become a problem.
Build React Applications at Scale Using Effective React Patterns and Best Practices
Understand Development with ReactJS
Snapshots are amazing tools for analyzing unintended changes to any interface in your React application, whether it be a UI, an API response, logs, or error messages. There are some best practices you should follow and consider while implementing React snapshot testing effectively.
Whatever kind of practice you follow to create a new code, you must also follow them here, just like you have to commit snapshots and review them. To do this, consider snapshots like any other test or code in your project.
Keep your snapshots focused and concise. Use tools that uphold these stylistic rules to make them understandable.
As we mentioned earlier, Jest uses pretty-format
to make snapshots readable by humans, but you might find it useful to introduce additional tools to encourage committing concise assertions, such as the eslint-plugin-jest
with its no-large-snapshots
option or snapshot-diff
with its component snapshot comparison feature.
The objective is to make it simple to examine snapshots in pull requests and combat the practice of creating new snapshots when test suites fail rather than looking into the causes of those failures.
Your tests should have a deterministic approach. Repeated tests on a component that has not been modified or changed should produce the same results every time. You must ensure that generated snapshots do not include platform-specific or non-deterministic data.
For instance, the snapshot produced by a component that utilizes Date.now()
, such as a Clock, will, alter each time the test case is executed. In this situation, we can simulate the Date.now()
method so that it always returns the same result when the test is run:
Date.now = jest.fn(() => 123456);
Every time you execute Date.now()
, it will show 123456 value consistently. In fact, this result will remain the same regardless of test execution.
Always try to give tests and/or snapshot names that are descriptive. The best names convey the anticipated snapshot content. As a result, it is simpler for reviewers to confirm the snapshots during review and for anyone to determine whether an older snapshot still represents the desired behavior before updating.
Consider comparing:
exports[`<UserName /> should handle some test case`] = `null`;
exports[`<UserName /> should handle some other test case`] = `
<div>
Radixweb
</div>
`;
To:
exports[`<UserName /> should render null`] = `null`;
exports[`<UserName /> should render Radixweb`] = `
<div>
Radixweb
</div>
`;
We can see in the above example whatâs executed in the output. Itâs clear that itâs wrong.
exports[`<UserName /> should render null`] = `
<div>
Radixweb
</div>
`;
exports[`<UserName /> should render Radixweb`] = `null`;
Connect with Radixweb to Understand BetterYou created snapshot tests for a React component in this tutorial. Additionally, you changed the component so that tests would fail. In order to fix the tests, you lastly updated the snapshots.This little simulation was based on a real project. Your development workflow will include this cycle of tests passing, failing, and fixing the issues caused by the failures.However, switching from Enzyme to React Testing Library can greatly improve the testing of your React application. React Testing Library focuses on testing a component's behavior from the viewpoint of the user, making the tests more reliable, readable, and simple to maintain.React Testing Library uses the real DOM and can generate large snapshots; therefore, it's crucial to keep this in mind. As a result, snapshots should be kept minimal and focused.If you find any issues while performing this task or need to implement it for your React applications, you can connect with our experts. We have implemented the Snapshot testing technique in more than 25 React applications for our clients. You can hire certified ReactJS developers to implement this test for your seamless and error-free development process.
Indu Nair works as a professional Bug Hunter at Radixweb. She is an expert in manual testing, agile testing, test case, and bug report writing. With 7 years of experience and a strong command over tools like JMeter, Rest Assured, TestNG, Appium, and Selenium, she guarantees seamless and reliable test automation. Her outstanding skills ensure that software releases are bug-free, efficient, and secure. Indu's comprehensive approach makes her an invaluable member of Radixwebâs QA team.
Ready to brush up on something new? We've got more to read right this way.