Разделы портала

Онлайн-тренинги

.
Автоматизированная работа с DevTools в Selenium 4
15.08.2023 00:00

Автор: компания Simbirsoft

Специалисты QA- и SDET-направлений довольно часто используют DevTools браузера, поскольку в нем есть ряд инструментов, необходимых для отладки и тестирования веб-приложений.

Например, при интеграции REST API методов с интерфейсом приложения достаточно трудоемко читать информацию по запросам и ответам в DevTools после каждого действия, а также сопоставлять это с документацией. Этот кейс можно автоматизировать, например, с помощью сравнительно новой библиотеки DevTools Selenium 4 и инструментов, которые она предоставляет.

В этой статье я — SDET-специалист SimbirSoft Мария, — расскажу про функциональности DevTools, которые были актуальны на наших проектах.

Подключение и выбор версии

Мы используем Selenium в обертке Selenide для более лаконичного и легко читаемого кода. С версии 6.0.1 Selenide обновился на Selenium WebDriver 4.0.0, но отдельной поддержки для новых возможностей, рассматриваемых в данной статье, пока нет. Также версия Selenide 6.0.1 не требует отдельного подключения зависимости JUnit или TestNG, вместо этого следует подключать Selenide TestNG, Selenide JUnit4 или для пользователей JUnit5 – Selenide.

Для того чтобы использовать функции DevTools Selenium 4, необходимо подключить версию библиотеки, совпадающую с версией драйвера. Доступ к данным API интерфейсам Selenium 4 предоставляют все драйверы на основе Chromium, например Chrome и Edge.

Selenide по умолчанию всегда запускает последнюю версию браузера, поэтому подключаем зависимость Selenide TestNG последней версии на июнь 2023 года — 6.14.0. При необходимости предыдущие версии драйверов вы можете указать в настройках конфигурации. Версия драйвера должна совпадать с версией библиотеки DevTools.

Инициализация сущностей

В Chromium Driver есть два способа подключения к сессии DevTools:

• вызвать у экземпляра ChromiumDriver метод getDevTools(), который возвращает объект класса DevTools, и создать сессию (об этом ниже);

• вызвать у экземпляра драйвера метод executeCdpCommand(), куда передать в виде строки название команды и необходимые параметры для ее выполнения.

Метод executeCdpCommand() можно использовать, если для какой-либо функции DevTools нет API Selenium.

Сначала объявим и проинициализируем в предусловиях теста сущности Chrome Driver и  DevTools. Также в предусловии тестов откроем сессию Dev Tools.

public class DevToolsTests {

    private DevTools devTools;
    private ChromeDriver driver;
    private final String url = "https://www.simbirsoft.com/contacts";

    @BeforeMethod
    public void init() {
        Configuration.holdBrowserOpen = true;
        Configuration.browserSize = "1920x1080";
        open(url);
        driver = (ChromeDriver) WebDriverRunner.getWebDriver();
        devTools = driver.getDevTools();
        devTools.createSession();
    }

Захват трафика из вкладки Network применительно к тестированию REST API

Раньше для тестирования интеграции REST API методов нам с frontend-разработчиками приходилось вручную проверять корректность последовательности — действие на странице, отправка запроса, получение ответа, отображение данных из ответа. End-to-end API тесты мы выполняли автоматически при помощи библиотеки Rest Assured или Postman. Напомню, что эти инструменты используются в основном для тестирования работы методов независимо от их интеграции на frontend.

Захватывая трафик автоматически, мы можем реализовать явные интеграционные «причина-следствие» тесты, которые позволят проверить работу REST-запросов в непосредственной связке с действиями и событиями на странице.

Рассмотрим кейс с захватом трафика из вкладки Network применительно к тестированию REST API. Допустим, нам необходимо выполнить какое-либо действие на странице и убедиться, что после него был отправлен определенный запрос (или несколько запросов). Тестирование подобных кейсов наиболее интересно, если отправка конкретного запроса является следствием определенного действия на веб-странице.

@Test
public void checkRequestFromCaptureNetwork() {
    Map requests = new HashMap<String, String>();
    devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    devTools.addListener(
            Network.requestWillBeSent(),
            entry -> {
                if (entry.getRequest().getUrl().equals("https://www.simbirsoft.com/contacts/")) {
                    requests.put(entry.getRequest().getUrl(), entry.getRequest().getHeaders().toJson());
                }
            }
    );

    $(By.xpath("//*[@href='/contacts/']"))
            .shouldBe(Condition.visible)
            .click();

    Assert.assertEquals(requests.size(), 1);
    Assert.assertTrue(requests.containsKey("https://www.simbirsoft.com/contacts/"));
}

Для включения сбора сетевого трафика нужно вызвать метод send и передать в него команду Network.enable, после этого добавить слушатель, который будет захватывать все запросы. Для удобства сохраним в хэш-таблицу url и заголовки этих запросов.

После подготовки выполняем тестовые действия — в нашем случае нажимаем на меню Контакты

