Наряду со стандартной автоматизацией на 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 элемента выглядит следующим образом:
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;
}
}