Как мне протестировать моментальный снимок компонента React с использованием HTML5 canvas?

#react-testing-library #node-canvas #jest-image-snapshot

#react-testing-library #узел-холст #jest-image-snapshot

Вопрос:

Я пытаюсь заставить тестирование моментального снимка изображения работать (т. Е. не издеваться) с компонентом React, который отображает холст HTML5. Я использую Jest, библиотеку тестирования React, Node Canvas, Puppeteer и Jest Image Snapshot.

Учитывая следующий компонент React render() :

   public render(): React.ReactElement<TestCanvas> {
    const { innerWidth, innerHeight } = window;

    return (
      <div id="canvas" style={{ height: `${innerHeight}px`, width: `${innerWidth}px` }}>
        <canvas ref={this.canvasRef} />
      </div>
    );
  }
  

Вот как может выглядеть тест Jest:

   it('should render a <TestCanvas/> component', async () => {
    const { container } = render(<TestCanvas />);

    const page: puppeteer.Page = await browser.newPage();
    await page.setContent(container.outerHTML);
    const image: string = await page.screenshot();

    expect(image).toMatchImageSnapshot();
  });
  

Однако этот тест генерирует пустое белое изображение в формате PNG размером 800×600 в качестве базовой линии.

Однако, если я изменю тест на этот:

   it('should render a <TestCanvas/> component', async () => {
    const { container } = render(<TestCanvas />);

    const canvas: HTMLCanvasElement = container.querySelector('canvas') as HTMLCanvasElement;
    const img = document.createElement('img');
    img.src = canvas.toDataURL();

    const page: puppeteer.Page = await browser.newPage();
    await page.setContent(img.outerHTML);
    const image: string = await page.screenshot();

    expect(image).toMatchImageSnapshot();
  });
  

Он отлично генерирует базовый снимок PNG на основе моего компонента React.

В настоящее время я пытаюсь отладить, где в конвейере что-то идет не так.

Ответ №1:

Я сделал снимок изображения html5 canvas с помощью метода, который не использует puppeteer, но метод puppeteer интересен. Вот метод, который я использовал

   test('canvas image snapshot', async () => {
    const { getByTestId } = render(
      <MyComponent />,
    )

    const canvas = await waitForElement(() =>
      getByTestId('mycanvas'),
    )

    const img = canvas.toDataURL()
    const data = img.replace(/^data:image/w ;base64,/, '')
    const buf = Buffer.from(data, 'base64')
    // may need to do fuzzy image comparison because, at least for me, on
    // travis-ci it was sometimes 2 pixel diff or more for font related stuff
    expect(buf).toMatchImageSnapshot({
      failureThreshold: 0.5,
      failureThresholdType: 'percent',
    })
  })
  

Использует https://github.com/americanexpress/jest-image-snapshot для toMatchImageSnapshot

Комментарии:

1. Да, это в основном то, что мы сделали. Потребовалось некоторое время, чтобы понять, что нам нужно удалить этот мусор кодирования.

Ответ №2:

Ответ от @ Colin выше — это то, что нужно сделать. А именно, удалите кодировку изображения из URL-адреса canvas, потому что [по-видимому] он предназначен для браузера. Вот что мы сделали:

 it('should scroll down', () => {
  const { getByTestId } = render(<PaneDrawerTestWrapper />);

  const mouseHandler = getByTestId(mouseHandlerId);
  act(() => {
    fireEvent.wheel(mouseHandler, { deltaY: 100 });
  });

  const canvas = getByTestId(canvasId) as HTMLCanvasElement;
  const image = stripEncoding(canvas.toDataURL());
  expect(image).toMatchImageSnapshot();
});
  

Где stripEncoding выглядит:

 export function stripEncoding(canvasImageUrl: string): string {
  return canvasImageUrl.replace(/^data:image/(png|jpg);base64,/, '');
}