В процессе написания автоматических тестов иногда приходится проверять видимость/отображение изображения на сайте: главная картинка страницы, блока и т.д. Однако простая проверка методом «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;