我正在尝试使用React测试库为react-chartjs-2组件设置视觉回归测试。但是,正在生成的所有快照都是空白的,但该组件在浏览器中正确呈现。
这是我目前正在测试的。我基本上将这篇博文 example 与 react-chartjs-2 中的饼图示例结合起来。
import React from 'react';
import {generateImage, debug} from 'jsdom-screenshot';
import {render} from '@testing-library/react';
import {Pie} from "react-chartjs-2";
it('has no visual regressions', async () => {
window.ResizeObserver =
window.ResizeObserver ||
jest.fn().mockImplementation(() => ({
disconnect: jest.fn(),
observe: jest.fn(),
unobserve: jest.fn(),
}));
const data = {
labels: ['Red', 'Blue', 'Yellow', 'Green', 'Purple', 'Orange'],
datasets: [
{
label: '# of Votes',
data: [12, 19, 3, 5, 2, 3],
backgroundColor: [
'rgba(255, 99, 132, 0.2)',
'rgba(54, 162, 235, 0.2)',
'rgba(255, 206, 86, 0.2)',
'rgba(75, 192, 192, 0.2)',
'rgba(153, 102, 255, 0.2)',
'rgba(255, 159, 64, 0.2)',
],
borderColor: [
'rgba(255, 99, 132, 1)',
'rgba(54, 162, 235, 1)',
'rgba(255, 206, 86, 1)',
'rgba(75, 192, 192, 1)',
'rgba(153, 102, 255, 1)',
'rgba(255, 159, 64, 1)',
],
borderWidth: 1,
},
],
};
render(<div><Pie data={data}/></div>)
expect(await generateImage()).toMatchImageSnapshot();
});
我想知道这是否是一个时间问题。在期望之前运行
debug()
显示宽度和高度为 0 的画布:
<canvas
height="0"
role="img"
style="display: block; box-sizing: border-box; height: 0px; width: 0px;"
width="0"
/>
您正在使用的图表库
react-chartjs-2
包装了 chart.js
,它依赖于 canvas
元素将图表渲染到屏幕上。需要注意的是,画布内容不是 DOM 的一部分,而是虚拟地呈现在单个 DOM canvas
元素之上。
记住这一点,看看
jsdom-screenshot
如何渲染图像(来自方法的解释):
我们使用jsdom来获取我们想要截图的HTML的状态。消费者可以使用 jsdom 轻松使组件进入他们想要截图的状态。然后 jsdom-screenshot 使用当时(该状态)的标记(“HTML”)。 jsdom-screenshot 启动本地网络服务器并将获得的标记作为index.html 提供。它还进一步服务通过serve提供的资产,以便加载本地资产。然后 jsdom-screenshot 使用 puppeteer 进行屏幕截图,使用无头 Google Chrome 对该页面进行屏幕截图。
当您调用
generateImage()
时,您发布的 HTML(只是一个空的 canvas
元素)将被复制到在 Puppeteer 中打开的文件 index.html
中,然后进行屏幕截图。由于 canvas
元素不将其内容包含在其标记中,因此当将 HTML 复制到文件中时,图表将丢失。
简而言之,
jsdom-screenshot
不支持在canvas
元素上绘图。
我建议查看 jest-puppeteer,它在 Puppeteer 中运行整个测试套件。它将使用实际的 Chromium DOM 实现,而不是使用虚拟化 DOM 实现,这具有更接近运行时使用的功能的额外好处。您可以使用
jsdom
截取与浏览器中显示的图表完全相同的屏幕截图,并具有完整的 DOM 支持(包括
page.screenshot()
)。查看 canvas
自述文件以开始使用。jest-puppeteer
,您不需要模拟组件或模拟画布渲染。 您可以对反应组件进行可视化回归测试。 我正在使用:
react-chartjs-2
在我的
chart.js v4.4.0
react-chartjs-2 v5.2.0
jsdom v19.0.0
jsdom-screenshot v4.0.0
jest v27.4.3
jest-image-snapshot v5.2.0
@jest/globals v27.4.2
@testing-library/jest-dom v5.16.0
@testing-library/react v12.1.2
中我有:
jest.config.js
在我的
testEnvironment: 'jsdom',
setupFilesAfterEnv: [
'<rootDir>/jest.setup.afterEnv.js',
],
中我有:
jest.setup.afterEnv.js
通过上面的设置,我可以从通用
import { expect } from '@jest/globals';
import { configureToMatchImageSnapshot } from 'jest-image-snapshot';
const toMatchImageSnapshot = configureToMatchImageSnapshot({
failureThresholdType: 'pixel',
customSnapshotsDir: `${__dirname}/test/snapshots/`,
});
// extend Jest expect
expect.extend({ toMatchImageSnapshot });
组件的玩笑测试中获取图像。
<Canvas />
将其扩展到
const getCanvasSnapshot = (canvas: HTMLCanvasElement, failureThreshold = 0) => {
const image = canvas.toDataURL();
const data = image.replace(/^data:image\/\w+;base64,/, '');
const snapshot = Buffer.from(data, 'base64');
expect(snapshot).toMatchImageSnapshot({ failureThreshold });
};
describe('<Canvas />', () => {
test('render into canvas', () => {
// @see https://medium.com/@pdx.lucasm/canvas-with-react-js-32e133c05258
const Canvas = (props: any) => {
const { draw, ...rest } = props;
const canvasRef = React.useRef(null);
React.useEffect(() => {
const canvas = canvasRef.current as unknown as HTMLCanvasElement;
const context = canvas.getContext('2d');
draw(context);
}, [draw]);
return <canvas ref={canvasRef} {...rest} />;
};
const App = () => {
const draw = (ctx: CanvasRenderingContext2D) => {
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.fillStyle = '#0000ff';
ctx.beginPath();
ctx.arc(50, 50, 5, 0, 2 * Math.PI);
ctx.fill();
};
return <Canvas draw={draw} width={100} height={100} />;
};
const { container } = render(<App />);
const canvas = container.querySelector('canvas') as HTMLCanvasElement;
getCanvasSnapshot(canvas);
});
});
就很简单了。我遇到的几个问题。 在浏览器模式下,图表可以从父容器获取其大小,但是当 jest 运行时,图表无法获取大小。 所以我必须设置
react-chartjs-2
options.responsive = false; // only when jest is running
的设置对于我的应用程序来说是不变的。
然后我必须直接在图表组件上设置宽度和高度options.maintainAspectRatio
然后 jest/jsdom 测试将生成一个图像。请注意,
return (
<Chart
{...(isJestRunning() ? { width: '198' } : {})}
{...(isJestRunning() ? { height: '202' } : {})}
type="scatter"
data={data as ChartData}
options={options as ChartOptions}
plugins={plugins}
/>
);
只是
<Plot />
的简单包装。<Chart />
希望这有帮助。