Jsdom: 模拟画布

创建于 2017-03-22  ·  25评论  ·  资料来源: jsdom/jsdom

是否可以在没有实际实现的情况下模拟画布( canvas / canvas-prebuilt )?

我想防止发生此错误,因为画布功能对我来说并不重要:

Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)

最有用的评论

这是我想出的一种模拟画布的简单方法:

//
// Mock Canvas / Context2D calls
//
function mockCanvas (window) {
    window.HTMLCanvasElement.prototype.getContext = function () {
        return {
            fillRect: function() {},
            clearRect: function(){},
            getImageData: function(x, y, w, h) {
                return  {
                    data: new Array(w*h*4)
                };
            },
            putImageData: function() {},
            createImageData: function(){ return []},
            setTransform: function(){},
            drawImage: function(){},
            save: function(){},
            fillText: function(){},
            restore: function(){},
            beginPath: function(){},
            moveTo: function(){},
            lineTo: function(){},
            closePath: function(){},
            stroke: function(){},
            translate: function(){},
            scale: function(){},
            rotate: function(){},
            arc: function(){},
            fill: function(){},
            measureText: function(){
                return { width: 0 };
            },
            transform: function(){},
            rect: function(){},
            clip: function(){},
        };
    }

    window.HTMLCanvasElement.prototype.toDataURL = function () {
        return "";
    }
}
const document = jsdom.jsdom(undefined, {
  virtualConsole: jsdom.createVirtualConsole().sendTo(console)
});

const window = document.defaultView;
mockCanvas(window);

所有25条评论

如果有人需要这个,这是我解决它的方法:

const utils = require("jsdom/lib/jsdom/utils");
const canvasMock = require("canvas-mock");

function Canvas () {
    canvasMock(this);
    this.toDataURL = function() { return ""; }
}
utils.Canvas = Canvas;

请不要那样做。 它将在未来的补丁版本中中断。 相反,覆盖 getContext() 方法,即 window.HTMLCanvasElement.prototype.getContext = ...

谢谢@domenic

@domenic我无法

import { jsdom } from 'jsdom';
import mockLocalStorage from './mockLocalStorage';
import jQuery from 'jquery';
import Backbone from 'backbone';
import moment from 'moment';

const dom = jsdom('<!doctype html><html><body></body></html>');
const { window } = dom.defaultView;

function copyProps(src, target) {
    const props = Object.getOwnPropertyNames(src)
        .filter(prop => typeof target[prop] === 'undefined')
        .map(prop => Object.getOwnPropertyDescriptor(src, prop));
    Object.defineProperties(target, props);
}

//Mock canvas (used by qtip)
window.HTMLCanvasElement.prototype.getContext = () => {
    return {};
};

global.window = window;
global.document = window.document;
global.navigator = {
    userAgent: 'node.js',
};
global.localStorage = mockLocalStorage;
global.jQuery = jQuery;
global.$ = jQuery;
global.fetch = () => Promise.resolve();
Backbone.$ = jQuery;
copyProps(window, global);

//Mock Mousetrap (only works in browser)
jest.mock('mousetrap', () => { return { bind: () => {}}});

//Set moment locale for all tests
moment.locale('sv');

很抱歉在节点中污染了全局,但这是一个非常古老且庞大的代码库,我尝试将其迁移到 Jest。
玩笑版本:21.2.1
Jsdom 版本:9.12.0

如果官方文档涵盖了模拟画布(不使用画布包,因为 Windows 不支持),而不仅仅是作为问题中的评论,那将会非常好。

不使用画布包,因为 Windows 不支持

为什么canvas-prebuilt不适合您? 这就是我们在项目中使用的没有任何问题的内容(Win、Mac 和 Linux,尽管一切都必须是 x64)。

一般来说,我们不打算添加文档或帮助解决一次性模拟问题。 我们已经在https://github.com/tmpvar/jsdom#intervening -before-parsing 中介绍了这一点,任何特定问题都将与您的特定代码库相关。

这是我想出的一种模拟画布的简单方法:

//
// Mock Canvas / Context2D calls
//
function mockCanvas (window) {
    window.HTMLCanvasElement.prototype.getContext = function () {
        return {
            fillRect: function() {},
            clearRect: function(){},
            getImageData: function(x, y, w, h) {
                return  {
                    data: new Array(w*h*4)
                };
            },
            putImageData: function() {},
            createImageData: function(){ return []},
            setTransform: function(){},
            drawImage: function(){},
            save: function(){},
            fillText: function(){},
            restore: function(){},
            beginPath: function(){},
            moveTo: function(){},
            lineTo: function(){},
            closePath: function(){},
            stroke: function(){},
            translate: function(){},
            scale: function(){},
            rotate: function(){},
            arc: function(){},
            fill: function(){},
            measureText: function(){
                return { width: 0 };
            },
            transform: function(){},
            rect: function(){},
            clip: function(){},
        };
    }

    window.HTMLCanvasElement.prototype.toDataURL = function () {
        return "";
    }
}
const document = jsdom.jsdom(undefined, {
  virtualConsole: jsdom.createVirtualConsole().sendTo(console)
});

const window = document.defaultView;
mockCanvas(window);

非常感谢! 画布预构建包似乎正在工作。

