В процессе написания автоматических тестов иногда приходится проверять видимость/отображение изображения на сайте: главная картинка страницы, блока и т.д. Однако простая проверка методом «Displayed» нам не поможет, а точнее она проверяет не совсем то, что нам нужно. Давайте всё рассмотрим на примерах.
Предварительно сообщу о используемом стеке: Selenium WebDriver + C# + NUnit
Есть у нас следующий код:
<div class="img-div"> <img itemprop="image" data-data-src="//victorz.ru/primer.png" class="img-primer"> </div>
Для проверки отображения элемента мы обычно пишем следующий код:
driver.FindElement(By.CssSelector("img.img-primer")).Displayed;
Далее это используется нами в условии if-else или в специальных методах, написанных нами.
Однако данный код на самом деле проверяет не отображение самого изображения на сайте, а видимость «img» и оно будет истинно, даже если само изображение не подгрузилось на сайте. С этой проблемой столкнулся и я. Далее была начата работа по исследованию этой проблемы. И в процессе изучения выяснилось, что для точной проверки придётся использовать дополнительно JavaScript. И сейчас я постараюсь подробно разобрать данный момент.
С помощью JavaScript мы можем получать ширину или высоту изображения, которое подгружается на сайт. Мы будем работать с шириной, так как одной величины нам будет достаточно. Если изображение не подгрузилось на сайт, то его ширина = 0, как и высота. Если изображение подгрузилось, то его ширина > 0. В JavaScript есть метод naturalWidth с помощью которого получаем натуральную ширину изображения. Отталкиваясь от сказанного ранее мы и будем строить свой метод проверки отображения изображения на сайте. Привожу готовый метод проверки, чтобы далее разобрать его. В качестве примера с изображением возьмём следующий HTML код:
<div class="img-div1"> <img itemprop="image" data-data-src="//victorz.ru/primer1.png" class="img-primer1"> </div> <div id="img-div2"> <img itemprop="image" data-data-src="//victorz.ru/primer2.png" id="img-primer2"> </div>
Метод проверки с пояснениями в коде:
/// <summary> /// Метод проверяет отображается или нет изображение на странице. Возвращает true/false /// </summary> /// <param name="iClass">В данной переменной сообщаем, как в JavaScript обращаться к элементу: id - getElementById, class - getElementsByClassName</param> /// <param name="iElement">В данной переменной передаётся значение id или класса элемента, если id="idel", то передаём "idel"</param> /// <param name="iImdChild">Если данный параметр <c>true</c>, то это означает, что тег img вложен в другой тег, чей класс мы указываем в iClass</param> public static bool isImgVisible(string iClass, string iElement, bool iImdChild) { IJavaScriptExecutor js = driver as IJavaScriptExecutor; // объявляем переменную для работы с JavaScript bool isImg = false; // переменная значение которой возвращает метод int imageWidth = 0; // переменная ширины изображения, сразу присваиваем 0 if (iClass == "id" & iImdChild == false) // проверяем, когда обращаемся к id самого изображения (id тега img) { imageWidth = int.Parse(js.ExecuteScript("return document.getElementById('" + iElement + "').naturalWidth;").ToString()); } if (iClass == "id" & iImdChild == true) // проверяем, когда обращаемся к id произвольного тега, в который вложен тег img { imageWidth = int.Parse(js.ExecuteScript("return document.getElementById('" + iElement + "').getElementsByTagName('img')[0].naturalWidth;").ToString()); } if (iClass == "class" & iImdChild == false) // проверяем, когда обращаемся к class самого изображения (class тега img) { imageWidth = int.Parse(js.ExecuteScript("return document.getElementsByClassName('" + iElement + "')[0].naturalWidth;").ToString()); } if (iClass == "class" & iImdChild == true) // проверяем, когда обращаемся к class произвольного тега, в который вложен тег img { imageWidth = int.Parse(js.ExecuteScript("return document.getElementsByClassName('" + iElement + "')[0].getElementsByTagName('img')[0].naturalWidth;").ToString()); } if (imageWidth != 0) // если ширина изображения не равна 0 (значит изображение отображается) { isImg = true; } return isImg; }
Теперь рассмотрим, как можно использовать метод проверяя изображение различными способами. Вызом метода прост:
isImgVisible("class", " img-primer1", false);
Пример 1 (попадает под if строки 16 метода):
if (isImgVisible("class", " img-primer1", false) == false) { throw new Exception("Фото primer1.png не отображается"); }
Пример 2 (попадает под if строки 12 метода):
if (isImgVisible("id", " img-primer2", false) == false) { throw new Exception("Фото primer2.png не отображается"); }
Пример 3 (попадает под if строки 18 метода):
if (isImgVisible("class", " img-div1", true) == false) { throw new Exception("Фото primer1.png не отображается"); }
Пример 4 (попадает под if строки 14 метода):
if (isImgVisible("id", " img-div2", true) == false) { throw new Exception("Фото primer2.png не отображается"); }
Пояснение к примерам 3-4: Хочу обратить внимание, что если вы хотите проверить второе или третье вложенное в любой тег изображение, то придётся дорабатывать метод, так как текущий метод ищет первое изображение (getElementsByTagName(‘img’)[0]).
Во всех примерах я вызываю принудительно ошибку при отсутствии изображения (throw new Exception), которая попадёт в отчёт. Вы можете делать что угодно на своё усмотрение.
Конечно же метод можно доработать и в него передавать строку кода JavaScript для проверки, чтобы эта строка не была жёстко зашита в сам метод. Давайте рассмотрим пример такого метода:
public static bool isImgVisible2(string iJavaScript) { IJavaScriptExecutor js = driver as IJavaScriptExecutor; bool isImg = false; int imageWidth = 0; imageWidth = int.Parse(js.ExecuteScript("return " + iJavaScript).ToString()); if (imageWidth != 0) { isImg = true; } return isImg; }
В этом случае в метод будем передавать JavaScript. Этот метод хорош тем, что он универсален и проверять можем любое изображение и с любой вложенностью. Минус – должны быть познания в JavaScript, чтобы правильно составлять код передаваемой в метод строки. Пример использования:
<div class="img-div1"> <span> <!-- span с индексом 0 --> </span> <span> <!-- span с индексом 1 --> <img data-src="//victorz.ru/primer1.png" /> <!-- img индексом 0 --> <img data-src="//victorz.ru/primer2.png" /> <!-- img индексом 1 --> </span> </div>
if (isImgVisible2("document.getElementsByClassName('img-div1')[0].getElementsByTagName('span')[1].getElementsByTagName('img')[1].naturalWidth;") == false) { throw new Exception("Фото primer2.png не отображается"); }
Как видим метод проверки можно модифицировать под свои нужды, как угодно.
У меня к проекту подключено следующее (возможно для вас что-то лишнее будет):
using System; using System.IO; using System.Threading; using System.Collections.Generic; using NUnit.Framework; using Selenium; using OpenQA.Selenium; using OpenQA.Selenium.Interactions; using OpenQA.Selenium.Remote; using OpenQA.Selenium.Chrome; using OpenQA.Selenium.Support.UI; using System.Globalization; using System.Runtime.InteropServices;