Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to add <canvas> support to my tests in Jest?

In my Jest unit test I am rendering a component with a ColorPicker. The ColorPicker component creates a canvas object and 2d context but returns 'undefined' which throws an error "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"

I'm having troubles figuring out why I can't get a 2d context. Maybe there an issue with my test config?

"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
}
like image 314
Adgezaza Avatar asked Oct 21 '15 20:10

Adgezaza


People also ask

How do I use Jest canvas?

In your package. json under the jest , create a setupFiles array and add jest-canvas-mock to the array. If you already have a setupFiles attribute you can also append jest-canvas-mock to the array. More about in configuration section.

Is Jest enough for testing?

Jest is a JavaScript test runner that lets you access the DOM via jsdom . While jsdom is only an approximation of how the browser works, it is often good enough for testing React components.

Do you need Jest for react testing library?

However, there are some things you can do when configuring your testing framework to reduce some boilerplate. In these docs we'll demonstrate configuring Jest, but you should be able to do similar things with any testing framework (React Testing Library does not require that you use Jest).


4 Answers

For those looking for examples using create-react-app

Install

yarn add --dev jest-canvas-mock 

Create a new ${rootDir}/src/setupTests.js with

import 'jest-canvas-mock'; 
like image 77
Siva Avatar answered Sep 30 '22 19:09

Siva


It's because your test doesn't run in a real browser. Jest uses jsdom for mocking the necessary parts of the DOM to be able to run the tests in Node, thus avoiding style calculation and rendering that a browser would normally do. This is cool because this makes tests fast.

On the other hand, if you need browser APIs in your components, it's more difficult than in the browser. Luckily, jsdom has support for canvas. You just have to configure it:

jsdom includes support for using the canvas package to extend any <canvas> elements with the canvas API. To make this work, you need to include canvas as a dependency in your project, as a peer of jsdom. If jsdom can find the canvas package, it will use it, but if it's not present, then <canvas> elements will behave like <div>s.

Alternatively, you could replace Jest with some browser-based test runner like Karma. Jest is pretty buggy anyway.

like image 44
mik01aj Avatar answered Sep 30 '22 21:09

mik01aj


Jest / jsdom can handle canvas elements if the library node-canvas is installed.

Thus uninstall jest-canvas-mock (if installed) and install canvas:

npm uninstall jest-canvas-mock
npm i --save-dev canvas
like image 27
sstauross Avatar answered Sep 30 '22 21:09

sstauross


For my use case I did simple monkey patching like this

beforeEach(() => {
    const createElement = document.createElement.bind(document);
    document.createElement = (tagName) => {
        if (tagName === 'canvas') {
            return {
                getContext: () => ({}),
                measureText: () => ({})
            };
        }
        return createElement(tagName);
    };
});

No need to install canvas-prebuilt or sinon.

like image 26
Andzej Maciusovic Avatar answered Sep 30 '22 19:09

Andzej Maciusovic