How to Test Forwarding Refs in React

Testing components that use React’s forwardRef API ensures that parent components can successfully access underlying DOM nodes. This article provides a practical, straight-to-the-point guide on how to test forwarded refs using Jest and React Testing Library, demonstrating how to verify that a ref is correctly attached and functional.

The Strategy for Testing Refs

To test a forwarding ref, you need to: 1. Create a ref object inside your test using React.createRef(). 2. Pass that ref to the component being tested. 3. Render the component. 4. Assert that ref.current is not null and points to the correct HTML DOM element.

Step-by-Step Code Example

Suppose you have a custom input component that forwards its ref to the native <input> element:

// CustomInput.jsx
import React from 'react';

const CustomInput = React.forwardRef((props, ref) => {
  return <input ref={ref} type="text" {...props} />;
});

CustomInput.displayName = 'CustomInput';

export default CustomInput;

Here is how you write the test using Jest and React Testing Library:

// CustomInput.test.jsx
import React from 'react';
import { render } from '@testing-library/react';
import CustomInput from './CustomInput';

test('successfully forwards ref to the input element', () => {
  // 1. Create a ref
  const ref = React.createRef();

  // 2. Render the component with the ref
  render(<CustomInput ref={ref} placeholder="Enter text" />);

  // 3. Assert the ref is attached to the correct DOM node
  expect(ref.current).not.toBeNull();
  expect(ref.current.tagName).toBe('INPUT');
  expect(ref.current.placeholder).toBe('Enter text');
});

Testing Ref Functionality

In addition to verifying that the ref points to the correct DOM node, you should test that the ref functions as expected, such as triggering focus.

test('allows focusing the element via the forwarded ref', () => {
  const ref = React.createRef();
  render(<CustomInput ref={ref} />);

  // Trigger focus programmatically via the ref
  ref.current.focus();

  // Assert that the element is currently focused in the document
  expect(document.activeElement).toBe(ref.current);
});