How to Mock useDebugValue Hook in React

Testing custom React hooks often requires mocking React’s built-in hooks to verify their behavior or prevent external side effects during unit tests. This article provides a clear, step-by-step guide on how to mock and assert the useDebugValue hook using popular testing libraries like Jest and Vitest.

Why Mock useDebugValue?

The useDebugValue hook is used to display a label for custom hooks in React DevTools. While it does not affect the runtime logic of your application, you may want to mock and spy on it during testing to ensure that: * The hook displays the correct debug information. * The formatting function passed to it executes correctly. * Unnecessary overhead is avoided in test environments.

How to Mock useDebugValue with Jest

To mock or spy on useDebugValue in Jest, you need to spy on the React object directly before rendering your hook in the test.

Here is an example of a custom hook that uses useDebugValue:

// useFriendStatus.js
import { useState, useDebugValue } from 'react';

export function useFriendStatus(initialStatus) {
  const [isOnline] = useState(initialStatus);
  
  useDebugValue(isOnline ? 'Online' : 'Offline');

  return isOnline;
}

Below is the test file showing how to mock and assert useDebugValue using Jest and React Testing Library:

// useFriendStatus.test.js
import React from 'react';
import { renderHook } from '@testing-library/react';
import { useFriendStatus } from './useFriendStatus';

describe('useFriendStatus', () => {
  let useDebugValueSpy;

  beforeEach(() => {
    // Spy on the useDebugValue hook from the React module
    useDebugValueSpy = jest.spyOn(React, 'useDebugValue');
  });

  afterEach(() => {
    // Restore the original implementation after each test
    useDebugValueSpy.mockRestore();
  });

  it('should call useDebugValue with the correct status label', () => {
    renderHook(() => useFriendStatus(true));

    // Verify that the hook was called with the expected value
    expect(useDebugValueSpy).toHaveBeenCalledWith('Online');
  });
});

How to Mock useDebugValue with Vitest

If you are using Vitest instead of Jest, the syntax is almost identical. You simply use vi.spyOn instead of jest.spyOn.

// useFriendStatus.test.js (Vitest)
import React from 'react';
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { renderHook } from '@testing-library/react';
import { useFriendStatus } from './useFriendStatus';

describe('useFriendStatus', () => {
  let useDebugValueSpy;

  beforeEach(() => {
    useDebugValueSpy = vi.spyOn(React, 'useDebugValue');
  });

  afterEach(() => {
    useDebugValueSpy.mockRestore();
  });

  it('should call useDebugValue with the correct status label', () => {
    renderHook(() => useFriendStatus(false));

    expect(useDebugValueSpy).toHaveBeenCalledWith('Offline');
  });
});

Mocking useDebugValue Globally

If you want to disable useDebugValue entirely across your test suite to avoid overhead, you can mock it globally in your test setup file:

import React from 'react';

jest.spyOn(React, 'useDebugValue').mockImplementation(() => {});