你好@cattermo
我已经将 canvas-prebuilt 添加到我的 deps 中,我需要更改我的 jest 配置吗? 我不能让它工作它给了我
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)

@micabe
我没有进行任何配置更改。 如果它存在于 node_modules 中,则 Jsdom 将拾取预构建的画布。

也许不支持该特定功能?

yarn cache clean之后它现在可以工作了,抱歉打扰您! 谢谢@cattermo

也许jest-canvas-mock可以提供帮助。

解决方案很简单,只需安装canvas作为 devDependency 并重新运行您的笑话测试。

参考: https :

由于 jsdom 在 lib/jsdom/utils.js 中检查画布模块的方式,这仍然不起作用:

  exports.Canvas = require(moduleName);
  if (typeof exports.Canvas !== "function") {
    // In browserify, the require will succeed but return an empty object
    exports.Canvas = null;
  }

执行 require('canvas') 返回一个具有 Canvas 功能的对象。 它不会立即返回 Canvas 函数。 还是我在这个问题上错了? 当我使用 canvas-prebuilt 模块时它运行良好,但似乎 canvas 模块具有不同的 API。 我正在使用画布的最新版本 2.0.1。
编辑
我测试了以前的主要版本 (1.6.x) 并且它工作正常,这是 JSDOM 未处理的 API 更改。

你可以这样做:

HTMLCanvasElement.prototype.getContext = jest.fn()

如果实际实施对您来说并不重要

由于 jsdom 在 lib/jsdom/utils.js 中检查画布模块的方式,这仍然不起作用:

  exports.Canvas = require(moduleName);
  if (typeof exports.Canvas !== "function") {
    // In browserify, the require will succeed but return an empty object
    exports.Canvas = null;
  }

执行 require('canvas') 返回一个具有 Canvas 功能的对象。 它不会立即返回 Canvas 函数。 还是我在这个问题上错了? 当我使用 canvas-prebuilt 模块时它运行良好,但似乎 canvas 模块具有不同的 API。 我正在使用画布的最新版本 2.0.1。
编辑
我测试了以前的主要版本 (1.6.x) 并且它工作正常,这是 JSDOM 未处理的 API 更改。

我也有同样的问题。 看起来问题与 jsdom 无关,因为该修复程序不久前已在https://github.com/jsdom/jsdom/pull/1964 中合并,并且自版本13起可用。
然而, jsdom版本jest-environment-jsdom仍然停留在^11.5.1 ,我相信这是造成问题的原因:
https://github.com/facebook/jest/blob/2e2d2c8dedb76e71c0dfa85ed36b81d1f89e0d87/packages/jest-environment-jsdom/package.json#L14

无需安装canvascanvas-prebuilt就能够摆脱与 HTMLCanvasElement 相关的错误,以及@endel很好地提出的任何其他画布方法作为解决此问题的一种黑客方法。 正如@hustcc 所提议的,使用jest-canvas-mock找到了非常干净的解决方案。 有关技术细节,请查看此评论

我看到诸如“无法读取 webkitBackingStorePixelRatio of null”之类的消息,以及“
未实现:HTMLCanvasElement.prototype.getContext(没有安装canvas npm包)”,安装canvas(-prebuilt)还不够。我进入package-lock.json,修复jest-environment-jsdom指向jsdom 13 , 扔掉 node_modules, 并重新运行 npm install. 错误信息消失了. 我认为@paradite是对的, 并开了一张反对笑话的票:

https://github.com/facebook/jest/issues/8016

得到反馈。 这与玩笑被旧节点版本卡住有关。 如果您需要对最新节点的支持,请查看此处: https :

@grtjn - 检查了jest-environment-jsdom-thirteen依赖项,但在我的情况下,我仍然遇到了这两个完全相同的错误

Error: Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)
TypeError: Cannot read property 'fillRect' of null

保持我前面提到的解决方案,关于 Node 版本我不会说 10.15 是一个已弃用的版本,因为我遇到了这种环境的问题

Angular CLI: 7.2.4
Node: 10.15.0
OS: win32 x64
Angular: 7.2.4

仅供参考:我必须将"testEnvironment": "jest-environment-jsdom-thirteen"附加到我的 jest 配置中,并安装 canvas 包以及 Cairo OS 工具集。 canvas-prebuilt 似乎对我不起作用。 我正在使用Vue。

链接到 Cairo OS 工具集依赖项? 找不到那个。

@danieldanielecki查看“画布”包的主页: https : //www.npmjs.com/package/canvas#compiling

@grtjn感谢它 - 也许在某个时候会利用它。 我错过了它,但看起来比我的解决方案更复杂,因此保持项目原样。

很抱歉发布 necropost 但@grtjn建议安装 jest-environment-jsdom-13(我使用了 14 个,因为它是最近的)解决了我的问题。 我尝试使用 jest-canvas-mock 但我们做了一些奇怪的事情,当 OffscreenCanvas 不可用时,我们使用 node-canvas 伪造 createImageBitmap,这在许多浏览器中都没有,并且 jest-canvas-mock 对此感到非常困惑。 也许改天我们会得到它的工作......这是一个很酷的模拟库。

此页面是否有帮助?
0 / 5 - 0 等级