    $(By.xpath("//*[@href='/contacts/']"))
            .shouldBe(Condition.visible)
            .click();

и ожидаем, что будет отправлен запрос https://www.simbirsoft.com/contacts/. В этой строке

Assert.assertTrue(requests.containsKey("https://www.simbirsoft.com/contacts/"));

проверяем, что в хеш-таблице requests присутствует интересующий нас запрос.

Бывают ситуации, когда необходимо исключить повторный вызов запросов или холостой вызов ненужных запросов. Тогда можно, например, сохранить в коллекцию только запросы по определенному критерию и проверить размер полученной коллекции.

Часто на практике приходится вручную проверять ответ от сервера на соответствие документации. Если запросов много, то это занимает очень много времени. Подобные проверки можно автоматизировать при помощи команды Network.responseReceived() и получить доступ к параметрам ответа.

@Test
public void checkResponseFromCaptureNetwork() {
    Map responses = new HashMap<String, String>();
    devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    devTools.addListener(
            Network.responseReceived(),
            entry -> {
                responses.put(entry.getResponse().getUrl(), entry.getResponse().getHeaders().toJson());
            }
    );

    $(By.xpath("//*[@href='/contacts/']"))
            .shouldBe(Condition.visible)
            .click();
    Assert.assertTrue(responses.containsKey("https://www.simbirsoft.com/contacts/"));
}

Класс Network предоставляет и другие методы для работы с этой вкладкой Dev Tools. В частности, нам интересны те, которые вносят изменения в запрос. Например, метод setUserAgentOverride подменяет значение User-Agent на заданное, метод setExtraHTTPHeaders принимает коллекцию заголовков и подставляет их в запрос.

Эмуляция параметров экрана

Методы DevTools предоставляют возможность эмуляции параметров экрана, что позволяет автоматизировать тестирование адаптивности веб-приложения. Размеры экрана устанавливаются командой Emulation.setDeviceMetricsOverride, куда должны передаваться 4 обязательных параметра (width, height, deviceScaleFactor, mobile) и еще 9 необязательных и экспериментальных параметров.

//device override
@Test
public void deviceMetricsDynamicTest() {
    for (int i = 1920; i > 400; i -= 100) {
        devTools.send(Emulation.setDeviceMetricsOverride(
                i, 600, 50, true,
                Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty(),
                Optional.empty(), Optional.empty(), Optional.empty(), Optional.empty()));
        open(url);
    }
}

Эта запись делает код плохо читаемым, поэтому лучше использовать вызов команды через executeCdpCommand, куда нужно передать команду в виде строки и набор параметров.

Ниже представлен тестовый пример, где в браузере меняется размер экрана веб-приложения. Чтобы протестировать веб-интерфейс на разных устройствах, можно передать размеры экрана через dataprovider.

//device override
@Test
public void deviceMetricsTest() {
    Map deviceMetrics = new HashMap()
    {{
        put("width", 600);
        put("height", 1000);
        put("mobile", true);
        put("deviceScaleFactor", 50);
    }};
    driver.executeCdpCommand("Emulation.setDeviceMetricsOverride", deviceMetrics);
    $(By.xpath("//*[@href='/contacts/']"))
            .shouldBe(Condition.visible)
            .click();
}

Также в Selenide есть возможность единоразово перед запуском тестов устанавливать параметры экрана. Эта же функция Dev Tools позволяет менять размеры экрана динамически во время выполнения теста и, например, тестировать адаптивность верстки.

Имитация скорости сети

На практике часто приходится тестировать производительность приложения. Например, будет ли оно корректно работать в условиях отключенного интернета или при подключении через Wi-Fi, 2G, 4G, 5G. В этом случае можно сымитировать скорость сети.

@Test
public void networkSpeedTest() {
    devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));
    devTools.send(Network.emulateNetworkConditions(
            false,
            50,
            50,
            80,
            Optional.of(ConnectionType.CELLULAR4G)
    ));
    $(By.xpath("//*[@href='/contacts/']"))
            .shouldBe(Condition.visible)
            .click();
}

В строке

   devTools.send(Network.enable(Optional.empty(), Optional.empty(), Optional.empty()));

открываем вкладку Network Dev Tools, а в строке

    devTools.send(Network.emulateNetworkConditions(

передаем команду Network.emulateNetworConditions со следующими параметрами:

1) offline для отключенного интернета true,

2) latency минимальная задержка в миллисекундах от отправленного запроса до полученных заголовков ответа,

3) максимальная пропускная способность загрузки и выгрузки,

4) тип подключения.

После того как все необходимые нам действия в Network выполнены, нужно закрыть соединение. Вызов команды Network.disable() вынесен в постусловия.

@AfterMethod
public void shutDown() {
    devTools.send(Network.disable());
    driver.close();
}

Вывод

В статье я рассмотрела часто встречающиеся кейсы, такие как захват трафика из вкладки Network, эмуляция размеров экрана, а также имитация скорости сети. Это только несколько возможных кейсов, которые могут встретиться в практике, и небольшая часть методов из API Chrome DevTools.

Интерес могут представлять также функция записи метрик браузера Performance.getMetrics() и эмуляция геоположения. В библиотеке Selenium DevTools есть функции, которые имеют сомнительную практическую значимость, на мой взгляд. Например, переопределение цвета бэкграунда страницы Emulation.setDefaultBackgroundColorOverride(). Если у вас есть идеи по этому поводу, напишите об этом в комментариях.

Полный список методов и их описание представлены в документации Chrome DevTools protocol. Если вы часто заглядываете в DevTools для тестирования, посмотрите, скорее всего теперь эти кейсы тоже можно автоматизировать. 

Конечно, необходимость использования тех или иных функций зависит от проекта. Поделитесь в комментариях, какие функции DevTools вы используете часто, а какие не использовали никогда?

Обсудить в форуме