如何用Jest和Testing Library测试ChakraUI useClipboard的剪贴板内容?
测试剪贴板复制功能的优雅方案
你遇到的TypeError: Cannot read properties of undefined (reading 'readText'),本质是Jest的Node.js测试环境没有原生浏览器的剪贴板API支持,导致无法正常读写剪贴板内容。下面给你两个不用mock业务逻辑的优雅解决思路:
方案1:补全测试环境的剪贴板API
这不是mock业务代码,而是给测试环境补上缺失的浏览器API,属于环境适配,完全符合你的要求:
在测试文件的最顶部添加这段代码,给navigator对象挂载模拟的剪贴板实现:
Object.defineProperty(navigator, 'clipboard', { value: { readText: jest.fn().mockResolvedValue(''), writeText: jest.fn().mockResolvedValue() }, writable: true });
之后在测试用例里,你可以直接断言剪贴板的writeText方法是否被传入正确的参数调用,也可以手动设置readText的返回值来验证读取逻辑:
test('点击复制按钮能正确复制指定内容', async () => { const testContent = '要复制的测试文本'; render(<CopyButton text={testContent} />); // 触发复制按钮点击 fireEvent.click(screen.getByRole('button', { name: /复制/i })); // 断言剪贴板写入方法被正确调用 expect(navigator.clipboard.writeText).toHaveBeenCalledWith(testContent); // 如果需要验证读取逻辑,手动设置返回值并断言 navigator.clipboard.readText.mockResolvedValue(testContent); expect(await navigator.clipboard.readText()).toBe(testContent); });
方案2:结合组件状态验证
如果你的组件用useClipboard后有状态更新(比如复制成功后的提示),可以同时验证状态和剪贴板调用:
假设你的组件实现是这样的:
const CopyButton = ({ text }) => { const { copy, success } = useClipboard(text); return ( <button onClick={copy}> {success ? '已复制' : '复制'} </button> ); };
测试用例可以这么写:
test('点击复制后状态更新且内容正确', async () => { const testContent = '要复制的测试文本'; // 先补全剪贴板API Object.defineProperty(navigator, 'clipboard', { value: { writeText: jest.fn().mockResolvedValue() }, writable: true }); render(<CopyButton text={testContent} />); const copyBtn = screen.getByRole('button', { name: /复制/i }); fireEvent.click(copyBtn); // 验证组件状态更新(复制成功提示) expect(copyBtn).toHaveTextContent('已复制'); // 验证剪贴板写入的内容正确 expect(navigator.clipboard.writeText).toHaveBeenCalledWith(testContent); });
为什么这两种方案不算“不优雅的mock”
这里的剪贴板API模拟是为了让测试环境贴近真实浏览器的行为,而非篡改业务代码的逻辑。和直接mockcopy-to-clipboard包的函数不同,这种方式更接近真实用户的操作场景,测试结果也更可靠。
内容的提问来源于stack exchange,提问作者Bassem
相关产品推荐
相关产品推荐

