How to Mock Forwarding Refs in React
This article explains how to successfully mock components that use
React’s forwardRef API during unit testing. You will learn
how to mock these components using Jest and React Testing Library to
prevent test failures and ensure your component interactions are
verified correctly.
The Problem with Mocking forwardRef
When you mock a standard React component in Jest using
jest.mock(), Jest replaces the component with a simple
dummy function. However, if the component being mocked uses
React.forwardRef, the parent component passing the ref
expects a valid React ref object or callback. If Jest replaces it with a
standard mock function, React will throw an error or the ref will
resolve to undefined, breaking any DOM interactions or
method calls (such as .focus()).
Solution 1: Mocking the Component with forwardRef
To mock a child component that uses forwardRef, you must
explicitly return a component wrapped in React.forwardRef
inside your jest.mock implementation.
Here is how to do it:
import React from 'react';
import { render, screen } from '@testing-library/react';
import ParentComponent from './ParentComponent';
// Mock the child component that uses forwardRef
jest.mock('./ChildComponent', () => {
const React = require('react');
// Return a mocked component wrapped in forwardRef
return React.forwardRef((props, ref) => (
<div ref={ref} data-testid="mocked-child">
{props.children}
</div>
));
});
describe('ParentComponent', () => {
it('renders the mocked child with the ref attached', () => {
render(<ParentComponent />);
const childElement = screen.getByTestId('mocked-child');
expect(childElement).toBeInTheDocument();
});
});By requiring react inside the factory function and
returning React.forwardRef, you ensure that the React
reconciler correctly attaches the ref to the mocked DOM element.
Solution 2: Mocking useImperativeHandle Custom Methods
Often, components that use forwardRef also use
useImperativeHandle to expose custom imperative methods
(like a custom .focus() or .clear() method) to
the parent.
If the parent component calls one of these custom methods on the ref,
your mock must implement useImperativeHandle to prevent “is
not a function” errors:
jest.mock('./CustomInputComponent', () => {
const React = require('react');
return React.forwardRef((props, ref) => {
// Implement useImperativeHandle to mock the exposed custom methods
React.useImperativeHandle(ref, () => ({
focus: jest.fn(),
customClear: jest.fn(),
}));
return <input data-testid="mocked-input" />;
});
});This setup ensures that when the parent component executes
ref.current.focus(), Jest executes the mock function
instead of throwing a runtime error.
Solution 3: Passing a Mocked Ref in Tests
If you are testing the component that uses forwardRef
directly and want to verify that it correctly assigns the ref to its
inner DOM element, you can pass a created ref directly in your test:
import React from 'react';
import { render } from '@testing-library/react';
import MyForwardRefComponent from './MyForwardRefComponent';
it('correctly forwards the ref to the input element', () => {
const ref = React.createRef();
render(<MyForwardRefComponent ref={ref} />);
// Verify the ref points to the actual DOM node
expect(ref.current).toBeInstanceOf(HTMLInputElement);
});