如何在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(); });
问题分析与解决方案
你的测试未生效核心原因有两个:
- 测试环境不提供
ClipboardItem和navigator.clipboard.write这类浏览器原生API,直接调用会抛出错误导致测试中断。 - 如果组件内部是通过
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(); });
关键要点
- 必须预先mock
ClipboardItem和navigator.clipboard.write,否则测试环境会因找不到这些API而报错。 - 若组件内部自行管理ref,需通过jest.mock拦截
useRef并返回预设的null ref;若为外部传入,确保组件正确接收并绑定该ref。 - 同时断言
ClipboardItem和navigator.clipboard.write未被调用,能更全面验证handleCopy在ref为null时的退出逻辑。
内容的提问来源于stack exchange,提问作者Takerlink
相关产品推荐
相关产品推荐

