如何在Jest/Node/JSDOM环境下获取Canvas中的图像?
对Canvas绘图代码进行Jest单元测试的解决方案
问题背景
需要对Canvas绘图的复杂代码做单元测试,之前用WPF时可以调用绘图代码转成位图,断言像素属性,但在Jest里不知道怎么获取Canvas里的图像。
踩过的坑
- 用
jest-canvas-mock尝试获取图像,但JSDOM的Blob没有实现arrayBuffer()方法,toBlob()的结果没法处理 - 试了
node-fetch,版本3+的ESM语法导致Jest报错;换成2.7.0后,fetch(c.toDataURL())又因为data协议不被支持报错 - 网传的
blob._buffer属性根本不存在 - 发现
jest-canvas-mock只是模拟API,没有实际渲染像素,换成node canvas库后,还是没法用fetch处理data URL
可行解决方案
方案1:用node-canvas直接获取像素数据(最适合单元测试)
放弃JSDOM的canvas,直接用node-canvas创建实例,用原生的getImageData()拿到像素数组,直接断言目标像素的RGB值:
import { createCanvas } from 'canvas'; describe('Canvas绘图验证', () => { it('检查绘制线条的像素值', () => { const canvas = createCanvas(10, 10); const ctx = canvas.getContext('2d'); // 执行你的绘图逻辑 ctx.strokeStyle = 'rgb(127, 0, 127)'; ctx.moveTo(0, 0); ctx.lineTo(10, 5); ctx.stroke(); // 获取像素数据:一维数组,每个像素占4位[r, g, b, a] const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const pixels = imageData.data; // 断言(0,0)位置的像素值 expect(pixels[0]).toBe(127); // 红色通道 expect(pixels[1]).toBe(0); // 绿色通道 expect(pixels[2]).toBe(127); // 蓝色通道 expect(pixels[3]).toBe(255); // 透明度(不透明) }); });
方案2:直接导出图像Buffer保存验证
如果需要把图像存下来直观验证,用node-canvas的toBuffer()方法直接生成Buffer,不需要绕Blob或fetch:
import { createCanvas } from 'canvas'; import * as fs from 'fs'; import { promisify } from 'util'; const writeFile = promisify(fs.writeFile); describe('Canvas绘图导出', () => { it('保存绘制的图像文件', async () => { const canvas = createCanvas(10, 10); const ctx = canvas.getContext('2d'); // 执行绘图逻辑 ctx.strokeStyle = 'rgb(127, 0, 127)'; ctx.moveTo(0, 0); ctx.lineTo(10, 5); ctx.stroke(); // 生成PNG Buffer并保存 const buffer = canvas.toBuffer('image/png'); await writeFile('test-output.png', buffer); // 可选:验证Buffer非空 expect(buffer.length).toBeGreaterThan(0); }); });
方案3:在JSDOM环境中替换为node-canvas
如果项目必须用JSDOM环境,可配置Jest用node-canvas替换JSDOM的canvas实现:
- 安装依赖:
npm install canvas jest-environment-jsdom --save-dev
- 修改Jest配置文件(
jest.config.js):
module.exports = { testEnvironment: 'jsdom', setupFilesAfterEnv: ['./jest.setup.js'], };
- 创建
jest.setup.js替换canvas:
import { createCanvas, createImage } from 'canvas'; // 替换document.createElement('canvas')的实现 global.document.createElement = (tagName) => { if (tagName.toLowerCase() === 'canvas') { return createCanvas(); } return document.createElement(tagName); }; // 可选:替换全局Image对象 global.Image = createImage;
之后就可以在测试里像用浏览器canvas一样调用getImageData()或toBuffer()。
关键提示
jest-canvas-mock仅适合测试API调用逻辑,没有实际像素渲染能力,没法验证绘图结果node-canvas是Node环境中真正渲染像素的库,能准确获取绘图后的像素数据,完全满足单元测试的断言需求- 不需要通过Blob、fetch这类浏览器API绕弯,直接用
node-canvas提供的方法就能搞定
内容的提问来源于stack exchange,提问作者Pete
相关产品推荐
相关产品推荐

