Тестирование веб-приложений Flutter с помощью Selenium

Всем привет. Хочу поделиться решением проблемы тестирования веб-приложений Flutter. Когда речь заходит о UI тестировании Web приложений, собранных с помощью Flutter, то непосвященный теряется, а тот кто знаком с проблемой, тот тяжело вздыхает. В общем, просто забываем о всех мощных инструментах, о Selenium, Protractor. Многие думают, что запустить тесты Web UI с помощью известных инструментов не получится, но это не так.

Для тех, кто не знаком с Flutter, позвольте объяснить проблему простыми словами.

Flutter не генерирует стандартные HTML-элементы, которые легко находятся привычными инструментами тестирования. Вместо этого он просто рисует пользовательский интерфейс. В итоге вы получаете в основном холст с некоторой оболочкой вокруг него. Без лишних слов, взгляните на этот сайт и убедитесь сами: https://flutter-gallery-archive.web.app/

А вот содержимое flutter-view:

5fd0216173245e52c4c7c76d8d5cb4ef.png

Другими словами, нет ничего, за что можно зацепиться.

Поиск не приводит ни к чему полезному. Или точнее, он приводит к собственным инструментам тестирования Flutter: integration_test. Это мощный инструмент. Вы можете запускать тесты для любой платформы, для которой вы создаете свое приложение. По сути, вы компилируете специальную версию приложения для тестирования. Нужно изменить тест? Компилируйте снова. У вас просто нет возможности тестировать развернутое веб-приложение. Это своего рода тестирование серого ящика. Более того, требуется преодолеть более крутую кривую обучения.

Решение есть. Далее разберем, как запустить полноценное black-box тестирование.

Мы будем использовать возможности Accessibility. Эта возможность используется экранными читалками. Для поддержки этих инструментов, Flutter позволяет построить семантическое дерево с описанием элементов. По умолчанию, оно не строится. Нужно в приложении его явно инициализировать:

import 'package:flutter/material.dart';
import 'package:flutter/semantics.dart';

void main() {
  runApp(const MyApp());
  SemanticsBinding.instance.ensureSemantics();
}

Допустим, никто не позаботился об этом заранее и не активировал этот режим. Flutter позволяет построить дерево, если вы программно нажмете на специальную кнопку размером в 1 пиксель.

Вот как это сделать вручную:

  1. Откройте ваше веб-приложение Flutter в браузере (в качестве примера откройте вот это https://flutter-gallery-archive.web.app/)

  2. Откройте инструменты разработчика (нажав Ctrl+Shift+I на Windows/Linux или Cmd+Option+I на macOS).

  3. Перейдите на вкладку «Консоль» в инструментах разработчика.

  4. Вставьте и выполните следующий скрипт:

document.querySelector('flt-glass-pane').shadowRoot.querySelector('flt-semantics-placeholder').click();

DOM заполнен, и вы можете выполнять тесты.

853d40b0f893cbca74fed895de7df5c9.png

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

Тем не менее вы можете писать стандартные тесты. Вот пример с Selenium:

const clickMeButtonXPath = '//flt-semantics[contains(@aria-label, "Click Me")]';
let clickMeButton = await driver.wait(until.elementLocated(By.xpath(clickMeButtonXPath)), 30000);

clickMeButton.click();

const clickedMeLabelXPath = '//flt-semantics[contains(@aria-label, "You clicked me")]';
let clickedMeLabel = await driver.wait(until.elementLocated(By.xpath(clickedMeLabelXPath)), 30000);

expect(clickedMeLabel).toBeDefined();

Для обнаружения элементов с помощью локаторов вы должны полагаться на атрибут aria-label. Вы можете явно управлять этим атрибутом через виджеты Semantics. Недавно, в версии Flutter 3.19.0, было добавлено свойство identifier. Но, к сожалению, оно не работает для веба.

В любом случае это станет неплохой отправной точкой.

Я написал небольшой npm пакет в качестве примера, который облегчает быстрый старт. Код можно найти здесь https://github.com/rentready/flutter-selenium-bridge/. Хотя я не могу гарантировать работу пакета во всех случаях, я открыт для предложений и улучшений. Так что если у вас есть дополнения — приглашаю сделать PR.

Пока писал эту статью, обнаружил https://github.com/appium/appium-flutter-driver. Он использует тот же самый механизм для тестирования мобильных приложений написанных на Flutter. Так что можно подсмотреть у них что-то, что можно перенести в тестирование веб приложений.

© Habrahabr.ru