WebDriver features: Робота с Canvas тегом при помощи Selenium WebDriver

Наряду со стандартной автоматизацией на Selenium WebDriver, неоднократно сталкиваешься с разными проблемами реализации. Всегда, кажется, что автоматизировать можно не весь функционал, и существуют  какие то ограничения. На форуме рассматриваются множество проблем с модальными окнами, доступам к элементам, разного рода работы с объектами web страниц через Selenium, что еще раз подтверждает  неоднозначность использования той или иной фичи данного средства автоматизации. В зависимости от построения web проекта, который автоматизируется, возникает необходимость написания собственных функций оберток, классов (точек расширения нашего framework-а), разного рода хитростей для выполнения той или иной задачи.  Нередко возникает необходимость использования дополнительных библиотек вместе с WebDriver-ом для достижения результата (напр. Sikuli, Robot, httpclient, итд). Но, как говориться, непреодолимых задач нет, и где-то с сотой попытки, переворачивая код по несколько раз,  наш тест проходит, исполняет все нужные действия и “зеленеет”.Данная стратегия предполагает неплохое знание языка программирования, на котором пишутся тесты, поэтому для большой целевой аудитории ароматизаторов, даже для тех, кто только начинает и пишет через IDE, все примеры будут выложены с детальным описаниям использования и реализации.

В циклах статей "Web Driver features" будут рассматриваться примеры нестандартных ситуаций, которые могут возникнуть при автоматизации на Selenium WebDriver. Наведенная реализация предполагает использование отдельных фич web драйвера, а также использование дополнительных библиотек при работе с отдельным функционалом, который обычно упускают с поля зрения автоматизации.

Web Driver features: Робота с Canvas тегом при помощи Selenium Web Driver

Canvas (англ. canvas — «холст») — элемент HTML 5, который предназначен для создания растрового изображения при помощи JavaScript. На сегодняшний день canvas чаще используется для построения графиков, простой анимации и игр в web-браузерах. Шаблон html кода canvas элемента выглядит следующим образом:  

<html>
<head>
<title>Пример использования</title>
</head>
<body>
<canvas id='canvas_id'>
Этот текст отобразится если браузер не поддерживает html5 элемент canvas.
</canvas>
</body>
</html>

Canvas тэг, обладающий локатором id, может быть изъят самым простым способом:

WebElement canvas = driver.findelement(By.id(“canvas_id”));

Бывает случай, когда div с canvas container-ом включает в себя 2 или больше sibling элемента с тегом canvas, для предотвращения, например, эффекта мерцания, но на web странице мы видим и соответственно управляем только одним явным объектом canvas, например, на котором и происходят манипуляции рисования. Соответственно в таком случае, если точный локатор не известен, используем простой маневр:

Listcanvas= driver().findElements(By.tagName("canvas"));

Нужно только будет “угадать” какой нам элемент массива нужен.

int index=0;
canvas.get(index);

Рисование по canvas элементу вручную предполагает манипуляции с мышкой, если же рисование на canvas-е подразумевает вывод какого- то результата действий, например построения графиков и тд., то оно генерируется с помощью кода, и делать какие- либо проверки нужно только через сопоставление нарисованного или же через javascript execution-ы webdriver-а.

 

2 типа "изобразительного искусства" в автоматизации canvas элемента при помощи selenium webdriver

  •  Манипуляции вручную (если нужно нарисовать что-нибудь на canvas-е):
Actions a = new Actions(driver); //создаем обьект типа Actions для action performing-а
a.build();
a.moveToElement(canvas_WebElement,x1,y1).clickAndHold(canvas_WebElement).moveByOffset(x2,y2)./*...moveByOffset(xn,yn)*/release(canvas_WebElement); // двигаем условный курсор в начальную позицию по координатах и отрезками движемся к другой координате, пока не отпустим action.
a.perform(); //исполнить действие предыдущих манипуляций

Соответственно, если в вашем приложение есть возможность рисовать разного рода фигуры, то перед созданием манипуляций с actions,  нужно установить элемент рисования (кликнуть по нему). При этом в зависимости от функциональной работы графического элемента можно написать различные функции рисования (напр. для прямоугольника, круга итд.).

void drawRectangle(WebDriver driver, WebElement canvas, int x1, int y1, int x2, int y2){
   	Actions a = new Actions(driver);
	a.moveToElement(canvas,x1,y1).clickAndHold(canvas).moveByOffset(x2,y2);
	a.perform();
} //рисует прямоугольник

Здесь нужно быть аккуратным в плане координат, так как можно задавать и отрицательное значение в параметры x,y для направления движения action-а. Поэтому, перед разного рода действиями нужно уяснить для себя размеры вашего объекта canvas, по котором будет что-либо рисоваться и в функцию дописать if-ку, которая будет проверять - попадают ли ваши координат в диапазон размера canvas-a:

int canvasWidth  =  Integer.parseInt(canvas.getAttribute("width"));
int canvasHeight =  Integer.parseInt(canvas.getAttribute("height"));

 

  • Графические объекты на canvas-е, которые генерируются кодом (графики, чарты, итд).

​Нас будет интересовать сама проверка рисунка, так как его прорисовка не зависит от действий с самым элементом. Здесь нужно использовать разные методы, начиная от банальных getAttribute(), getCssValue() итд и заканчивая JavascriptExecutor - все зависит от реализации рисования.

Проверка рисунка через Sikuli:

// все рисунку нужно скриншотить и сохранять с разширением .png
// для начала импортируем библиотеку Sikuli
// import org.sikuli.*   

static public boolean imageExist(String browser, String imageName, int waitTimeout, int similarityPercentage){
double s = similarityPercentage/100;
Settings.MinSimilarity = s; //коефициент соответствия (от 0 до 1), например 60% соответствия равно s = 0.6;
ImageLocator imageLocator = new ImageLocator();
imageLocator.addImagePath(“images/”); // указываем путь где храниться рисунок “эталон”;
Screen screen = new Screen(); //это главный обьект Sikuli - “экран”
Match m = screen.exists(“images/” + imageName + “.png”); //метчер соответсвия
String existanceMessage = m.toString(); // выводим сообщения о состоянии метчера в консоль
try{
App app = new App(browser);
app.focus(); // ставим фокус на окно браузера в котором происходит автоматизация, соотвествено на отдаленном сервере итд работать скорее всего не будет. В переменную browser нужно передавать точное имя бразуера, например “chrome.exe”
screen.wait(“images/” + imageName + “.png”,waitTimeout);
} catch(FindFailed e){
e.printStackTrace();
}
if (getSikuli().exists(“images/” + imageName + “.png”)!=null && m!=null) //конструкция тавтология, но почему то если убрать один из компонентом if-ки - то не работает, если поискать в гугле то можна наткнуться на соотвественную проблему
{
System.out.println(existanceMessage);
return true;
} else {
System.out.println(existanceMessage);
return false;
}
}

А с помощью Python можно как-то это реализовать?

1 лайк