我正在尝试为此沙箱中找到的示例创建一个玩笑测试: 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>
</>
)
}
这不是一个答案,但我发现这篇文章很有用: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/ 给出了另一种解释。
解决方案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 '';
}