Jsdom: Lienzo simulado

Creado en 22 mar. 2017  ·  25Comentarios  ·  Fuente: jsdom/jsdom

¿Es posible simular el lienzo sin tener la implementación real ( canvas / canvas-prebuilt )?

Me gustaría evitar que ocurra este error, ya que la funcionalidad del lienzo no es realmente importante para mí:

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

Comentario más útil

Aquí hay una forma sencilla de simular el lienzo que se me ocurrió:

//
// 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 comentarios

En caso de que alguien necesite esto, así es como lo resolví:

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, no hagas eso. Se romperá en una futura versión de parche. En su lugar, anule el método getContext (), es decir, window.HTMLCanvasElement.prototype.getContext = ...

¡Gracias @domenic !

@domenic No puedo hacer que eso funcione. No se llama a mi método anulado. Utilizo el archivo de script de configuración y broma de la siguiente manera:

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

Lo siento por contaminar global en el nodo, pero esta es una base de código muy antigua y grande que intento migrar a Jest.
Versión de broma: 21.2.1
Versión de Jsdom: 9.12.0

Sería muy bueno si los documentos oficiales cubrieran la burla de lienzo (sin usar el paquete de lienzo, ya que no es compatible con Windows) y no solo como un comentario en un problema.

sin usar el paquete de lienzo ya que no es compatible con Windows

¿Por qué el lienzo preconstruido no es una opción para usted? Eso es lo que estamos usando en nuestro proyecto sin ningún problema (Win, Mac y Linux, aunque todo tiene que ser x64).

En general, no estamos planeando agregar documentos o ayudar con problemas de simulación únicos. Hemos cubierto esto en https://github.com/tmpvar/jsdom#intervening -before-parsing en general y cualquier problema específico estará relacionado con su base de código específica.

Aquí hay una forma sencilla de simular el lienzo que se me ocurrió:

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

¡Muchas gracias! El paquete de lienzo prediseñado parece estar funcionando.

Hola @cattermo ,
He agregado un lienzo preconstruido a mis departamentos, ¿necesito cambiar mi configuración de broma? No puedo hacer que funcione, me da
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)

@micabe
No realicé ningún cambio de configuración. Jsdom recogerá el lienzo precompilado si está presente en node_modules.

¿Quizás esa función específica no es compatible?

Está funcionando ahora después de yarn cache clean Lo siento por molestarte! gracias @cattermo

Tal vez jest-canvas-mock pueda ayudar.

La solución es simple, simplemente instale canvas como devDependency y vuelva a ejecutar sus pruebas de broma.

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

Eso todavía no funciona debido a la forma en que jsdom verifica los módulos de lienzo en 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;
  }

Hacer require ('lienzo') devuelve un Objeto que tiene la función Canvas. No devuelve la función Canvas de inmediato. ¿O me equivoco en este tema? Funcionó bien cuando estaba usando el módulo preconstruido de lienzo, pero parece que el módulo de lienzo tiene una API diferente. Estoy usando la última versión de canvas, 2.0.1.
Editar
Probé la versión principal anterior (1.6.x) y funciona bien, es un cambio de API que JSDOM no está tratando.

Puedes simplemente hacer:

HTMLCanvasElement.prototype.getContext = jest.fn()

si la implementación real no es importante para usted

Eso todavía no funciona debido a la forma en que jsdom verifica los módulos de lienzo en 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;
  }

Hacer require ('lienzo') devuelve un Objeto que tiene la función Canvas. No devuelve la función Canvas de inmediato. ¿O me equivoco en este tema? Funcionó bien cuando estaba usando el módulo preconstruido de lienzo, pero parece que el módulo de lienzo tiene una API diferente. Estoy usando la última versión de canvas, 2.0.1.
Editar
Probé la versión principal anterior (1.6.x) y funciona bien, es un cambio de API que JSDOM no está tratando.

Tengo el mismo problema. Parece que el problema no es con jsdom, ya que la solución se fusionó hace un tiempo en https://github.com/jsdom/jsdom/pull/1964 y está disponible desde la versión 13 .
Sin embargo, la versión jsdom en jest-environment-jsdom todavía está bloqueada en ^11.5.1 y creo que eso está causando el problema:
https://github.com/facebook/jest/blob/2e2d2c8dedb76e71c0dfa85ed36b81d1f89e0d87/packages/jest-environment-jsdom/package.json#L14

Sin instalar canvas , o canvas-prebuilt pudo deshacerse de los errores relacionados con HTMLCanvasElement, así como cualquier otro método de lienzo bien propuesto por @endel como un truco para solucionar este problema. Como propuso @hustcc , usé jest-canvas-mock para encontrar una solución bastante limpia. Para obtener detalles técnicos, eche un vistazo a este comentario .

Veía mensajes como "No se puede leer webkitBackingStorePixelRatio de null", así como "
No implementado: HTMLCanvasElement.prototype.getContext (sin instalar el paquete canvas npm) ", e instalar canvas (-prebuilt) no fue suficiente. Entré en package-lock.json, arreglé el jest-environment-jsdom para que apunte a jsdom 13 , tiró node_modules y volvió a ejecutar npm install. Los mensajes de error desaparecieron. Creo que @paradite tiene razón y abrió un ticket contra broma:

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

Recibí comentarios. Está relacionado con la broma que se atasca con versiones de nodos anteriores. Si necesita soporte para el último nodo, busque aquí: https://www.npmjs.com/package/jest-environment-jsdom-thirteen. Sin embargo, esto es específico de la broma, por lo que quizás un poco fuera de tema aquí. Compartiendo de todos modos para la posteridad.

@grtjn : verifiqué la dependencia jest-environment-jsdom-thirteen , pero en mi caso todavía tengo estos 2 exactamente los mismos errores

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

Manteniendo mi solución mencionada anteriormente, sobre la versión de Node, no diría que 10.15 es una obsoleta, ya que tengo los problemas para dicho entorno

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

FYI: Tuve que agregar "testEnvironment": "jest-environment-jsdom-thirteen" a mi configuración de jest e instalar el paquete canvas, así como el conjunto de herramientas del SO Cairo. canvas-prebuilt no pareció funcionar para mí. Estoy usando Vue.

¿Enlace a la dependencia del conjunto de herramientas del SO Cairo? No pude encontrar ese.

@danieldanielecki Consulte la página principal del paquete 'lienzo': https://www.npmjs.com/package/canvas#compiling

@grtjn gracias por ello, tal vez en algún momento lo aproveche. Me lo estaba perdiendo, pero parece más complicado que mi solución, por lo que mantengo el proyecto como está.

Perdón por necropost, pero la sugerencia de @grtjn de instalar jest-environment-jsdom-thirteen (usé catorce solo porque es más reciente) solucionó mi problema. Intenté usar jest-canvas-mock pero hicimos algunas cosas raras en las que falsificamos createImageBitmap usando node-canvas cuando OffscreenCanvas no está disponible, que no está en muchos navegadores, y jest-canvas-mock se confundió bastante con esto. Tal vez otro día lo haremos funcionar ... es una biblioteca simulada genial.

¿Fue útil esta página
0 / 5 - 0 calificaciones

Temas relacionados

vsemozhetbyt picture vsemozhetbyt  ·  4Comentarios

Progyan1997 picture Progyan1997  ·  3Comentarios

lehni picture lehni  ·  4Comentarios

josephrexme picture josephrexme  ·  4Comentarios

mitar picture mitar  ·  4Comentarios