Основы мета-языка
Для описания тестов платформа “Meta Test” использует специализированный мета-язык. По сути это декларативный, внутренний предметно-ориентированный язык предназначенный для описания автоматизированных QA тестов веб приложений на selenium-е.
Такой подход позволяет:
- Значительно сократить время описания тестов
- Повысить стабильность тестов
- Снизить порог вхождения в автоматизированное тестирование
- Получить эффективное многопоточное выполнение тестов (за счёт гарантированной атомарности на уровне теста)
Поскольку интерпретатор мета-языка работает поверх виртуальной машину python, то возможно комбинировать тесты описанные на мета-языке с программным кодом написанным на python. Но нужно учитывать что код на python-е будет работать только во время загрузки тестов, но не во время их выполнения.
Описание тестов
TEST[“Заголовок”](Последовательность команд, [атрибут=значение, …])[(параметр=значение, …)]
Этот объект используется для описания теста. Обязательно должен быть задан заголовок теста и последовательность команд которые будут выполнены при запуске теста. Для конкретизации свойств конкретного теста он может быть определён со следующими атрибутами. Если атрибут не задан явно, то будут использовано его значение по умолчанию или взято значение из параметров среды.
- tags - Множество текстовых тегов для котором определён тест. Если это множество не пересекается с множеством CONFIG.TAGS, то тест не будет запущен. Если множество пустое или аргумент явно не определён, то тест будет выполнен только в том случае если множество тегов CONFIG.TAGS не определено. Если имя тега начинается с символа **@*, то это означает что тест на этом теге не может быть определён. Например если атрибут теги [“@Тег1”, “Тег2”], то тест не будет запущен если CONFIG.TAGS содержит тег “Тег1”. По умолчанию - {}*
- browser - Множество идентификаторов браузеров для которого определён тест. Если это множество не пересекается с множеством CONFIG.BROWSERS, то тест не будет запущен. Если множество пустое или аргумент явно не определён, то тест будет выполнен на всех браузерах из множества CONFIG.BROWSERS. по умолчанию - {}
- test_id - Идентификатор теста (см CONFIG.TEST_ID). Уникальная строка которая однозначно идентифицирует тест. Если аргумент не определён, то идентификатор генерируется автоматически.
- size - Размер окна браузера. Может быть определён как кортеж (длина, ширина) или как строковые константы. по умолчанию - CONFIG.PAGE_SIZE
Константа | Описание |
---|---|
maximize | Развернуть окно во весь экран |
fullscreen | Полноэкранный режим |
minimize | Свернуть окно браузера |
- fatality - Завершать тестирование после первой ошибки. По умолчанию CONFIG.TEST_FATALITY
- retries - Устанавливает максимальное количество перезапусков теста. По умолчанию CONFIG.RETRIES
- retries_sleep - Устанавливает задержку в сек. перед перезапуском теста. Переопределяет По умолчанию CONFIG.RETRIES_SLEEP
- repiated - Устанавливает количество запусков теста (игнорируется если установлен retries). По умолчанию CONFIG.TEST_REPIATED
- active - Флаг, если он установлен в False то тест не выполняется. По умолчанию True
- single_thread - Флаг указывающий что все экземпляры теста (т.е. параметризованные тесты и тесты для разных браузеров) должны выполняться последовательно. По умолчанию CONFIG.SINGLE_THREADS
- negative - Если этот флаг установлен в True то тест негативный. По умолчанию False
- trigger - Идентификатор триггера для текущего теста.
- description - Текст описания теста.
- severity - Строковая константа устанавливающая степень важности тестируемого дефекта. Может принимать значения: TRIVIAL | MINOR | NORMAL | CRITICAL | BLOCKER. По умолчанию - NORMAL
- flaky - Флаг, если он установлен в True то тест считается не стабильным. Можно перезапускать только нестабильные тесты если см. CONFIG.RETRIES_MODE. По умолчанию False
- Для совместимости с отчётами allure могут быть определены дополнительные текстовые аргументы: epic, feature, story, issue, owner, tms_link.
Пример:
"На хабр можно зайти"](
TEST["https://habr.com/")
URL("habr.com" > PAGE_URL
, "Проверка наличия блока логотипа"
, "scope::habr/logo_locator")
, ONE("Проверка наличия блока поиска"
, "scope::habr/search_locator")
, ONE("Проверка наличия блока рекламы"
, "scope::habr/news_block_locator")
, ONE(= "Мы можем зайти на habr.com, нам виден логотип и некоторые блоки"
, description = ("chrome", "firefox")
, browser = ("base", "habr")
, tags )
Параметризованные тесты
Тесты можно запускать с различными параметрами. Для каждого набора параметров будет запущен отдельный экземпляр теста. После запуска теста текущие параметры записываются в пространство имён теста и могут быть получены командой ARG.
Параметры теста могут быть именованные и не именованные. Если параметр именованный, то его имя явно задаётся при описания теста, в противном случае значение параметра можно получить по его индексу.
Пример:
from faker import Faker
= TEST["text-box"](
test "https://demoqa.com/text-box")
URL("Заполняем"
, "#userName", ARG(0))
, DATA("#userEmail", ARG(1))
, DATA("#currentAddress", ARG("address1"))
, DATA("#permanentAddress", ARG("address2"))
, DATA("#submit")
, CLICK(
"Проверяем"
, "#name") == "Name:" + ARG(0)
, ONE("#email") == "Email:" + ARG(1)
, ONE("p#currentAddress") == "Current Address :" + ARG("address1")
, ONE("p#permanentAddress") == "Permananet Address :" + ARG("address2")
, ONE(= "form"
, tags
)
# выполняем тест "text-box" 100 раз.
# каждый раз генерируется новый набор тестовых данных
= Faker("ru_RU")
fake
for _ in range(100):
test(# Не именованные параметры
fake.name(), fake.email() =fake.address() # Именованные параметры
, address1=fake.address()
, address2 )
Если во время выполнения параметризованного теста могут меняться данные на сайте, то возможно будет целесообразным установить атрибут single_thread в True. Это позволит гарантировать последовательное выполнение тестов при многопоточном запуске что позволит обеспечить их атомарность.
Субтесты
Иногда необходимо не завершая текущий тест открыть новый браузер и выполнить ряд действий на тестируемом сайте. Для этих целей используются субтесты. Они определяются как вложенный тест без указания заголовка.
Пример:
"Основной тест"](
TEST[
URL
, ...
TEST(
URL
, ...
)
, ... )
Субтест имеет общее пространство имён с основным тестом и наследует все его атрибуты.
SCRIPT[“Идентификатор”](Последовательность команд, [атрибут=значение, …])
Этот объект позволяет задать идентификатор последовательности команд что позволяет переиспользовать её в тестах. Для скрипта может быть переопределён атрибут fatality.
Пример:
# Создаём скрипт
"login"](
SCRIPT["/login")
URL("pht::Username", "Admin")
, DATA("pht::Password", "admin123")
, DATA("button")
, CLICK(=True
, fatality )
ARG(“name”[, value][, default=value])
Перед запуском теста создаётся специальное пространство имён доступ к которому могут получить только команды выполняемые во время тестирования. Это пространство используется для обмена данными между скриптами, субтестами и основным тестом, а так же для параметризации тестов и скриптов. Непосредственный доступ к пространству внутри теста можно получить посредством команды ARG следующим образом:
- ARG(“name”, default=value) - Возвращает значение ассоциированное с именем name. Если с именем name не было ассоциировано никаких данных, то возвращается значение определённое в атрибуте default.
- ARG(“name”, value) - Устанавливает ассоциацию имени name со значением value
- ARG(“name”) - Возвращает значение ассоциированное с именем name. Если с именем name не было ассоциировано никаких данных, то действие в котором использован аргумент будет пропущено. В режиме отладки пропущенные действия отображаются со статусом SCIP. Если необходимо пропустить не одно, а несколько действий, то можно воспользоваться условным оператором.
Пример:
# этот блок будет выполнен только если определён аргумент user
"user"), (
IF(ARG("pht::Username", ARG("user"))
DATA("button")
, CLICK( ))
Обратите внимание на то что аргументы не являются переменными. Одна команда должна установить определить ассоциацию с данными лишь единожды.
SCRIPT[“Идентификатор”] | SCRIPT(“Идентификатор 1” [, …, “Идентификатор n”] [, аргумент=значение, …])
Для того что бы выполнить ранее определённый скрипт нужно использовать команду SCRIPT[“Идентификатор”].
Пример:
"login"](
SCRIPT["/login")
URL("pht::Username", ARG("user"))
, DATA("pht::Password", ARG("passwd"))
, DATA("button")
, CLICK(~(PAGE_URL < "/login") # URL текущей страница не должен содержать подстроки /login
, =True
, fatality
)
"Проверка входа на сайт"](
TEST["user", "Admin")
ARG("passwd", "admin123")
, ARG("login"]
, SCRIPT[ )
Как видно при большом количестве аргументов не удобно использовать их явное определение. По этому для вызова параметризованного скрипта нужно использовать конструкцию SCRIPT(“Идентификатор”, [аргумент=значение, …]). Так же с её помощью возможно вызвать последовательно несколько скриптов указав их идентификаторы через запятую.
Пример:
"Проверка входа на сайт"](
TEST["login", user="Admin", passwd="admin123")
SCRIPT(
)
"Без пароля не войдём"](
TEST["login", user="Admin")
SCRIPT(=True
, negative
)
"Без логина не войдём"](
TEST["login", passwd="admin123")
SCRIPT(=True
, negative
)
"Заходим и выходим"](
TEST["login", "logout", passwd="admin123", user="Admin")
SCRIPT( )
STEP[“Заголовок”](Последовательность команд, [атрибут=значение, …])
Логически связанную последовательность команд можно объединить вместе при помощи объекта STEP. Это позволит детализировать информацию выводимую в отчётах. Для краткости можно указывать только заголовок шага, все команды находящиеся после него до следующего заголовка или конца теста будут рассматриваться как тело шага.
Пример:
..."Логин"](
, STEP["pht::Username", ARG("user"))
DATA("pht::Password", ARG("passwd"))
, DATA("button")
, CLICK(
)
# шаги могут быть вложенными:
..."Логин"](
, STEP["заполняем"](
STEP["pht::Username", ARG("user"))
DATA("pht::Password", ARG("passwd"))
, DATA(
)"button")
, CLICK(
)
# Сокращённая запись (вложенность не поддерживается)
..."Логин"
, "pht::Username", ARG("user"))
, DATA("pht::Password", ARG("passwd"))
, DATA("button") , CLICK(
Для шага могут быть определены атрибуты description, uuid и fatality.
SCOPE([“space_id”])
Для передачи данных между тестами можно создавать пользовательские пространства имён. Вызов объекта SCOPE возвращает ссылку на пространство имён доступное всем тестам. Это полезно для хранения данных которые используют тесты из разных файлов.
Объект SCOPE может принимать текстовый параметр space_id который является идентификатором возвращаемого пространства имён.
Пример:
from faker import Faker
= Faker("ru_RU")
fake
= SCOPE("user")
scp = fake.name()
scp.fio = fake.email()
scp.email = fake.address()
scp.address
"..."](
TEST[
..."#fio", scp.fio)
, DATA(
, ... )
Для доступа к SCOPE-пространству имён данным из теста кроме ссылки на само пространство можно использовать специальный локатор - “scope::space_id/name” или объект NP(space_id, name)
Пример:
"#fio", "scope::scp/fio")
DATA(
"#fio", NP("scp", "fio")) DATA(
Селекторы
Для определения пути к элементу страницы используются селекторы. Существует несколько типов селекторов, обычно платформа может автоматически определит его тип. Если тип определяется не верно или необходимо использовать селектор другого типа, то его можно явно указать при помощи префикса селектора с разделителем “::”. Правила определения типа селектора приведены в таблице.
Префикс | Описание |
---|---|
/ | Поиск по XPATH |
( | Поиск по XPATH |
./ | Поиск по XPATH |
.. | Поиск по XPATH |
*/ | Поиск по XPATH |
. | Поиск по CSS селектору (класс) |
# | Поиск по CSS селектору (id) |
* | Поиск по CSS селектору |
[ … ] | Поиск по CSS селектору |
htlm-тег | Поиск по CSS селектору |
css:: | Поиск по CSS селектору |
xpath:: | Поиск по XPATH |
id:: | Поиск по атрибуту ID |
name:: | Поиск по имени |
class:: | Поиск по имени класса |
link:: | Поиск по полному тексту ссылки |
plink:: | Поиск по частичному тексту ссылки |
tag:: | Поиск по тегу |
pht:: | Поиск по тексту placeholder-а |
text:: | Поиск по полному тексту элемента |
Если ни одно из вышеприведённых правил не подходит, то происходит поиск элемента с видимым текстом соответствующим заданному селектору. Фактически поиск происходит по следующему XPATH селектору: //*[contains(normalize-space(text()), normalize-space(‘ТЕКСТ’))]
Часто бывает что селектор указывает не на один, а на список элементов. В этом случае что бы выбрать конкретный элемент можно указать его индекс добавив его в конец префикса селектора - префикс[индекс]::селектор. Отсчёт индексов начинается с 1, индекс 0 будет указывать на последний элемент, индекс -1 на предпоследний и т.д.
# Кликнет на первый элемент который принадлежат классу react-datepicker-wrapper
"[1]::.react-datepicker-wrapper")
CLICK(
# То же, но с указанием типа селектора.
"css[1]::.react-datepicker-wrapper") CLICK(
Составные селекторы
Иногда бывает проще определить путь к элементу страницы как список селекторов подчинённых элементов. Такие селекторы называются составными. Этот способ определения селектора удобен ещё тем что позволяет комбинировать селекторы разных типов.
Пример:
# Поле форме есть несколько полей с заполнителем "Адрес".
# по этому выбираем то которое находится в контейнере с идентификатором "adress_1"
"#adress_1", "pht::Адрес"]) ONE([
Составными селекторами не стоит злоупотреблять т.к. скорость их работы может быть значительно меньше чем у обычных селекторов.
FP(“селектор фрейма 1”[, … “селектор фрейма n”], “Селектор элемента”)
Для определения пути к элементу находящемуся в фрейме нужно использовать специальный объект FP (Frame Pointer). Сначала ему нужно передать селектор фрейма (или нескольких фреймов в порядке вложенности) в котором находится элемент, а затем селектор самого элемента.
Пример:
"nestedframes"](
TEST["https://demoqa.com/nestedframes")
URL("#frame1", "body")) == "Parent frame"
, ONE(FP("#frame1", "iframe", "body")) == "Child Iframe"
, ONE(FP( )
SP(“селектор 1” [, … “селектор n”], “Селектор элемента”)
Для элементов в теневом DOM тоже есть аналогичный объект, он называется SP (Shadow Pointer). Ему сначала передают селекторы контейнеров содержащих вложенный DOM, а затем селектор элемента.
Пример:
"shadow DOM"](
TEST["http://watir.com/examples/shadow_dom.html")
URL("#shadow_host", "input[type=text]"), "file.jpeg")
, DATA(SP("#shadow_host", "input[type=file]"), "file.jpeg")
, UPLOAD(SP("#shadow_host", "input[type=checkbox]"))
, CLICK(SP("#shadow_host", "#nested_shadow_host", "#nested_shadow_content")) == "nested text"
, ONE(SP( )
Выражения и Кванторы
Для проверки значений на страницы сайта используются выражения. Все выражения имеют смысл если являются предикатами т.е. возвращают логическое значение.
Для получения данных из элементов веб страницы используются объекты называемый кванторами они получили своё название из за схожего поведения с одноимёнными абстракциями математической логики.
ONE(“селектор” [, propertie] [, displayed] [, strip] [, timeout])
Квантор единственности. Если селектор будет указывать более чем на один элемент или элементов вообще не будет обнаружено, то попытка выполнения квантора завершится с ошибкой. В противном случае квантор вернёт свойство элемента на который указывает селектор.
Какое именно свойство нужно вернуть указывается в необязательном атрибуте properties. Если атрибут не задан то:
- для элементов input, textarea, select, progress и param возвращается значение свойства value
- для элемента option возвращается значение свойства selected
- для всех других элементов значение свойства textContent
properties так же может ссылаться на css свойства элемента или на его атрибуты. Для этого нужно указать его префикс css:: или attr:: соответственно.
Кроме properties квантор может принимать следующие параметры:
- displayed - Если равен True, то ждём отображения элемента на страницы. По умолчанию - False
- strip - Если равен True, удаляются все пробельные символы в начале и конце возвращаемой строки. По умолчанию - True
- timeout - Время явного ожидания ожидания элемента. По умолчанию - CONFIG.WAIT_TIMEOUT
К полученному значению могут быть применены следующие операторы:
Оператор | Описание |
---|---|
+ | Сумма числовых или конкатенация строковых значений |
- | Разность числовых значений |
* | Произведение числовых значений |
/ | Деление числовых значений |
// | Целочисленное деление числовых значений |
% | Остаток от деления числовых значений |
** | Возведение в степень числовых значений |
[] | Получение значения по индексу |
>> | Вхождение подстроки без учёта регистра ( подстрока >> выражение ) |
<< | Вхождение подстроки без учёта регистра ( выражение << подстрока ) |
> | Вхождение подстроки с учётом регистра ( подстрока > выражение ) |
< | Вхождение подстроки с учётом регистра ( выражение < подстрока ) |
>= | Вхождение подстроки в начало значения ( подстрока >= выражение ) |
<= | Вхождение подстроки в конец значения ( выражение <= подстрока ) |
== | Проверка на равенство |
!= | Проверка на неравенство |
& | Логическая операция И |
| | Логическая операция ИЛИ |
~ | Логическая операция НЕ |
@ | Проверка соответствия регулярному выражению |
Пример:
# Существует только ОДИН элемент соответствующий селектору "div.passwd"
"div.passwd")
ONE(
# Существует только ОДИН элемент соответствующий селектору "div.passwd"
# Текст которого содержит подстроку "Пароль"
"Пароль" > ONE("div.passwd")
# Существует только ОДИН элемент соответствующий селектору "div.passwd"
# Цвет фона которого равен #f5f5f5
"div.passwd", "css::background-color") == "#f5f5f5" ONE(
ALL(“селектор” [, properties] [, displayed] [, strip] [, timeout])
Квантор всеобщности Этот квантор возвращает не одно, а список значений. Его использование аналогично квантору ONE, за тем исключением что операторы обрабатывают не одно значение, а список. По этому их семантика изменена.
Семантика операторов при операциях со скалярным значением:
Оператор | Описание |
---|---|
+ | Сумма или конкатенация значения с каждым элементом выражения |
- | Разность значения с каждым элементом выражения |
* | Произведение значения с каждым элементом выражения |
/ | Деление значения с каждым элементом выражения |
// | Целочисленное деление значения с каждым элементом выражения |
% | Остаток от деления значения с каждым элементом выражения |
** | Возведение в степень значения с каждым элементом выражения |
>> | Вхождение подстроки в КАЖДОЕ значение выражения без учёта регистра |
<< | Вхождение подстроки в КАЖДОЕ значение выражения без учёта регистра |
> | Вхождение подстроки в КАЖДОЕ значение выражения с учётом регистра |
< | Вхождение подстроки в КАЖДОЕ значение выражения с учётом регистра |
>= | Вхождение подстроки в начало КАЖДОГО значения выражения |
<= | Вхождение подстроки в начало КАЖДОГО значения выражения |
== | Проверка на равенство КАЖДОМУ значению выражения |
!= | Проверка на неравенство КАЖДОМУ значению выражения |
& | Логическая операция И над КАЖДЫМ элементом выражения |
| | Логическая операция ИЛИ над КАЖДЫМ элементом выражения |
~ | Логическая операция НЕ над КАЖДЫМ элементом выражения |
@ | Проверка соответствия КАЖДОГО значения регулярному выражению |
Пример:
# Текст во ВСЕХ элементов соответствующих селектору "div.passwd" содержит подстроку "Пароль"
"div.passwd") < "Пароль"
ALL(
# Текст во ВСЕ свойствах элементов соответствующих селектору "div.passwd" равен строке "Пароль"
"div.passwd") == "Пароль" ALL(
Семантика операторов при операциях со списком:
Оператор | Описание |
---|---|
+ | Конкатенация |
- | Список различающихся элементов |
>> | Вхождение каждой подстроки списка в КАЖДЫМ значение выражения без учёта регистра |
<< | Вхождение каждой подстроки списка в КАЖДЫМ значение выражения без учёта регистра |
> | Вхождение каждой подстроки списка в КАЖДЫМ значение выражения с учётом регистра |
< | Вхождение каждой подстроки списка в КАЖДЫМ значение выражения с учётом регистра |
>= | Вхождение каждой подстроки списка в начало КАЖДОГО значения выражения |
<= | Вхождение каждой подстроки списка в конец КАЖДОГО значения выражения |
== | Проверка на равенство выражения списку |
!= | Проверка на неравенство выражения списку |
& | Операция И над декартовым произведением значения и списка |
| | Операция ИЛИ над декартовым произведением значения и списка |
~ | Операция НЕ над декартовым произведением значения и списка |
Пример:
# Текст ВСЕХ элементов соответствующих селектору "div.passwd" содержат подстроку "Пароль" И "Passwd"
"div.passwd") < ["Пароль", "Passwd"]
ALL(
# проверка заполнения таблицы
"tr > td") == [
ALL("Student Name", NP("data", "фамилия") + " " + NP("data", "имя")
"Student Email", "scope::data/email"
, "Gender", "Male"
, "Mobile", "scope::data/mobile"
, "Date of Birth", "31 December,1999"
, "Subjects", "Physics"
, "Hobbies", "Sports"
, "Picture", "scope::data/image_name"
, "Address", "scope::data/address"
, "State and City", "Haryana Panipat"
, ])
Результат применения операторов: >>, <<, >, <, >=, <=, ==, !=, &, |, ~ к выражению передаётся в функцию all тем самым всё выражение приводится к одному логическому значению.
ANY(“селектор” [, properties] [, displayed] [, strip] [, timeout])
Квантор существования. Этот объект во многом схож с ALL, но в отличии от него принимает истину когда любое из его значений истинно, а не все.
Семантика операторов при операциях со скалярным значением:
Оператор | Описание |
---|---|
+ | Сумма или конкатенация значения с каждым элементом выражения |
- | Разность значения с каждым элементом выражения |
* | Произведение значения с каждым элементом выражения |
/ | Деление значения с каждым элементом выражения |
// | Целочисленное деление значения с каждым элементом выражения |
% | Остаток от деления значения с каждым элементом выражения |
** | Возведение в степень значения с каждым элементом выражения |
>> | Вхождение подстроки в ЛЮБОЕ значение выражения без учёта регистра |
<< | Вхождение подстроки в ЛЮБОЕ значение выражения без учёта регистра |
> | Вхождение подстроки в ЛЮБОЕ значение выражения с учётом регистра |
< | Вхождение подстроки в ЛЮБОЕ значение выражения с учётом регистра |
>= | Вхождение подстроки в начало ЛЮБОГО значения выражения |
<= | Вхождение подстроки в начало ЛЮБОГО значения выражения |
== | Проверка на равенство ЛЮБОМУ значению выражения |
!= | Проверка на неравенство ЛЮБОМУ значению выражения |
& | Логическая операция И над ЛЮБЫМ элементом выражения |
| | Логическая операция ИЛИ над ЛЮБЫМ элементом выражения |
~ | Логическая операция НЕ над ЛЮБЫМ элементом выражения |
@ | Проверка соответствия ЛЮБОГО из значений регулярному выражению |
Пример:
# СУЩЕСТВУЕТ элемент соответствующий селектору "div.passwd" текст которого содержит подстроку "Пароль"
"div.passwd") < "Пароль"
ANY(
# СУЩЕСТВУЕТ элемент соответствующий селектору "div.passwd" текст которого равен строке "Пароль"
"div.passwd") == "Пароль" ANY(
Семантика операторов при операциях со списком:
Оператор | Описание |
---|---|
+ | Конкатенация |
- | Список различающихся элементов |
>> | Вхождение ЛЮБОЙ подстроки списка в ЛЮБОЕ значение выражения без учёта регистра |
<< | Вхождение ЛЮБОЙ подстроки списка в ЛЮБОЕ значение выражения без учёта регистра |
> | Вхождение ЛЮБОЙ подстроки списка в ЛЮБОЕ значение выражения с учётом регистра |
< | Вхождение ЛЮБОЙ подстроки списка в ЛЮБОЕ значение выражения с учётом регистра |
>= | Вхождение ЛЮБОЙ подстроки списка в начало ЛЮБОГО значения выражения |
<= | Вхождение ЛЮБОЙ подстроки списка в конец ЛЮБОГО значения выражения |
== | Проверка на равенство выражения списку |
!= | Проверка на неравенство выражения списку |
& | Операция И над декартовым произведением значения и списка |
| | Операция ИЛИ над декартовым произведением значения и списка |
~ | Операция НЕ над декартовым произведением значения и списка |
Пример:
# СУЩЕСТВУЕТ элементов соответствующий селектору "div.passwd"
# Текст которого содержит подстроки "Пароль" И "Passwd"
"div.passwd") < ["Пароль", "Passwd"] ANY(
Результат применения операторов: >>, <<, >, <, >=, <=, ==, !=, &, |, ~ к выражению передаётся в функцию any тем самым всё выражение приводится к одному логическому значению.
Проверка инвариантов
Вышеприведённые выражения можно использовать для проверки данных на странице и её поведения. Для этого достаточно поместить любое выражение в описании теста.
Если такое выражение окажется ложным, то тест или завершится со статусом FATAL или продолжится со статусом FAILED в зависимости от значения параметра CONFIG.TEST_FATALITY. Команды ASSERT и FATAL позволяют явно задать это поведение.
Пример:
# Тест завершится или выдаст ошибку, но продолжит работать
# если текст в элементе с селектором "div.user" не будет равен "Admin"
"div.user") == "Admin" , ONE(
ASSERT | ASSERT(выражение[, “сообщение”])
Вычисляет выражение, если его значение False, то тест продолжится со статусом FAILED. К отчёту можно добавить текст сообщения об ошибки.
Аргументы:
- выражение - Выражение в котором произошла ошибка
- сообщение - пользовательское описание ошибки
FATAL | FATAL(выражение[, “сообщение”])
Вычисляет выражение, если его значение False, то тест завершится со статусом FATAL. К отчёту можно добавить текст сообщения об ошибки.
Аргументы:
- выражение - Выражение в котором произошла ошибка
- сообщение - пользовательское описание ошибки
Пример:
# Завершает тест если текущий URL не содержит подстроки "/news"
"/news" > PAGE_URL, "Не тот URL")
, FATAL(
# Если в тексте заголовка страницы отсутствует подстрока "Новости",
# то переводим тест в FAILED, но продолжаем тестировать
"Новости" > PAGE_TITLE, "Не верный заголовок страницы") , ASSERT(
Дополнительные возможности
Динамическое получение данных
В предыдущих примерах данные создавались перед выполнением теста. Но иногда необходимо получать их динамически во время его выполнение. Для этой цели можно в качестве данных использовать нульарную функцию (т.е. функцию не принимающую аргументов) которая и будет их возвращать.
Пример:
# pass_manager - гипотетическая функция которая выдаёт пароль пользователя во время выполнения команды DATA из теста.
# С её помощью можно гарантировать не пересечение данных между тестами.
= TEST["Зачисление денег на счёт"](
test
..."#user", ARG("user_pass"))
, DATA(
...="123"
, test_id
)=lambda: pass_manager(test.test_id))
test(user_pass
= TEST["Списание денег с счёта"](
test
..."#user", ARG("user_pass"))
, DATA(
...="345"
, test_id
)=lambda: pass_manager(test.test_id)) test(user_pass
Прямой доступ к WebDriver
При описании теста на метаязыке вы полностью абстрагированы от объекта WebDriver-а. Но не исключено что может возникнуть необходимость в низкоуровневом доступе к управлению браузером. В этом случае можно получить объект WebDriver-а передав в тело теста функцию которая этот объект и будет принимать.
Пример:
def todo_url(driver):
"https://todomvc.com")
driver.get(
"Пример перехода на URL через WebDriver"](
TEST[
todo_url10)
, PAUSE( )
Использовать эту возможность нужно очень аккуратно и только при крайней необходимости.
Telegramm группа
Политика конфиденциальности
Персональные данные