web-dev-qa-db-fra.com

Comment ajouter le support <canvas> à mes tests dans Jest?

Dans mon Jest test unitaire, je rend un composant avec un ColorPicker . Le composant ColorPicker crée un objet canevas et un contexte 2D mais renvoie 'undefined' qui génère une erreur "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"

J'ai du mal à comprendre pourquoi je ne peux pas obtenir un contexte 2D. Peut-être y a-t-il un problème avec ma configuration de test?

"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
}
21
Adgezaza

C'est parce que votre test ne s'exécute pas dans un vrai navigateur. Jest utilise jsdom pour se moquer des parties nécessaires du DOM pour pouvoir exécuter les tests dans Node, évitant ainsi le calcul de style et le rendu que ferait normalement un navigateur. C'est cool car cela rend les tests rapides.

D'un autre côté, si vous avez besoin d'API de navigateur dans vos composants, c'est plus difficile que dans le navigateur. Heureusement, jsdom prend en charge le canevas . Il suffit de le configurer:

jsdom inclut la prise en charge de l'utilisation du package canvas pour étendre tout <canvas> éléments avec l'API canvas. Pour que cela fonctionne, vous devez inclure le canevas comme dépendance dans votre projet, en tant que pair de jsdom. Si jsdom peut trouver le paquet canvas, il l'utilisera, mais s'il n'est pas présent, alors <canvas> les éléments se comporteront comme <div>s.

Alternativement, vous pouvez remplacer Jest par un lanceur de test basé sur un navigateur comme Karma . Jest is pretty buggy de toute façon.

12
mik01aj

Pour ceux qui recherchent des exemples utilisant create-react-app

Installer

yarn add --dev jest-canvas-mock

Créer un nouveau ${rootDir}/src/setupTests.js avec

import 'jest-canvas-mock';
13
shiva

J'ai eu exactement le même problème. Je déploie vers gitlab ci pour exécuter mes tests, et puisque npm canvas nécessite une installation de Cairo, utiliser ce n'était pas une option viable.

Tout ce que je voulais vraiment faire était de simuler l'implémentation via Jest afin qu'il n'essaye pas de créer un vrai contexte. Voici comment je l'ai résolu:

ajouté à 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);
3
Donald White

Pour mon cas d'utilisation, j'ai fait un simple patch de singe comme celui-ci

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

Pas besoin d'installer de toile pré-construite ou sinon.

3
Andzej Maciusovic
npm install -D canvas-prebuilt@1

Cela fournit un support pour canvas for jest.Cela fonctionne même si quelqu'un obtient une erreur en raison de Lottie.js.

1
ankita lal

J'ai réussi à créer un test d'instantané d'image à partir d'une toile en plaisantant avec react-testing-library et jest-image-snapshot. C'est une sorte de mot à la mode, mais cela a bien fonctionné.

Si vous êtes en mesure de configurer correctement vos tests de plaisanterie avec node-canvas (pas jest-canvas-mock ou similaire), vous pouvez littéralement appeler toDataURL sur l'élément canvas.


  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',
    })
  })

J'ai trouvé que je devais utiliser un seuil bas plutôt que de comparer directement l'URL des données image/png car il y avait deux pixels qui étaient juste différents au hasard lors de l'exécution sur travis-CI

Pensez également à mettre à niveau manuellement l'environnement jest jsdom vers jest-environment-jsdom-thirteen ou jest-environment-jsdom-fourteen (les autres réponses de cette page suggèrent des similitudes) et reportez-vous à https://github.com/jsdom/jsdom/issues/1782

0
Colin D

jest-canvas-mock fonctionnera bien.

1) Installez par **npm i --save-dev jest-canvas-mock**

2) Dans votre plaisanterie jest.config.js ajoutez "setupFiles": ["jest-canvas-mock"] attribut. (Si vous avez déjà un attribut setupFiles, vous pouvez également ajouter jest-canvas-mock au tableau, par exemple "setupFiles": ["something-xyz.js", "jest-canvas-mock"]).

Terminé.

0
zernab hussain

Pour tester la sortie du canevas en plaisantant, vous devez procéder comme suit:

Assurez-vous que vous utilisez au moins jsdom 13. Vous pouvez le faire en incluant le package jsom pour jest, pour 14 c'est:

jest-environment-jsdom-fourteen

Et configurer jest pour l'utiliser

jest --env=jest-environment-jsdom-fourteen

ou dans le package.json

"jest": {
   ...
   "testEnvironment": "jest-environment-jsdom-fourteen",

Incluez le package canvas npm. (à partir de la version 2.x, cela inclut la version intégrée, donc la toile pré-construite est déconseillée).

0
Tom