使用 Jest 的 canvas 元素的简单测试示例

问题描述 投票:0回答:2

我正在尝试为此沙箱中找到的示例创建一个玩笑测试: https://codesandbox.io/s/r3f-basic-demo-forked-297k3?file=/src/App.js

基本上我想测试每个盒子上的 onClick 功能。我已经发现笑话测试不能在真正的浏览器中运行。 Jest 使用 jsdom 来模拟 DOM 的必要部分。因此,我可能需要 jsdom 的画布支持,但我不太确定到底该怎么做。

App.js

import React, { useRef, useState } from 'react'
import { Canvas, useFrame } from 'react-three-fiber'

function Box(props) {
  // This reference will give us direct access to the mesh
  const mesh = useRef()
  // Set up state for the hovered and active state
  const [hovered, setHover] = useState(false)
  const [active, setActive] = useState(false)
  // Rotate mesh every frame, this is outside of React without overhead
  useFrame(() => {
    mesh.current.rotation.x = mesh.current.rotation.y += 0.01
  })
  return (
    <mesh
      {...props}
      ref={mesh}
      scale={active ? [1.5, 1.5, 1.5] : [1, 1, 1]}
      onClick={(e) => setActive(!active)}
      onPointerOver={(e) => setHover(true)}
      onPointerOut={(e) => setHover(false)}>
      <boxBufferGeometry args={[1, 1, 1]} />
      <meshStandardMaterial color={hovered ? 'hotpink' : 'orange'} />
    </mesh>
  )
}

export const App = () => {
  return (
    <>
      <Canvas>
        <ambientLight intensity={0.5} />
        <spotLight position={[10, 10, 10]} angle={0.15} penumbra={1} />
        <pointLight position={[-10, -10, -10]} />
        <Box position={[-1.2, 0, 0]} />
        <Box position={[1.2, 0, 0]} />
      </Canvas>
    </>
  )
}
reactjs testing jestjs html5-canvas react-three-fiber
2个回答
0
投票

这不是一个答案,但我发现这篇文章很有用:https://www.valentinog.com/blog/canvas/

建议正确测试

canvas
元素,不应使用 Jest(或任何单元测试),而应使用某种 e2e 测试,以便它可以实际渲染
canvas

我能够通过以下方式进行一些较小的测试:

首先使用 jest 正常渲染页面。您可以为您的画布提供一个测试 ID,或者(如我的情况)在您的画布周围放置一个 div,并为该 div 提供一个测试 ID。

我最终得到以下结果:

let canvasContainer = getByTestId("canvas-container");
let canvas = canvasContainer.getElementsByTagName("canvas")[0];
let canvasContext = canvas.getContext("2d");

无论哪种情况,您的目标都是获取

canvas
' 元素上下文。

从那里您可以使用

canvasContext.__getDrawCalls()

检查它

这将为您提供有关迄今为止已完成的所有“

drawCalls
”的一些信息(例如绘制线条或矩形或您拥有的东西)。

需要对

__getDrawCalls
进行一些检查,但您应该会发现到目前为止的每个调用都已包含在内。

我写了一些函数来帮助我获得我想要的确切细节:

const getLineInfo = (lineInfo) => {
    if (lineInfo.type !== "stroke") {
        return "not a line";
    }

    let lineInfoDetail = lineInfo.props.path[3];

    return {
        lineStart: {
            x: lineInfoDetail.transform[4],
            y: lineInfoDetail.transform[5],
        },
        lineEnd: {
            x: lineInfoDetail.transform[4] + lineInfoDetail.props.x,
            y: lineInfoDetail.transform[5] + lineInfoDetail.props.y,
        },
    };
};

const getRectInfo = (rectInfo) => {
    if (rectInfo.type !== "fill") {
        return "not a rect";
    }

    let rectInfoDetail = rectInfo.props.path[1];

    return {
        rectStart: {
            x: rectInfoDetail.transform[4],
            y: rectInfoDetail.transform[5],
        },
        rectEnd: {
            x: rectInfoDetail.transform[4] + rectInfoDetail.props.width,
            y: rectInfoDetail.transform[5] + rectInfoDetail.props.height,
        },
    };
};

例如,如果我知道第二次绘制是一条线,我可以执行以下操作:

    expect(getLineInfo(canvasContext.__getDrawCalls()[1])).toStrictEqual({
        lineStart: { x: 150, y: 250 },
        lineEnd: { x: 150, y: 350 },
    });

这是测试该元素是否是一条起点为

{ x: 150, y: 250 }
和终点为
{ x: 150, y: 350 }

的线

这样做的问题是你无法在jest中触发canvas元素的点击和拖动事件,因此使用jest来测试canvas似乎非常有限。

编辑: 看起来 https://yonatankra.com/how-to-test-html5-canvas-with-jest/ 给出了另一种解释。


0
投票

解决方案1

安装

yarn add --dev jest-canvas-mock

npm i --save-dev jest-canvas-mock

然后只需在测试文件中导入 jest-canvas-mock

import 'jest-canvas-mock';

解决方案2

如果您无法按照常见方法安装该库。

以这种方式尝试模拟画布

window.HTMLCanvasElement.prototype.getContext = function () {
    return {
        fillRect() {},
        clearRect() {},
        getImageData(x, y, w, h) {
            return {
                data: new Array(w * h * 4)
            };
        },
        putImageData() {},
        createImageData() { return [] },
        setTransform() {},
        drawImage() {},
        save() {},
        fillText() {},
        restore() {},
        beginPath() {},
        moveTo() {},
        lineTo() {},
        closePath() {},
        stroke() {},
        translate() {},
        scale() {},
        rotate() {},
        arc() {},
        fill() {},
        measureText() {
            return { width: 0 };
        },
        transform() {},
        rect() {},
        clip() {}
    };
}

window.HTMLCanvasElement.prototype.toDataURL = function () {
    return '';
}
© www.soinside.com 2019 - 2024. All rights reserved.