Jsdom: Toile factice

Créé le 22 mars 2017  ·  25Commentaires  ·  Source: jsdom/jsdom

Est-il possible de simuler le canevas sans avoir l'implémentation réelle ( canvas / canvas-prebuilt ) ?

J'aimerais éviter que cette erreur ne se produise, car la fonctionnalité de canevas n'est pas vraiment importante pour moi :

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

Commentaire le plus utile

Voici un moyen simple de se moquer de la toile que j'ai trouvée :

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

Tous les 25 commentaires

Au cas où quelqu'un aurait besoin de cela, voici comment je l'ai résolu :

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

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

S'il te plaît, ne fais pas ça. Il se brisera dans une future version de correctif. Au lieu de cela, remplacez la méthode getContext(), c'est-à-dire window.HTMLCanvasElement.prototype.getContext = ...

Merci @domenic !

@domenic, je ne peux pas le faire fonctionner. Ma méthode remplacée n'est pas appelée. J'utilise jest et le fichier de script d'installation comme suit :

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

Désolé de polluer global en node mais il s'agit d'une base de code très ancienne et volumineuse que j'essaie de migrer vers Jest.
Version du jeu : 21.2.1
Version Jsdom : 9.12.0

Ce serait très bien si se moquer de canvas (sans utiliser le package canvas car non pris en charge par Windows) était couvert par la documentation officielle et pas seulement comme commentaire dans un numéro.

sans utiliser le package canvas car non pris en charge sous Windows

Pourquoi canvas-prebuilt n'est-il pas une option pour vous ? C'est ce que nous utilisons dans notre projet sans aucun problème (Win, Mac et Linux, bien que tout doive être x64).

En général, nous ne prévoyons pas d'ajouter des documents ou d'aider avec des problèmes de moquerie ponctuels. Nous avons couvert cela dans https://github.com/tmpvar/jsdom#intervening -before-parsing en général et tout problème spécifique sera lié à votre base de code spécifique.

Voici un moyen simple de se moquer de la toile que j'ai trouvée :

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

Merci beaucoup! Le package pré-construit canvas semble fonctionner.

Bonjour @cattermo ,
J'ai ajouté canvas-prebuilt à mes deps, dois-je changer ma configuration jest ? Je ne peux pas le faire fonctionner ça me donne
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)

@micabe
Je n'ai fait aucune modification de configuration. Jsdom récupérera le canevas pré-construit s'il est présent dans node_modules.

Peut-être que cette fonction spécifique n'est pas prise en charge ?

Cela fonctionne maintenant après yarn cache clean Désolé de vous déranger ! merci @cattermo

Peut - être que

La solution est simple, il suffit d'installer canvas tant que devDependency et de relancer vos jest tests.

réf : https://github.com/jsdom/jsdom#canvas -support

Cela ne fonctionne toujours pas à cause de la façon dont jsdom vérifie les modules de canevas dans 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;
  }

Faire require('canvas') renvoie un objet qui a la fonction Canvas. Il ne renvoie pas la fonction Canvas tout de suite. Ou est-ce que je me trompe sur cette question ? Cela fonctionnait bien lorsque j'utilisais le module pré-construit canvas, mais il semble que le module canvas ait une API différente. J'utilise la dernière version de canvas, 2.0.1.
Éditer
J'ai testé la version majeure précédente (1.6.x) et cela fonctionne bien, c'est un changement d'API que JSDOM ne traite pas.

Tu peux juste faire :

HTMLCanvasElement.prototype.getContext = jest.fn()

si la mise en œuvre réelle n'est pas importante pour vous

Cela ne fonctionne toujours pas à cause de la façon dont jsdom vérifie les modules de canevas dans 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;
  }

