Jsdom: Mock canvas

Criado em 22 mar. 2017  ·  25Comentários  ·  Fonte: jsdom/jsdom

É possível simular a tela sem ter a implementação real ( canvas / canvas-prebuilt )?

Gostaria de evitar que esse erro aconteça, pois a funcionalidade do canvas não é muito importante para mim:

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

Comentários muito úteis

Esta é uma maneira simples de simular uma tela que eu criei:

//
// 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);

Todos 25 comentários

Caso alguém precise disso, aqui está como resolvi:

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

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

Por favor, não faça isso. Ele será interrompido em uma versão de patch futura. Em vez disso, substitua o método getContext (), ou seja, window.HTMLCanvasElement.prototype.getContext = ...

Obrigado @domenic !

@domenic Não consigo fazer isso funcionar. Meu método substituído não é chamado. Eu uso o arquivo jest e o arquivo de script de configuração da seguinte maneira:

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');

Desculpe por poluir globalmente no nó, mas esta é uma base de código muito antiga e grande que tento migrar para o Jest.
Versão Jest: 21.2.1
Versão Jsdom: 9.12.0

Seria muito bom se o mocking do canvas (sem usar o pacote canvas, já que não é suportado no Windows) fosse coberto pela documentação oficial e não apenas como um comentário em um problema.

sem usar o pacote canvas, pois não é compatível com Windows

Por que a pré-configuração da tela não é uma opção para você? É isso que estamos usando em nosso projeto sem nenhum problema (Win, Mac e Linux, embora tudo tenha que ser x64).

Em geral, não planejamos adicionar documentos ou ajudar com problemas únicos de simulação. Abordamos isso em https://github.com/tmpvar/jsdom#intervening -before-parsing em geral e qualquer problema específico estará relacionado à sua base de código específica.

Esta é uma maneira simples de simular uma tela que eu criei:

//
// 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);

Muito obrigado! O pacote pré-construído do canvas parece estar funcionando.

Olá @cattermo ,
Eu adicionei canvas pré-construídas aos meus deps, preciso alterar minha configuração de jest? Eu não consigo fazer funcionar, isso me dá
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)

@micabe
Não fiz nenhuma alteração na configuração. Jsdom pegará a tela pré-construída se estiver presente em node_modules.

Talvez essa função específica não seja compatível?

Agora está funcionando depois de yarn cache clean Desculpe incomodá-lo! obrigado @cattermo

Talvez jest-canvas-mock possa ajudar.

A solução é simples, basta instalar canvas como um devDependency e executar novamente seus testes de jest.

ref: https://github.com/jsdom/jsdom#canvas -support

Isso ainda não está funcionando devido à maneira como o jsdom verifica os módulos do canvas em 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;
  }

Fazer require ('canvas') retorna um objeto que tem a função Canvas. Ele não retorna a função Canvas imediatamente. Ou estou errado neste assunto? Funcionou bem quando eu estava usando o módulo canvas pré-construído, mas parece que o módulo canvas tem uma API diferente. Estou usando a versão mais recente do canvas, 2.0.1.
Editar
Testei a versão principal anterior (1.6.x) e funciona bem, é uma alteração da API que o JSDOM não está tratando.

Você pode apenas fazer:

HTMLCanvasElement.prototype.getContext = jest.fn()

se a implementação real não for importante para você

Isso ainda não está funcionando devido à maneira como o jsdom verifica os módulos do canvas em 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;
  }

Fazer require ('canvas') retorna um objeto que tem a função Canvas. Ele não retorna a função Canvas imediatamente. Ou estou errado neste assunto? Funcionou bem quando eu estava usando o módulo canvas pré-construído, mas parece que o módulo canvas tem uma API diferente. Estou usando a versão mais recente do canvas, 2.0.1.
Editar
Testei a versão principal anterior (1.6.x) e funciona bem, é uma alteração da API que o JSDOM não está tratando.

Eu tenho o mesmo problema. Parece que o problema não é com jsdom, pois a correção foi mesclada um tempo atrás em https://github.com/jsdom/jsdom/pull/1964 e está disponível desde a versão 13 .
No entanto, a versão jsdom em jest-environment-jsdom ainda está presa em ^11.5.1 e acredito que isso esteja causando o problema:
https://github.com/facebook/jest/blob/2e2d2c8dedb76e71c0dfa85ed36b81d1f89e0d87/packages/jest-environment-jsdom/package.json#L14

Sem instalar o canvas , ou canvas pré-construídas foram capazes de se livrar dos erros relacionados ao HTMLCanvasElement, bem como quaisquer outros métodos de canvas bem propostos por @endel como um hack para contornar este problema. Como @hustcc propôs, usou jest-canvas-mock para encontrar uma solução bastante limpa. Para detalhes técnicos, dê uma olhada neste comentário .

Eu estava vendo mensagens como "Cannot read webkitBackingStorePixelRatio of null", bem como "
Não implementado: HTMLCanvasElement.prototype.getContext (sem instalar o pacote npm do canvas) ", e instalar o canvas (-prebuilt) não foi suficiente. Entrei no package-lock.json, consertei o jest-environment-jsdom para apontar para jsdom 13 , jogou fora node_modules e reran npm install. As mensagens de erro foram embora. Acho que @paradite está certo e abriu um tíquete contra jest:

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

Tenho feedback. Está relacionado ao fato de o gracejo ficar preso a versões de nós mais antigas. Se precisar de suporte para o nó mais recente, veja aqui: https://www.npmjs.com/package/jest-environment-jsdom-thirteen. No entanto, isso é específico para uma brincadeira, então talvez um pouco fora do assunto aqui. Compartilhando de qualquer maneira para a posteridade ..

@grtjn - verifiquei a dependência jest-environment-jsdom-treze , mas no meu caso ainda

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

Mantendo minha solução mencionada anteriormente, sobre a versão do Node eu não diria que a 10.15 está obsoleta, pois tenho os problemas para tal ambiente

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

Para sua informação: Tive que acrescentar "testEnvironment": "jest-environment-jsdom-thirteen" à minha configuração de brincadeira e instalar o pacote canvas, bem como o conjunto de ferramentas do Cairo OS. canvas pré-construídas não parecem funcionar para mim. Estou usando o Vue.

Link para a dependência do conjunto de ferramentas do Cairo OS? Não foi possível encontrar esse.

@danieldanielecki Veja a página principal do pacote 'canvas': https://www.npmjs.com/package/canvas#compiling

@grtjn obrigado por isso - talvez em algum momento tire vantagem disso. Eu estava sentindo falta, mas parece mais complicado do que a minha solução, então mantendo o projeto como está.

Desculpe por necropost, mas a sugestão @grtjn de instalar jest-environment-jsdom-treze (usei quatorze apenas porque é mais recente) corrigiu meu problema. Eu tentei usar jest-canvas-mock, mas fizemos algumas coisas estranhas onde fingimos criarImageBitmap usando node-canvas quando OffscreenCanvas não está disponível, o que não está em muitos navegadores, e jest-canvas-mock ficou muito confuso com isso. Talvez outro dia vamos fazer isso funcionar ... é uma biblioteca simulada legal.

Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

domenic picture domenic  ·  3Comentários

potapovDim picture potapovDim  ·  4Comentários

kilianc picture kilianc  ·  4Comentários

eszthoff picture eszthoff  ·  3Comentários

tolmasky picture tolmasky  ·  4Comentários