私の Jest 単体テストでは、コンポーネントを ColorPicker でレンダリングしています。 ColorPicker
コンポーネントはキャンバスオブジェクトと2Dコンテキストを作成しますが、エラーをスローする'undefined'
を返します"Cannot set property 'fillStyle' of undefined"
if (typeof document == 'undefined') return null; // Dont Render On Server
var canvas = document.createElement('canvas');
canvas.width = canvas.height = size * 2;
var ctx = canvas.getContext('2d'); // returns 'undefined'
ctx.fillStyle = c1; // "Cannot set property 'fillStyle' of undefined"
2Dコンテキストを取得できない理由を理解できません。テスト構成に問題があるのでしょうか?
"jest": {
"scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
"unmockedModulePathPatterns": [
"<rootDir>/node_modules/react",
"<rootDir>/node_modules/react-dom",
"<rootDir>/node_modules/react-addons-test-utils",
"<rootDir>/node_modules/react-tools"
],
"moduleFileExtensions": [
"jsx",
"js",
"json",
"es6"
],
"testFileExtensions": [
"jsx"
],
"collectCoverage": true
}
これは、テストが実際のブラウザーで実行されないためです。 Jestは、DOMの必要な部分をモックしてNodeでテストを実行できるようにするためにjsdom
を使用します。これにより、ブラウザーが通常行うようなスタイル計算とレンダリングを回避できます。テストが高速になるため、これはすばらしいことです。
一方、コンポーネントにブラウザAPIが必要な場合は、ブラウザよりも難しくなります。幸い、 jsdom
はcanvasをサポートしています 。あなたはそれを設定する必要があります:
jsdomには canvas パッケージを使用して、キャンバスAPIで
<canvas>
要素を拡張するためのサポートが含まれています。これを機能させるには、jsdomのピアとして、プロジェクトの依存関係としてキャンバスを含める必要があります。 jsdomがcanvasパッケージを見つけることができる場合、それを使用しますが、それが存在しない場合、<canvas>
要素は<div>
sのように動作します。
または、Jestを Karma のようなブラウザベースのテストランナーに置き換えることもできます。ジェストはとにかく かなりバギー です。
Create-react-appを使用した例を探している方
インストール
yarn add --dev jest-canvas-mock
新しいを作成します ${rootDir}/src/setupTests.js
と
import 'jest-canvas-mock';
私はまったく同じ問題を抱えていました。テストを実行するためにgitlab ciにデプロイしています。npmcanvasにはCairoをインストールする必要があるため、これを使用することは現実的ではありませんでした。
私が本当にやりたかったことは、Jestを介して実装をモックすることだけで、実際に実際のコンテキストを作成しようとはしません。これが私がそれを解決した方法です:
package.jsonに追加
"jest": {
"setupFiles": ["./tests/setup.js"],
}
tests/setup.js
import sinon from 'sinon';
const createElement = global.document.createElement;
const FAKECanvasElement = {
getContext: jest.fn(() => {
return {
fillStyle: null,
fillRect: jest.fn(),
drawImage: jest.fn(),
getImageData: jest.fn(),
};
}),
};
/**
* Using Sinon to stub the createElement function call with the original method
* unless we match the 'canvas' argument. If that's the case, return the Fake
* Canvas object.
*/
sinon.stub(global.document, 'createElement')
.callsFake(createElement)
.withArgs('canvas')
.returns(FAKECanvasElement);
私のユースケースでは、このような単純なサルのパッチを行いました
beforeEach(() => {
const createElement = document.createElement.bind(document);
document.createElement = (tagName) => {
if (tagName === 'canvas') {
return {
getContext: () => ({}),
measureText: () => ({})
};
}
return createElement(tagName);
};
});
Canvas-prebuiltやsinonをインストールする必要はありません。
npm install -D canvas-prebuilt@1
これはjestのキャンバスをサポートします。これは、Lottie.jsが原因でエラーが発生した場合でも機能します。
React-testing-libraryとjest-image-snapshotを使用して、jestのキャンバスからイメージスナップショットテストを作成できました。それは一種の流行語ですが、うまくいきました。
Node-canvas(jest-canvas-mockなどではない)を使用してjestテストを適切に設定できる場合は、canvas要素のtoDataURLを文字通り呼び出すことができます。
import {render, waitForElement} from 'react-testing-library'
import React from 'react'
import { toMatchImageSnapshot } from 'jest-image-snapshot'
expect.extend({ toMatchImageSnapshot })
test('open a canvas', async () => {
const { getByTestId } = render(
<YourCanvasContainer />,
)
const canvas = await waitForElement(() =>
getByTestId('your_canvas'),
)
const img = canvas.toDataURL()
const data = img.replace(/^data:image\/\w+;base64,/, '')
const buf = Buffer.from(data, 'base64')
expect(buf).toMatchImageSnapshot({
failureThreshold: 0.001,
failureThresholdType: 'percent',
})
})
Travis-CIで実行するとランダムに異なる2つのピクセルがあったため、image/pngデータのURLを直接比較するのではなく、低いしきい値を使用する必要があることがわかりました
また、jest環境jsdomをjest-environment-jsdom-thirteenまたはjest-environment-jsdom-fourteen(このページの他の回答も同様に提案しています)に手動でアップグレードすることを検討し、 https://github.com/jsdom/jsdomを参照)/issues/1782
jest-canvas-mock はうまくいきます。
1)**npm i --save-dev jest-canvas-mock**
によるインストール
2)jestjest.config.jsに"setupFiles": ["jest-canvas-mock"]
属性を追加します。 (すでにsetupFiles属性がある場合は、配列にjest-canvas-mockを追加することもできます。例:"setupFiles": ["something-xyz.js", "jest-canvas-mock"]
)。
全部終わった。
Jestでキャンバス出力をテストするには、以下を実行する必要があります。
少なくともjsdom 13を使用していることを確認してください。これを行うには、jestのjsomパッケージを含めます。14の場合は次のとおりです。
jest-environment-jsdom-fourteen
そして、これを使用するようにjestを設定します
jest --env=jest-environment-jsdom-fourteen
またはpackage.json
"jest": {
...
"testEnvironment": "jest-environment-jsdom-fourteen",
canvas
npmパッケージを含めます。 (2.x以降、これにはビルドバージョンが含まれるため、canvas-prebuiltは非推奨です)。