Проверка содержимого canvas

В современных веб-приложениях элементы <canvas> часто используются для динамической визуализации, графиков, игр или сложной анимации. Тестирование таких элементов требует особого подхода, так как их содержимое нельзя проверить обычными методами, применяемыми к DOM-элементам. Cypress предоставляет инструменты для работы с canvas через прямой доступ к его API.


Получение контекста canvas

Первый шаг — это доступ к объекту canvas и его контексту:

cy.get('canvas#myCanvas')
  .then($canvas => {
    const canvas = $canvas[0];
    const ctx = canvas.getContext('2d');
    // ctx теперь позволяет читать пиксели или проверять отрисовку
  });
  • $canvas[0] возвращает реальный DOM-элемент.
  • getContext('2d') предоставляет интерфейс для работы с пикселями и графикой.

Проверка пиксельного содержимого

Canvas хранит изображение в виде массива пикселей. Для проверки конкретного цвета в точке используется метод getImageData:

cy.get('canvas#myCanvas')
  .then($canvas => {
    const ctx = $canvas[0].getContext('2d');
    const imageData = ctx.getImageData(50, 50, 1, 1); // проверка пикселя (50,50)
    const [r, g, b, a] = imageData.data;

    expect(r).to.eq(255);
    expect(g).to.eq(0);
    expect(b).to.eq(0);
    expect(a).to.eq(255);
  });
  • Параметры getImageData(x, y, width, height) позволяют выбрать область для проверки.
  • Массив data содержит значения RGBA для каждого пикселя.
  • Такой подход подходит для точечной проверки отрисовки.

Сравнение содержимого с эталонным изображением

Для сложных случаев, когда canvas рисует сложные графики, проще сравнивать его с эталонным изображением:

cy.get('canvas#myCanvas')
  .then($canvas => {
    const canvas = $canvas[0];
    const currentData = canvas.toDataURL();

    cy.fixture('expectedCanvas.png', 'base64').then(expectedData => {
      expect(currentData.split(',')[1]).to.eq(expectedData);
    });
  });
  • toDataURL() возвращает изображение в формате Base64.
  • Используется для сверки полной картинки, а не отдельных пикселей.
  • Такой метод удобен для регрессионного тестирования визуальных элементов.

Валидация отрисовки после взаимодействий

Canvas часто изменяется после действий пользователя. Cypress позволяет проверять изменения после событий:

cy.get('button#drawCircle').click();
cy.get('canvas#myCanvas')
  .then($canvas => {
    const ctx = $canvas[0].getContext('2d');
    const pixel = ctx.getImageData(100, 100, 1, 1).data;
    expect(pixel[0]).to.eq(0); // красный
  });
  • Клик по кнопке инициирует отрисовку.
  • Проверка конкретного пикселя позволяет убедиться, что графика обновилась корректно.

Проверка с помощью сторонних библиотек

Иногда для сложной визуализации используют библиотеку pixelmatch для точного сравнения изображений:

import pixelmatch from 'pixelmatch';
import { PNG } from 'pngjs';

cy.get('canvas#myCanvas')
  .then($canvas => {
    const canvas = $canvas[0];
    const imgData = PNG.sync.read(Buffer.from(canvas.toDataURL().split(',')[1], 'base64'));
    
    cy.fixture('expectedCanvas.png', 'base64').then(expectedBase64 => {
      const expectedData = PNG.sync.read(Buffer.from(expectedBase64, 'base64'));
      const diff = new PNG({width: imgData.width, height: imgData.height});
      const numDiffPixels = pixelmatch(imgData.data, expectedData.data, diff.data, imgData.width, imgData.height, {threshold: 0.1});
      
      expect(numDiffPixels).to.eq(0);
    });
  });
  • Позволяет выявить малейшие расхождения.
  • Threshold регулирует чувствительность сравнения.
  • Подходит для графиков, диаграмм и игр с точной визуализацией.

Полезные советы при тестировании canvas

  • Тестировать отдельные пиксели удобно для простых элементов, но для сложной графики лучше использовать сравнение с эталоном.
  • Асинхронные операции: перед проверкой убедиться, что все отрисовки завершены (например, через cy.wait() или колбэки рендера).
  • Размер canvas: убедиться, что canvas имеет фиксированные размеры, иначе сравнение с эталонным изображением будет некорректным.
  • Высокое разрешение: при использовании retina-дисплеев учитывать devicePixelRatio, так как canvas может масштабироваться.

Работа с <canvas> в Cypress требует прямого доступа к пикселям или генерации изображений, что делает проверку более точной и детализированной по сравнению с обычным DOM-тестированием. Эти методы позволяют создавать надежные автоматические тесты для любых визуальных компонентов.