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

Jest测试中如何验证execCommand('copy')执行后的剪贴板实际内容

Jest 下验证 execCommand 复制内容的实现方案

你之前只对document.execCommand做返回值和参数的mock,确实无法校验实际复制的内容——Jest 跑测试用的jsdom环境本身没有实现真实的系统剪贴板交互,只要补全mock层的内容捕获逻辑,不需要访问真实剪贴板就能完成校验,具体实现如下:


核心实现思路

document.execCommand('copy')触发时,实际写入剪贴板的内容只有两个来源:

  1. 当前页面上被选中的普通文本/表单控件选中文本
  2. 业务代码在copy事件回调里通过e.clipboardData.setData()手动写入的内容
    你只需要在mock层拦截这两部分内容,就能准确拿到复制操作的实际写入值。

具体代码实现

1. 测试前置Mock配置

beforeEach(() => {
  let capturedCopyText = '';

  // 绑定copy事件捕获逻辑
  const copyHandler = (e) => {
    e.preventDefault();
    const activeEl = document.activeElement;
    // 兼容input/textarea内选中文本的场景
    if (activeEl instanceof HTMLInputElement || activeEl instanceof HTMLTextAreaElement) {
      capturedCopyText = activeEl.value.slice(activeEl.selectionStart, activeEl.selectionEnd);
    } 
    // 兼容普通DOM节点选中文本的场景
    else if (document.getSelection()) {
      capturedCopyText = document.getSelection().toString();
    }
    // 兼容手动通过clipboardData写入内容的场景
    if (e.clipboardData?.dataStore?.['text/plain']) {
      capturedCopyText = e.clipboardData.getData('text/plain');
    }
  };
  document.addEventListener('copy', copyHandler);

  // 重写execCommand的mock实现
  jest.spyOn(document, 'execCommand').mockImplementation((command) => {
    if (command === 'copy') {
      // 构造符合规范的copy事件,挂载clipboardData对象
      const copyEvent = new Event('copy', { bubbles: true, cancelable: true });
      Object.defineProperty(copyEvent, 'clipboardData', {
        value: {
          dataStore: {},
          setData(type, value) {
            this.dataStore[type] = value;
          },
          getData(type) {
            return this.dataStore[type] || '';
          }
        }
      });
      document.dispatchEvent(copyEvent);
      // 把捕获到的文本挂在mock实例上,方便断言读取
      document.execCommand.copiedText = capturedCopyText;
      return true;
    }
    return false;
  });

  // 测试后清理环境
  afterEach(() => {
    document.removeEventListener('copy', copyHandler);
    jest.restoreAllMocks();
  });
});

2. 测试用例断言示例

import { render, fireEvent, screen } from '@testing-library/react';
import CopyButton from './CopyButton'; // 你的业务组件

test('点击复制按钮时,正确写入指定内容到剪贴板', () => {
  const testCopyText = '测试要复制的内容_123456';
  render(<CopyButton text={testCopyText} />);
  
  // 触发复制操作
  fireEvent.click(screen.getByText('复制'));

  // 原有参数校验保留
  expect(document.execCommand).toHaveBeenCalledWith('copy');
  // 直接断言捕获到的复制内容
  expect(document.execCommand.copiedText).toBe(testCopyText);
});

注意事项

  • 不要尝试在单元测试里读取系统真实剪贴板,jsdom环境没有对应权限,也会导致测试在CI/无GUI环境跑失败
  • 如果你的业务逻辑用了第三方封装的copy库(比如copy-to-clipboard),这套mock逻辑同样适用,因为这类库底层还是走的execCommand + 选中文本/clipboardData的逻辑
  • 如果用例之间存在DOM污染,可以在jest配置里打开testEnvironmentOptions: { url: 'http://localhost' },同时每个用例后重置document.body内容,避免选中文本串用例

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 07:12:24