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

无需引入额外库 Jest如何Mock canvas的toDataURL方法

Jest环境下仅mock canvas的toDataURL方法实现方案

Jest默认使用的jsdom环境未实现canvas原生API,无需引入全量的jest-canvas-mock,通过以下两种方式即可针对性mocktoDataURL()返回固定值,满足测试需求。


方案1:单测试用例局部mock(推荐,无全局污染)

toDataURL是HTMLCanvasElement原型上的内置方法,通过jest.spyOn监听原型方法即可覆盖所有canvas实例的调用,不会影响其他测试用例。

示例测试代码(基于React Testing Library,其他测试库逻辑一致):

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

test('触发canvas touchend事件后按钮切换为可用状态', () => {
  // mock toDataURL返回固定测试字符串
  const mockToDataURL = jest
    .spyOn(HTMLCanvasElement.prototype, 'toDataURL')
    .mockReturnValue('data:image/png;base64,testMockData');

  // 渲染业务组件,建议给canvas标签加testId方便选中:<canvas data-testid="signature-canvas" />
  const { getByTestId, getByText } = render(<MyView />);
  const canvas = getByTestId('signature-canvas');

  // 触发touchend事件
  fireEvent.touchEnd(canvas);

  // 断言逻辑:onChange触发后data被赋值,按钮解除禁用
  const actionBtn = getByText('Button label');
  expect(actionBtn).not.toBeDisabled();
  expect(mockToDataURL).toHaveBeenCalledTimes(1);

  // 清除mock,恢复原生方法,避免影响其他用例
  mockToDataURL.mockRestore();
});

注意:不要尝试spy单个canvas实例的toDataURL方法,jsdom中元素是动态创建的,只有监听原型方法才能命中所有实例的调用。


方案2:全局统一mock(适合多测试文件复用)

如果项目中多个测试文件都需要用到canvas相关mock,可以在Jest全局配置的setup文件中统一重写原型方法,按需实现你用到的API即可,无需引入全量依赖。

  1. 找到Jest配置中setupFilesAfterEnv字段指向的setup文件(通常是jest.setup.js)
  2. 添加如下mock代码:
// 全局mock toDataURL
HTMLCanvasElement.prototype.toDataURL = jest.fn(
  () => 'data:image/png;base64,globalMockCanvasData'
);

// 按需mock其他你用到的canvas API,用到什么加什么即可
HTMLCanvasElement.prototype.getBoundingClientRect = jest.fn(() => ({
  top: 0,
  left: 0,
  width: 300,
  height: 150,
  right: 300,
  bottom: 150
}));

HTMLCanvasElement.prototype.getContext = jest.fn(() => ({
  fillRect: jest.fn(),
  beginPath: jest.fn(),
  arc: jest.fn(),
  lineTo: jest.fn(),
  stroke: jest.fn(),
  fill: jest.fn()
}));

额外代码修正提示

你提供的组件代码中事件绑定写法有误:onTouchMove和onTouchStart被写在了onTouchEnd的回调函数内部,这两个事件永远不会被正确绑定,测试和实际生产运行都会失效,需要修正为同级属性:

// 错误写法
<canvas
  onTouchEnd={e => {
    onChange(e.target.toDataURL());
    onTouchMove={e => draw(e)} // 写在这里不会生效
    onTouchStart={e => { setTouchPosition(e); }} // 写在这里不会生效
  }}
/>

// 正确写法
<canvas
  data-testid="signature-canvas"
  onTouchStart={e => setTouchPosition(e)}
  onTouchMove={e => draw(e)}
  onTouchEnd={e => onChange(e.target.toDataURL())}
/>

内容的提问来源于stack exchange,提问作者juliano.net

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 17:36:22