Jsdom: Макет холста

Созданный на 22 мар. 2017  ·  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 Я не могу заставить это работать. Мой переопределенный метод не вызывается. Я использую файл jest и установочного скрипта следующим образом:

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.
Версия Jest: 21.2.1
Версия Jsdom: 9.12.0

Было бы очень хорошо, если бы имитация холста (без использования пакета холста, поскольку он не поддерживается в Windows) охватывалась официальной документацией, а не только как комментарий к проблеме.

без использования пакета холста, так как не поддерживается в Windows

Почему вам не подходит вариант с

Как правило, мы не планируем добавлять документы или помогать с одноразовыми издевательствами. Мы рассмотрели это в 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 в свой deps, мне нужно изменить конфигурацию jest? Я не могу заставить его работать, это дает мне
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)

@micabe
Я не вносил никаких изменений в конфигурацию. Jsdom подберет предварительно собранный холст, если он присутствует в node_modules.

Может быть, эта конкретная функция не поддерживается?

Теперь он работает после yarn cache clean Извините за беспокойство! спасибо @cattermo

Может быть, шутка-холст-издевательство может помочь.

Решение простое: просто установите canvas как devDependency и повторно запустите свои шутливые тесты.

ссылка: https://github.com/jsdom/jsdom#canvas -support

Это все еще не работает, потому что 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, но, похоже, модуль Canvas имеет другой API. Я использую последнюю версию Canvas, 2.0.1.
Редактировать
Я тестировал предыдущую основную версию (1.6.x), и она отлично работает, это изменение API, которое JSDOM не обрабатывает.

Вы можете просто сделать:

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, но, похоже, модуль Canvas имеет другой API. Я использую последнюю версию Canvas, 2.0.1.
Редактировать
Я тестировал предыдущую основную версию (1.6.x), и она отлично работает, это изменение API, которое JSDOM не обрабатывает.

У меня точно такая же проблема. Похоже, проблема не в 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

Без установки холста , или холст-прекомпилированное был в состоянии избавиться от ошибок , связанных с 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://www.npmjs.com/package/jest-environment-jsdom-thirteen. Хотя это шутка специфическая, так что, возможно, здесь немного не по теме. Делиться так или иначе для потомков ..

@grtjn - проверил зависимость jest-environment-jsdom-thirteen , но в моем случае у меня все равно были эти 2 точно такие же ошибки

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 и установить пакет холста, а также набор инструментов Cairo OS. Canvas-prebuilt, похоже, не сработал для меня. Я использую Vue.

Ссылка на зависимость набора инструментов Cairo OS? Не могу найти того.

@danieldanielecki См. главную страницу пакета 'canvas': https://www.npmjs.com/package/canvas#compiling

@grtjn спасибо за это - может быть, в какой-то момент этим воспользуются. Мне его не хватало, но он выглядит сложнее, чем мое решение, поэтому сохраните проект как есть.

Извините за necropost, но предложение @grtjn об установке jest-environment-jsdom-thirteen (я использовал четырнадцать только с тех пор, как оно появилось позже) устранило мою проблему. Я пробовал использовать jest-canvas-mock, но мы сделали несколько странных вещей, где мы подделали createImageBitmap с помощью node-canvas, когда OffscreenCanvas недоступен, чего нет во многих браузерах, и jest-canvas-mock из-за этого довольно запутался. Может быть, в другой день мы получим эту работу ... это классная имитация библиотеки.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги