如何设置react-chartjs-2组件的视觉回归

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

我正在尝试使用React测试库为react-chartjs-2组件设置视觉回归测试。但是,正在生成的所有快照都是空白的,但该组件在浏览器中正确呈现。

这是我目前正在测试的。我基本上将这篇博文 examplereact-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"
/>
jestjs react-testing-library jsdom react-chartjs
2个回答
3
投票

您正在使用的图表库

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
自述文件以开始使用。
    


0
投票
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 />

希望这有帮助。

© www.soinside.com 2019 - 2024. All rights reserved.