You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Testing Library中测试useRef.current为null的场景?

如何测试useRef.current为null时的handleCopy逻辑

我正在做测试,这是实现100%测试覆盖率的最后一项,但试了多种方法都没解决。想知道怎么设置测试来验证useRef.current为null的情况。

组件代码

const handleCopy = (): void => {
  if (matrixTableRef.current === null) return

  const clipboardItem = new ClipboardItem({
        'text/html': new Blob([matrixTableRef.current.outerHTML], {
      type: 'text/html',
        }),
      })
  navigator.clipboard.write([clipboardItem])

  triggerCopyPopover()
}

我尝试的测试代码

test('handleCopy does nothing when matrixTableRef.current is null', () => {

  // Render component with a mock ref
  const mockRef = { current: null };
  render(<Matrix matrixTableRef={mockRef} />);

  // Access the element that triggers handleCopy
  const copyButton = screen.getByTestId('copy-table');

  // Fire the event that triggers handleCopy
  fireEvent.click(copyButton);

  // Assert that navigator.clipboard.write was not called
  expect(navigator.clipboard.write).not.toHaveBeenCalled();


});

问题分析与解决方案

你的测试未生效核心原因有两个:

  1. 测试环境不提供ClipboardItem和navigator.clipboard.write这类浏览器原生API,直接调用会抛出错误导致测试中断。
  2. 如果组件内部是通过useRef自行创建的matrixTableRef,而非接收外部props传入的ref,那么你传入的mockRef不会被组件使用。

针对不同场景,给出两种解决方案:

场景1:组件内部自行创建useRef

若组件代码如下:

import { useRef } from 'react';

const Matrix = () => {
  const matrixTableRef = useRef<HTMLTableElement>(null);
  
  const handleCopy = () => {
    // ... 你的handleCopy逻辑
  };

  return (
    <>
      <table ref={matrixTableRef}></table>
      <button data-testid="copy-table" onClick={handleCopy}>复制</button>
    </>
  );
};

修改后的测试代码:

import { useRef } from 'react';
import { render, fireEvent, screen } from '@testing-library/react';
import Matrix from './Matrix';

// Mock React.useRef
jest.mock('react', () => ({
  ...jest.requireActual('react'),
  useRef: jest.fn(),
}));

test('handleCopy 不执行任何操作当 matrixTableRef.current 为 null', () => {
  // 让useRef返回current为null的对象
  (useRef as jest.Mock).mockReturnValue({ current: null });

  // Mock浏览器剪贴板相关API
  const mockClipboardWrite = jest.fn();
  global.navigator.clipboard = { write: mockClipboardWrite };
  global.ClipboardItem = jest.fn();

  render(<Matrix />);

  const copyButton = screen.getByTestId('copy-table');
  fireEvent.click(copyButton);

  // 断言剪贴板方法未被调用
  expect(mockClipboardWrite).not.toHaveBeenCalled();
  // 断言ClipboardItem未被实例化
  expect(global.ClipboardItem).not.toHaveBeenCalled();
});

场景2:组件接收外部传入的ref

若组件通过props接收matrixTableRef:

const Matrix = ({ matrixTableRef }) => {
  const handleCopy = () => {
    // ... 你的handleCopy逻辑
  };

  return (
    <>
      <table ref={matrixTableRef}></table>
      <button data-testid="copy-table" onClick={handleCopy}>复制</button>
    </>
  );
};

修改后的测试代码:

import { render, fireEvent, screen } from '@testing-library/react';
import Matrix from './Matrix';

test('handleCopy 不执行任何操作当 matrixTableRef.current 为 null', () => {
  // Mock浏览器剪贴板相关API
  const mockClipboardWrite = jest.fn();
  global.navigator.clipboard = { write: mockClipboardWrite };
  global.ClipboardItem = jest.fn();

  const mockRef = { current: null };
  render(<Matrix matrixTableRef={mockRef} />);

  const copyButton = screen.getByTestId('copy-table');
  fireEvent.click(copyButton);

  expect(mockClipboardWrite).not.toHaveBeenCalled();
  expect(global.ClipboardItem).not.toHaveBeenCalled();
});

关键要点

  • 必须预先mockClipboardItem和navigator.clipboard.write,否则测试环境会因找不到这些API而报错。
  • 若组件内部自行管理ref,需通过jest.mock拦截useRef并返回预设的null ref;若为外部传入,确保组件正确接收并绑定该ref。
  • 同时断言ClipboardItem和navigator.clipboard.write未被调用,能更全面验证handleCopy在ref为null时的退出逻辑。

内容的提问来源于stack exchange,提问作者Takerlink

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 11:43:21