When it comes to testing React components, it's critical to select the approach that best fits your needs. Shallow rendering and full rendering are two popular approaches for testing React components. In this Answer, we will look at the distinctions between these two methods.
Shallow rendering is a testing technique that renders only the currently tested component, excluding its descendant components. This method allows you to isolate the component being tested and concentrate entirely on its behavior and output. Since it avoids rendering the full component tree, shallow rendering is a lightweight and efficient way to execute component testing.
We will create a sample project to demonstrate the process step by step.
After creating a new React project using Create React App, install the necessary dependencies. For this example project, you will need the following dependencies.
npm install react-test-renderer/shallow
import React from 'react';import Subcomponent from './Subcomponent';function MyComponent() {return (<div><span className="heading">Title</span><Subcomponent foo="bar" /></div>);}export default MyComponent;
import React from 'react';function Subcomponent({ foo }) {return <div>{foo}</div>;}export default Subcomponent;
import React from 'react';import ShallowRenderer from 'react-test-renderer/shallow';import MyComponent from './App.js';import Subcomponent from './Subcomponent';it('renders MyComponent correctly', () => {const renderer = new ShallowRenderer();renderer.render(<MyComponent />);const result = renderer.getRenderOutput();expect(result.type).toBe('div');expect(result.props.children).toEqual([<span className="heading">Title</span>,<Subcomponent foo="bar" />]);});
Line 6: We define a test case using the it
function provided by the testing framework (e.g., Jest). The test case verifies that the MyComponent
renders correctly.
Line 7: We create a new instance of ShallowRenderer
using new ShallowRenderer()
.
Line 8: We call the render
method on the ShallowRenderer
instance, passing in the MyComponent
component as the argument. This performs the shallow rendering of the component.
Line 9: We retrieve the rendered output using the getRenderOutput
method of the ShallowRenderer
instance and assign it to the result
variable.
Lines 11–15: We use assertions (provided by the testing framework) to check if the rendered output matches our expectations. We verify that the result
is of type <div>
and that its children
prop is an array with a <span>
element, with the class name "heading" and a Subcomponent
component with the prop foo
set to "bar".
Run the tests using the following command.
npm test
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>
Here are a few of the advantages of shallow rendering.
Faster execution: Shallow rendering focuses on the component being tested, resulting in faster test execution than full rendering.
Isolation: Shallow rendering allows you to isolate the component under test, making it easier to debug.
Simplicity: Shallow rendering provides a simpler API for testing components because it avoids the complexity of rendering the complete component tree.
Full rendering, also referred to as deep rendering, involves rendering the full component tree, including all child components and their descendants. This method provides a more comprehensive testing environment because it simulates the component's actual behavior in a real-world application.
Let's create another sample project to explain shallow rendering in React.
After creating the project, install the following dependencies.
npm install --save-dev @testing-library/react react-test-renderer
import React from 'react';function Button({ onClick, children }) {return <button onClick={onClick}>{children}</button>;}export default Button;
Lines 3–5: We create a functional React component called Button
that takes two props: onClick
(a function to be called when the button is clicked) and children
(the content inside the button). It returns a button element with the specified onClick
handler and the provided children
as its content.
import React from 'react';import { render } from '@testing-library/react';import Button from './App';it('renders a button with correct text', () => {const { getByText } = render(<Button onClick={() => {}}>Click me</Button>);expect(getByText('Click me')).toBeInTheDocument();});
Lines 5–8: Defines a test case with the description "renders a button with the correct text". The it
function is provided by the testing framework and is used to define individual test cases.
Line 6: const { getByText } = render(<Button onClick={() => {}}>Click me</Button>);
uses the render
function to render the Button
component with the specified props. The onClick
prop is set to an empty arrow function, and the text "Click me" is passed as the content of the button. The render
function returns an object with various querying methods, such as getByText
, which we destructure from the returned object.
Line 7: expect(getByText('Click me')).toBeInTheDocument();
uses the expect
function to assert that the text "Click me" is present in the rendered component. The getByText
function is used to find the element containing the specified text. The toBeInTheDocument
matcher checks if the element is present in the document. The test will be passed if it is present, otherwise fail.
Run the tests using the following command.
npm test
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <link rel="icon" href="%PUBLIC_URL%/favicon.ico" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <meta name="theme-color" content="#000000" /> <meta name="description" content="Web site created using create-react-app" /> <link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" /> <!-- manifest.json provides metadata used when your web app is installed on a user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/ --> <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> <!-- Notice the use of %PUBLIC_URL% in the tags above. It will be replaced with the URL of the `public` folder during the build. Only files inside the `public` folder can be referenced from the HTML. Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will work correctly both with client-side routing and a non-root public URL. Learn how to configure a non-root public URL by running `npm run build`. --> <title>React App</title> </head> <body> <noscript>You need to enable JavaScript to run this app.</noscript> <div id="root"></div> <!-- This HTML file is a template. If you open it directly in the browser, you will see an empty page. You can add webfonts, meta tags, or analytics to this file. The build step will place the bundled scripts into the <body> tag. To begin the development, run `npm start` or `yarn start`. To create a production bundle, use `npm run build` or `yarn build`. --> </body> </html>
Here are a few of the advantages of full rendering.
Realistic testing environment: Full rendering allows you to test the component in a more realistic context because it depicts the complete component tree and captures interactions with child components.
Integration testing: Full rendering is well-suited for integration testing, where you need to verify the interactions between different components.
Accessibility testing: Full rendering provides a comprehensive environment for testing accessibility features, allowing you to check the component's functionality under different user scenarios.
Now, let us see the main differences between the shallow rendering and full rendering.
Aspect | Shallow Rendering | Full Rendering |
Rendered Components | Only the current component being tested | Entire component tree and child components |
Test Focus | Isolates the component under test, focusing on its behavior and output | Simulates the actual behavior of the component in a real application |
Test Efficiency | Faster execution due to rendering only the current component | Slower execution as it renders the entire component tree |
Component Interaction | Child components are not rendered, their behavior is not captured | Captures interactions with child components |
Test Complexity | Simpler API, less complexity | More complex, requires rendering and interacting with the whole tree |
Use Cases | Unit testing individual components | Integration testing, testing component interactions |
Debugging | Easier to debug, isolated environment | Realistic context for debugging |
Accessibility Testing | Limited in testing accessibility features | Provides a comprehensive environment for testing accessibility |
Shallow rendering and full rendering are two distinct approaches to testing React components, each with its own advantages. Full rendering provides a more thorough testing environment that includes the entire component tree, whereas shallow rendering improves speed and simplicity by focusing on the component under test. The right technique is determined by the specific requirements of your testing scenario.
Free Resources