Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Doesn't work with latest Create React App #72

Open
ztolley opened this issue Nov 27, 2020 · 17 comments
Open

Doesn't work with latest Create React App #72

ztolley opened this issue Nov 27, 2020 · 17 comments

Comments

@ztolley
Copy link

ztolley commented Nov 27, 2020

Steps to reproduce:

  1. npx create-react-app myapp --template typescript

  2. cd myapp

  3. npm install jest-canvas-mock

4: Edit App.test.tsx and add the following test

import "jest-canvas-mock";

test("Canvas support works with context", () => {
  const canvas: HTMLCanvasElement = document.createElement("canvas");
  const context = canvas.getContext("2d");

  expect(context).not.toBeUndefined();
});
  1. Run npm run test

The test should be able to create a canvas context but it comes back undefined

@albert-schilling
Copy link

albert-schilling commented Nov 30, 2020

Same here. It worked with "react-scripts": "^3.4.4" but not with "react-scripts": "4.0.0". Probably due to the different Jest version used by the CRA 4? In your tests, according to your package.json, you use "jest": "^25.3.0". CRA 4 uses Jest 26. It would be very much appreciated if you could upgrade to Jest 26 / CRA 4. Thank you!

@albert-schilling
Copy link

albert-schilling commented Nov 30, 2020

Update: As far as I can tell, Jest / jsdom can handle canvas elements if the library node canvas is installed as a peer dependency.
https://github.com/jsdom/jsdom#canvas-support
https://www.npmjs.com/package/canvas
Thus, making this library obsolete, at least for testing purposes?

@ztolley
Copy link
Author

ztolley commented Dec 14, 2020

My restriction is I cannot do this, hence using this package

@mregula
Copy link

mregula commented Jan 11, 2021

@albert-schilling Do you have any resource how to make it working?
What I did:

  1. Added peerDependencies to my package.json
    "peerDependencies": { "canvas": "^2.6.1" }

  2. npm install
    but no success...

Thanks!

@albert-schilling
Copy link

@mregula
I think it suffices if you install canvas as a regular package. npm i --save-dev canvas
At least, this is all we did.
I guess JSDOM tries to import canvas from your node_modules folder and uses the library if it can import it.

@mregula
Copy link

mregula commented Jan 12, 2021

Thanks @albert-schilling !

What I did: npm install --save-dev canvas. If your component draws on canvas and uses img.onload to put the data into canvas, you need to mock also Image object in your jest test file:

import { Image } from "canvas";
beforeAll(() => {
  (global as any).Image = Image;
});

@VittorioAccomazzi
Copy link

I'm running in to the same problem here. I follow the steps outlines above by @ztolley and I also update the file setupTests.ts as suggested here adding the line import 'jest-canvas-mock' but the result doesn't change, the test still fails.

Afterwards I follow the suggestion of @albert-schilling installing node canvas and the test passed !, jsdom indeed was able to instantiate a canvas object.

However it is my understanding that node canvas is less portable then jest-canvas-mock because it relies on Cairo v1.10.0 libraries, and so using jest-canvas-mock would make the code more easily portable.

@nicolas-chaulet
Copy link

nicolas-chaulet commented Feb 12, 2021

Hey! Following up on that, the node canvas library indeed fixes the issue but I am not sure that would work when the test cannot control the creation of the canvas directly. For example if the canvas creation is happening inside a React component. How would you go about that?

For example:

test('test canvas', () => {
  render(<canvas data-testid="canvas" />);
  let canvas = screen.getByTestId("canvas")
  expect(canvas.getContext("2d")).not.toBeUndefined()

});

@nicolas-chaulet
Copy link

nicolas-chaulet commented Feb 12, 2021

Actually, the solution is to remove all dependencies to jest-canvas-dom and install canvas instead, that's it. Node takes care of the rest. The test above works just fine after that change.

@marlonmleite
Copy link

Actually, the solution is to remove all dependencies to jest-canvas-dom and install canvas instead, that's it. Node takes care of the rest. The test above works just fine after that change.

The lib canvas is quite limited, it doesn't support Video element as an argument and many other things. Any suggestion for use this in lasted CRA?

@heisenbugged
Copy link

I'm having this same problem. While using canvas works, it is not a good solution if you need to actually assert on your canvas, as you don't get any spy/mock functionality if you use the canvas library.

@kolorobot
Copy link

kolorobot commented Nov 26, 2021