Faire require('canvas') renvoie un objet qui a la fonction Canvas. Il ne renvoie pas la fonction Canvas tout de suite. Ou est-ce que je me trompe sur cette question ? Cela fonctionnait bien lorsque j'utilisais le module pré-construit canvas, mais il semble que le module canvas ait une API différente. J'utilise la dernière version de canvas, 2.0.1.
Éditer
J'ai testé la version majeure précédente (1.6.x) et cela fonctionne bien, c'est un changement d'API que JSDOM ne traite pas.

J'ai le même problème. Il semble que les problèmes ne concernent pas jsdom car le correctif a été fusionné il y a quelque temps dans https://github.com/jsdom/jsdom/pull/1964 et disponible depuis la version 13 .
Cependant, la version jsdom dans jest-environment-jsdom est toujours bloquée à ^11.5.1 et je pense que c'est à l'origine du problème :
https://github.com/facebook/jest/blob/2e2d2c8dedb76e71c0dfa85ed36b81d1f89e0d87/packages/jest-environment-jsdom/package.json#L14

Sans installer canvas , ou canvas-prebuilt a pu éliminer les erreurs liées à HTMLCanvasElement, ainsi que toutes les autres méthodes de canvas joliment proposées par @endel comme hack pour contourner ce problème. Comme @hustcc l'a proposé, jest-canvas-mock pour trouver une solution assez propre. Pour les détails techniques s'il vous plaît jeter un oeil sur ce commentaire .

Je voyais des messages comme "Impossible de lire webkitBackingStorePixelRatio of null", ainsi que "
Non implémenté : HTMLCanvasElement.prototype.getContext (sans installer le package canvas npm)", et l'installation de canvas (-prebuilt) n'était pas suffisante. Je suis allé dans package-lock.json, j'ai corrigé le jest-environment-jsdom pour pointer vers jsdom 13 , a jeté node_modules et a réexécuté l'installation de npm. Les messages d'erreur ont disparu. Je pense que @paradite a raison et a ouvert un ticket contre jest :

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

J'ai eu des retours. C'est lié au fait que j'est coincé avec des versions de nœuds plus anciennes. Si vous avez besoin d'assistance pour le dernier nœud, regardez ici : https://www.npmjs.com/package/jest-environment-jsdom-thirteen. C'est une plaisanterie spécifique, donc peut-être un peu hors sujet ici. Partage de toute façon pour la postérité..

@grtjn - a vérifié la dépendance jest-environment-jsdom-thirteen , mais dans mon cas, j'ai toujours exactement les mêmes erreurs

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

En gardant ma solution mentionnée plus tôt, à propos de la version Node, je ne dirais pas que 10.15 est obsolète, car j'ai eu des problèmes pour un tel environnement

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

Pour info : j'ai dû ajouter "testEnvironment": "jest-environment-jsdom-thirteen" à ma configuration jest et installer le package canvas, ainsi que l'ensemble d'outils Cairo OS. canvas-prebuilt ne semble pas fonctionner pour moi. J'utilise Vue.

Lien vers la dépendance de l'ensemble d'outils Cairo OS ? Impossible de trouver celui-là.

@danieldanielecki Voir la page principale du package 'canvas' : https://www.npmjs.com/package/canvas#compiling

@grtjn merci pour cela - peut-être qu'à un moment donné en profitera. Cela me manquait, mais cela semble plus compliqué que ma solution, donc je garde le projet tel quel.

Désolé de necropost mais la suggestion de @grtjn d'installer jest-environment-jsdom-thirteen (j'en ai utilisé quatorze juste parce que c'est plus récent) a résolu mon problème. J'ai essayé d'utiliser jest-canvas-mock mais nous avons fait des trucs étranges où nous avons simulé createImageBitmap en utilisant node-canvas lorsque OffscreenCanvas n'est pas disponible, ce qui n'est pas le cas dans de nombreux navigateurs, et jest-canvas-mock a été assez confus par cela. Peut-être qu'un autre jour, nous le ferons fonctionner ... c'est une bibliothèque fictive cool.

Cette page vous a été utile?
0 / 5 - 0 notes