Работа с графиками и SVG

Protractor является мощным инструментом для автоматизированного тестирования веб-приложений на основе Angular и AngularJS, но его возможности не ограничиваются исключительно Angular-специфическими элементами. Одной из сложных задач при автоматизации является работа с графиками и SVG-элементами, так как они часто не используют стандартные HTML-формы и кнопки, а формируются динамически через <svg> и дочерние элементы <path>, <circle>, <rect>, <line> и другие.

Особенности работы с SVG

SVG-элементы имеют несколько особенностей, которые важно учитывать при автоматизации:

  1. Отсутствие стандартных атрибутов формы. Элементы графиков не имеют value или innerText, привычных для обычных HTML-элементов.
  2. Наследование координат и трансформаций. Позиция элементов в SVG может задаваться через атрибуты x, y, cx, cy, transform.
  3. Динамическое построение. Многие библиотеки (Chart.js, D3.js, Highcharts) создают элементы графиков на лету, что требует ожидания их появления в DOM перед взаимодействием.

Поиск SVG-элементов

Для взаимодействия с SVG в Protractor используют CSS-селекторы или XPath. Примеры:

// Поиск всех кругов в SVG
let circles = element.all(by.css('svg circle'));

// Поиск линии с определенным атрибутом
let line = element(by.css('svg line[stroke="#ff0000"]'));

// Использование XPath для сложных графиков
let specificPoint = element(by.xpath('//svg//*[name()="circle" and @data-value="50"]'));

Важно помнить, что для XPath необходимо использовать name() для выбора SVG-элементов, так как стандартный //circle может не работать из-за пространства имён SVG.

Взаимодействие с элементами графиков

Так как SVG-элементы часто визуальны, взаимодействие с ними требует симуляции кликов по координатам или использования WebElement методов:

let point = element(by.css('svg circle:nth-child(3)'));

// Получение координат точки
point.getLocation().then(location => {
    browser.actions().mouseMove({x: location.x, y: location.y}).click().perform();
});

Для графиков с динамическими подписями и tooltip важно дождаться появления элементов перед взаимодействием:

let tooltip = element(by.css('.chart-tooltip'));
let thirdBar = element(by.css('svg rect:nth-child(3)'));

browser.wait(ExpectedConditions.visibilityOf(thirdBar), 5000);
browser.actions().mouseMove(thirdBar).perform();
browser.wait(ExpectedConditions.visibilityOf(tooltip), 3000);

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

SVG-графики часто содержат визуальные данные, которые не доступны через innerText. Для проверки значений используют атрибуты элементов:

let bar = element(by.css('svg rect:nth-child(2)'));
bar.getAttribute('height').then(height => {
    expect(parseInt(height)).toBeGreaterThan(0);
});

bar.getAttribute('fill').then(color => {
    expect(color).toBe('#00ff00');
});

Для сложных графиков с D3.js можно проверять data-* атрибуты, которые хранят значения, используемые при построении графика:

let dataPoint = element(by.css('svg circle[data-value="75"]'));
expect(dataPoint.isPresent()).toBeTruthy();

Работа с библиотеками визуализации

Chart.js: Элементы создаются внутри <canvas>, поэтому прямого доступа к DOM нет. Здесь применяется API библиотеки через Jav * aScript:

browser.executeScript(() => {
    return Chart.instances[0].data.datasets[0].data[2];
}).then(value => {
    expect(value).toBe(50);
});

D3.js и Highcharts: Используют SVG, поэтому прямой доступ через Protractor возможен через CSS и XPath. Можно комбинировать:

let chartPoint = element(by.css('svg g.highcharts-point:nth-child(4)'));
chartPoint.getAttribute('fill').then(color => {
    expect(color).toBe('#7cb5ec');
});

Использование ExpectedConditions

Из-за динамической природы графиков крайне важно использовать ожидания перед проверкой или взаимодействием с элементами:

let chart = element(by.css('svg'));
browser.wait(ExpectedConditions.presenceOf(chart), 5000);

let point = chart.element(by.css('circle:nth-child(1)'));
browser.wait(ExpectedConditions.elementToBeClickable(point), 3000);

Скроллинг и видимость

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

let point = element(by.css('svg circle:nth-child(5)'));
browser.executeScript('arguments[0].scrollIntoView(true);', point.getWebElement());
browser.actions().mouseMove(point).click().perform();

Советы по надежной автоматизации

  • Всегда использовать element.all для коллекций SVG-элементов, чтобы избежать ошибок при динамическом рендеринге.
  • Применять getAttribute() для проверки данных, а не getText().
  • Использовать browser.executeScript() для сложных проверок через JavaScript API графиков.
  • Оборачивать взаимодействия в ExpectedConditions для стабильности тестов.

Работа с графиками и SVG в Protractor требует сочетания тщательного выбора селекторов, ожиданий и использования координат клика, что обеспечивает стабильность и точность тестирования динамических визуализаций.