Как проверить снимок изображения компонента React с помощью холста HTML5?

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

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

  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 800x600 в качестве базового.

Если же я поменяю тест на это:

  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.

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


person icfantv    schedule 04.03.2019    source источник


Ответы (2)


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

  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',
    })
  })
person Colin D    schedule 28.02.2020
comment
Да, в основном это то, что мы сделали. Потребовалось время, чтобы понять, что нам нужно удалить этот кодовый мусор. - person icfantv; 02.03.2020

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

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,/, '');
}
person icfantv    schedule 02.03.2020