์ค์ ๊ตฌํ ์์ด ์บ๋ฒ์ค๋ฅผ ๋ชจ์ํ ์ ์์ต๋๊น( canvas
/ canvas-prebuilt
)?
์บ๋ฒ์ค ๊ธฐ๋ฅ์ด ๋์๊ฒ ์ค์ ๋ก ์ค์ํ์ง ์๊ธฐ ๋๋ฌธ์ ์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ง ์๋๋ก ํ๊ณ ์ถ์ต๋๋ค.
Not implemented: HTMLCanvasElement.prototype.getContext (without installing the canvas npm package)
๋๊ตฐ๊ฐ ์ด๊ฒ์ ํ์๋กํ๋ ๊ฒฝ์ฐ๋ฅผ ๋๋นํ์ฌ ๋ค์๊ณผ ๊ฐ์ด ํด๊ฒฐํ์ต๋๋ค.
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๋ก ๋ง์ด๊ทธ๋ ์ด์
ํ๋ ค๊ณ ํ๋ ๋งค์ฐ ์ค๋๋๊ณ ํฐ ์ฝ๋ ๊ธฐ๋ฐ์
๋๋ค.
๋๋ด ๋ฒ์ : 21.2.1
Jsdom ๋ฒ์ : 9.12.0
๋ชจ์ ์บ๋ฒ์ค(Windows์์ ์ง์๋์ง ์๊ธฐ ๋๋ฌธ์ ์บ๋ฒ์ค ํจํค์ง๋ฅผ ์ฌ์ฉํ์ง ์์)๊ฐ ๋ฌธ์ ์ ๋ํ ์๊ฒฌ์ด ์๋๋ผ ๊ณต์ ๋ฌธ์์์ ๋ค๋ฃจ์ด์ง๋ค๋ฉด ๋งค์ฐ ์ข์ ๊ฒ์ ๋๋ค.
Windows์์ ์ง์๋์ง ์์ผ๋ฏ๋ก ์บ๋ฒ์ค ํจํค์ง๋ฅผ ์ฌ์ฉํ์ง ์๊ณ
์บ๋ฒ์ค ์ฌ์ ์ ์ ์ต์ ์ด ์๋ ์ด์ ๋ ๋ฌด์์ ๋๊น? ์ด๊ฒ์ด ์ฐ๋ฆฌ ํ๋ก์ ํธ์์ ๋ฌธ์ ์์ด ์ฌ์ฉํ๊ณ ์๋ ๊ฒ์ ๋๋ค(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 ์
๋๋ค .
๋ด deps์ ๋ฏธ๋ฆฌ ๋น๋๋ ์บ๋ฒ์ค๋ฅผ ์ถ๊ฐํ์ต๋๋ค. ๋ด jest ๊ตฌ์ฑ์ ๋ณ๊ฒฝํด์ผ ํฉ๋๊น? ๋๋ ๊ทธ๊ฒ์ด ๋์๊ฒ ์ ๊ณตํ๋ ์๋ํ๊ฒ ํ ์ ์์ต๋๋ค
Not implemented: HTMLCanvasElement.prototype.toBlob (without installing the canvas npm package)
@micabe
๊ตฌ์ฑ์ ๋ณ๊ฒฝํ์ง ์์์ต๋๋ค. Jsdom์ node_modules์ ์๋ ๊ฒฝ์ฐ ๋ฏธ๋ฆฌ ๋น๋๋ ์บ๋ฒ์ค๋ฅผ ์ ํํฉ๋๋ค.
ํน์ ๊ธฐ๋ฅ์ด ์ง์๋์ง ์๋ ๊ฒ์ ์๋๊น?
yarn cache clean
์ดํ์ ์๋ํฉ๋๋ค. ๋ฒ๊ฑฐ๋กญ๊ฒ ํด์ ์ฃ์กํฉ๋๋ค! @cattermo ๊ฐ์ฌํฉ๋๋ค
์๋ง๋ jest-canvas-mock ์ด ๋์์ด ๋ ์ ์์ต๋๋ค.
์๋ฃจ์
์ ๊ฐ๋จํฉ๋๋ค. canvas
๋ฅผ devDependency๋ก ์ค์นํ๊ณ jest ํ
์คํธ๋ฅผ ๋ค์ ์คํํ๊ธฐ
์ฐธ์กฐ: 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 ํจ์๊ฐ ์๋ Object๋ฅผ ๋ฐํํฉ๋๋ค. 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 ํจ์๊ฐ ์๋ Object๋ฅผ ๋ฐํํฉ๋๋ค. Canvas ํจ์๋ฅผ ๋ฐ๋ก ๋ฐํํ์ง ์์ต๋๋ค. ์๋๋ฉด์ด ๋ฌธ์ ์ ๋ํด ๋ด๊ฐ ์๋ชป ์๊ณ ์์ต๋๊น? ์บ๋ฒ์ค์ ๋ฏธ๋ฆฌ ๋น๋๋ ๋ชจ๋์ ์ฌ์ฉํ ๋๋ ์ ์๋ํ์ง๋ง ์บ๋ฒ์ค ๋ชจ๋์ ๋ค๋ฅธ API๊ฐ ์๋ ๊ฒ ๊ฐ์ต๋๋ค. ์ ๋ ์บ๋ฒ์ค์ ์ต์ ๋ฒ์ ์ธ 2.0.1์ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
ํธ์งํ๋ค
์ด์ ์ฃผ ๋ฒ์ (1.6.x)์ ํ ์คํธํ๋๋ฐ ์ ์๋ํฉ๋๋ค. JSDOM์ด ์ฒ๋ฆฌํ์ง ์๋ API ๋ณ๊ฒฝ ์ฌํญ์ ๋๋ค.
๋๋ ๊ฐ์ ๋ฌธ์ ๋ฅผ ์๊ณ ์์ด. ์์ ์ฌํญ์ด ์ผ๋ง ์ ์ https://github.com/jsdom/jsdom/pull/1964 ์ ๋ณํฉ๋์๊ณ 13
๋ฒ์ ๋ถํฐ ์ฌ์ฉํ ์ ์์ผ๋ฏ๋ก ๋ฌธ์ ๊ฐ jsdom์ ์๋ ๊ฒ ๊ฐ์ต๋๋ค.
๊ทธ๋ฌ๋, jsdom
์์ ๋ฒ์ jest-environment-jsdom
์ฌ์ ํ์ ๊ฐํ ^11.5.1
๋๋ ๊ทธ ๋ฌธ์ ๋ฅผ ์ผ์ผํค๋ ์๊ฐ :
https://github.com/facebook/jest/blob/2e2d2c8deb76e71c0dfa85ed36b81d1f89e0d87/packages/jest-environment-jsdom/package.json#L14
Canvas๋ฅผ ์ค์นํ์ง ์๊ณ canvas-prebuilt ๋ HTMLCanvasElement์ ๊ด๋ จ๋ ์ค๋ฅ๋ฅผ ์ ๊ฑฐํ ์ ์์๊ณ @endel ์ด ์ด ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํ ํดํน์ผ๋ก ๋ฉ์ง๊ฒ ์ ์ํ ๋ค๋ฅธ ์บ๋ฒ์ค ๋ฐฉ๋ฒ์ ์ ๊ฑฐํ ์ ์์์ต๋๋ค. @hustcc๊ฐ ์ ์ํ ๊ฒ์ฒ๋ผ -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 ๊ฐ ์ณ๋ค๊ณ ์๊ฐํ๊ณ
ํผ๋๋ฐฑ์ ๋ฐ์์ต๋๋ค. ๋๋ด์ด ์ด์ ๋ ธ๋ ๋ฒ์ ๊ณผ ๊ด๋ จ์ด ์์ต๋๋ค. ์ต์ ๋ ธ๋์ ๋ํ ์ง์์ด ํ์ํ ๊ฒฝ์ฐ ์ฌ๊ธฐ๋ฅผ ์ฐธ์กฐ ํ์ญ์์ค.
@grtjn - -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
์ฐธ๊ณ ๋ก ์ jest ๊ตฌ์ฑ์ "testEnvironment": "jest-environment-jsdom-thirteen"
๋ฅผ ์ถ๊ฐํ๊ณ Canvas ํจํค์ง์ Cairo OS ๋๊ตฌ ์ธํธ๋ฅผ ์ค์นํด์ผ ํ์ต๋๋ค. Canvas-prebuilt๊ฐ ์ ์๊ฒ ํจ๊ณผ๊ฐ ์๋ ๊ฒ ๊ฐ์์ต๋๋ค. ์ ๋ ๋ทฐ๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
Cairo OS ๋๊ตฌ ์ธํธ ์ข ์์ฑ์ ๋ํ ๋งํฌ? ์ฐพ์ ์ ์์ต๋๋ค.
@danieldanielecki 'canvas' ํจํค์ง ๋ฉ์ธ ํ์ด์ง ์ฐธ์กฐ: https://www.npmjs.com/package/canvas#compiling
@grtjn ๊ฐ์ฌํฉ๋๋ค. ์ธ์ ๊ฐ๋ ํ์ฉํ ์ ์์ ๊ฒ์ ๋๋ค. ๋๋ ๊ทธ๊ฒ์ ๋์น๊ณ ์์์ง๋ง ๋ด ์๋ฃจ์ ๋ณด๋ค ๋ ๋ณต์กํด ๋ณด์ด๊ธฐ ๋๋ฌธ์ ํ๋ก์ ํธ๋ฅผ ๊ทธ๋๋ก ์ ์งํฉ๋๋ค.
necropost์๊ฒ ๋ฏธ์ํ์ง๋ง jest -environment-jsdom-thirteen ์ค์น์ ๋ํ
๊ฐ์ฅ ์ ์ฉํ ๋๊ธ
๋ค์์ ๋ด๊ฐ ์๊ฐํด๋ธ ์บ๋ฒ์ค๋ฅผ ์กฐ๋กฑํ๋ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ๋๋ค.