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

如何在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实现:

  1. 安装依赖:
npm install canvas jest-environment-jsdom --save-dev
  1. 修改Jest配置文件(jest.config.js):
module.exports = {
  testEnvironment: 'jsdom',
  setupFilesAfterEnv: ['./jest.setup.js'],
};
  1. 创建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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 19:51:18