jest-canvas-mock does not work with CRA 4 (react-scripts@4.0.3) - I tried this with freshly started project and it fails to work. On the other hand, with Parcel it works like a charm (tested with https://github.com/kolorobot/parcel-starters/tree/master/parcel-react-typescript-starter)

Using canvas is not an option for me neither.

  • Are there any plans to fix this?
  • Is there any solution that could work with CRA?

ngxingyu added a commit to source-academy/frontend that referenced this issue Dec 30, 2021
- Changed konva import path
- Fix target type for setHoveredStyle from Node to Node | Group
- Fix imports
- Some issue with jest-canvas-mock (hustcc/jest-canvas-mock#72) so replaced it with canvas
chownces added a commit to source-academy/frontend that referenced this issue Jan 5, 2022
* Bump konva from 7.2.5 to 8.2.3

Bumps [konva](https://github.com/konvajs/konva) from 7.2.5 to 8.2.3.
- [Release notes](https://github.com/konvajs/konva/releases)
- [Changelog](https://github.com/konvajs/konva/blob/master/CHANGELOG.md)
- [Commits](konvajs/konva@7.2.5...8.2.3)

---
updated-dependencies:
- dependency-name: konva
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* - Removed konva-node since "merged into konva" in 8.0.0
- Changed konva import path
- Fix target type for setHoveredStyle from Node to Node | Group
- Fix imports
- Some issue with jest-canvas-mock (hustcc/jest-canvas-mock#72) so replaced it with canvas

* added missing Group type

* Upgrade konva to latest version

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Martin Henz <henz@comp.nus.edu.sg>
Co-authored-by: En Rong <53928333+chownces@users.noreply.github.com>
@ggayowsky
Copy link

ggayowsky commented Jan 26, 2022

Let me look into this, but I believe that this package doesn't work with the latest react-create-app is because of the fact that the jest configuration file has resetMocks to true.

I was testing against a file that had

beforeEach(() => {
  jest.resetAllMocks();
})

which is functionally equivalent to having resetMocks set to true. So try flipping the resetMocks flag in the jest configuration file to false and the library should work.

@kolorobot
Copy link

kolorobot commented Jan 26, 2022

  • I created new CRA (5.0.0) app
  • I added the following configuration to package.json:
 "jest": {
    "resetMocks": false
  }

Now the tests do not fail anymore.

Source code of my dummy component:

// @ts-nocheck
import * as React from 'react';
import { createRef, Ref, useState } from 'react';

type CanvasProps = {
    onUpdate?: (dataURL: string) => void,
}

const Canvas: React.FC<CanvasProps> = ({ onUpdate }) => {
    const canvasRef: Ref<HTMLCanvasElement> = createRef();

    const draw = () => {
        // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Drawing_shapes
        const canvas = canvasRef.current;

        const ctx = canvas.getContext('2d');

        ctx.beginPath();
        ctx.arc(75, 75, 50, 0, Math.PI * 2, true);
        ctx.moveTo(110, 75);
        ctx.arc(75, 75, 35, 0, Math.PI, false);
        ctx.moveTo(65, 65);
        ctx.arc(60, 65, 5, 0, Math.PI * 2, true);
        ctx.moveTo(95, 65);
        ctx.arc(90, 65, 5, 0, Math.PI * 2, true);
        ctx.stroke();
        onUpdate && onUpdate(canvas.toDataURL());
    };

    const clear = () => {
        const canvas = canvasRef.current;
        const ctx = canvas.getContext('2d');
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        onUpdate && onUpdate(canvas.toDataURL());
    };

    return (
        <>
            <div>
                <button onClick={draw}>Draw</button>
                <button onClick={clear}>Clear</button>
            </div>
            <div>
                <canvas data-testid='canvas' ref={canvasRef} width={150} height={150}
                        style={{ border: '1px solid #000' }} />
            </div>
        </>
    );
};

export default Canvas;

And the test:

// @ts-nocheck
import * as React from 'react';
import 'jest-canvas-mock';
import Canvas from './Canvas';
import { getByTestId, getByText, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

describe('Canvas', () => {

    it('renders empty canvas', async () => {
        const { container } = render(<Canvas />);
        expect(container).toMatchSnapshot();
    });

    it('renders canvas element', async () => {
        const { container } = render(<Canvas />);

        userEvent.click(getByText(container, 'Draw'));
        expect(container).toMatchSnapshot();
    });

    it('validates canvas state after draw was clicked', () => {
        const { container } = render(<Canvas />);

        userEvent.click(getByText(container, 'Draw'));

        const canvas: HTMLCanvasElement = getByTestId(container, 'canvas');
        const ctx = canvas.getContext('2d');

        const events = ctx.__getEvents();

        expect(events).toMatchSnapshot();
    });

    it('gets updated with `dataURL` on draw', () => {
        const callback = jest.fn();
        const { container } = render(<Canvas onUpdate={callback} />);

        userEvent.click(getByText(container, 'Draw'));

        expect(callback).toBeCalledWith('data:image/png;base64,00');
    });
});

So, @ggayowsky you were right as it goes to the workaround.

@wowry
Copy link

wowry commented Feb 5, 2022

Same here, but import "jest-canvas-mock"; and "resetMocks": false solved my error. Thank you very much :)

@nicks
Copy link
Contributor

nicks commented Aug 1, 2022

would the maintainers accept a PR to expose mockWindow https://github.com/hustcc/jest-canvas-mock/blob/master/src/index.js#L6, so that my test can setup the mock itself?

I'm working in a codebase where lots of existing tests use resetAllMocks, which breaks this library.

@nicks
Copy link
Contributor

nicks commented Aug 3, 2022

I was able to workaround this by yarn patch-ing #98 into my project.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests