How to Test useDebugValue Hook in React
Testing the useDebugValue hook in React ensures that
your custom hooks provide the correct debugging labels within the React
Developer Tools. This article explains how the
useDebugValue hook works and provides a step-by-step guide
on how to write unit tests to verify its behavior using Jest and React
Testing Library.
Understanding useDebugValue
The useDebugValue hook is used to display a label for
custom hooks in React DevTools. It does not affect the runtime behavior
of your application or return any value. Because its only side effect is
UI-related within the DevTools extension, you cannot test it by
asserting against the rendered DOM. Instead, you must test it by spying
on the hook’s execution.
Here is a simple custom hook that uses
useDebugValue:
import { useState, useDebugValue } from 'react';
export function useFriendStatus(friendId) {
const [isOnline, setIsOnline] = useState(null);
// Show a label in DevTools next to this hook
useDebugValue(isOnline ? 'Online' : 'Offline');
return isOnline;
}How to Test useDebugValue with Jest
To test that useDebugValue is called with the correct
arguments, you need to spy on React.useDebugValue before
rendering your custom hook using
@testing-library/react.
Below is the complete testing setup:
1. The Test Code
import React from 'react';
import { renderHook, act } from '@testing-library/react';
import { useFriendStatus } from './useFriendStatus';
describe('useFriendStatus Debug Value', () => {
let useDebugValueSpy;
beforeEach(() => {
// Spy on React.useDebugValue
useDebugValueSpy = jest.spyOn(React, 'useDebugValue');
});
afterEach(() => {
// Clear the spy to avoid polluting other tests
useDebugValueSpy.mockRestore();
});
it('should call useDebugValue with the correct status', () => {
// Render the hook
const { result } = renderHook(() => useFriendStatus(1));
// Initially, isOnline is null, which evaluates to 'Offline'
expect(useDebugValueSpy).toHaveBeenCalledWith('Offline');
});
});2. Testing with Formatting Functions
Often, formatting a debug value can be an expensive operation. To
optimize performance, useDebugValue accepts an optional
formatting function as a second argument. This function only runs if the
DevTools are actually open.
Here is how you define a hook with a formatting function:
import { useState, useDebugValue } from 'react';
export function useDateHook() {
const [date] = useState(new Date());
// The formatting function only runs when inspected
useDebugValue(date, d => d.toDateString());
return date;
}To test this scenario, you need to assert that
useDebugValue was called with both the state and the
formatting function, and then verify the formatting function logic
independently:
import React from 'react';
import { renderHook } from '@testing-library/react';
import { useDateHook } from './useDateHook';
describe('useDateHook Debug Value', () => {
it('should pass the date and formatting function to useDebugValue', () => {
const useDebugValueSpy = jest.spyOn(React, 'useDebugValue');
renderHook(() => useDateHook());
// Verify useDebugValue was called with a Date object and a function
expect(useDebugValueSpy).toHaveBeenCalledWith(
expect.any(Date),
expect.any(Function)
);
// Retrieve the formatting function passed to the hook
const formatter = useDebugValueSpy.mock.calls[0][1];
const testDate = new Date('2026-03-29');
// Test the formatter function output directly
expect(formatter(testDate)).toBe('Sun Mar 29 2026');
useDebugValueSpy.mockRestore();
});
});