无需引入额外库 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即可,无需引入全量依赖。
- 找到Jest配置中
setupFilesAfterEnv字段指向的setup文件(通常是jest.setup.js) - 添加如下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
相关产品推荐
相关产品推荐

