В этой статье мы поговорим о том, что можно проверить у локатора (элемента) и какие вообще есть возможности проверок. Более того, в этой статье я описал упражнения, которые вы можете выполнить и отработать в качестве практики.
Обычно мои статьи были холиварными, а не техническими. Но в этот раз решила выложить что-то действительно техническое и полезное. Тестировщики, налетай! Очень хочу, чтобы опытные ребята, которые с playwright работают давно, поделиться своим мнением о примерах в тексте статьи. Достаточно ли они информативны.
Проверки локаторов
Это могут быть как интерактивные элементы (кнопки, поля ввода, чек-боксы, ...), так и статика (картинки, текст, иконки и т.д.).
Каждый элемент на странице может давать пользователю обратную связь: поле ввода подсвечивается красным, если вы ввели невалидные данные, иконка "Сохранить" неактивна, потому что вы еще не внесли изменения в документ, цвет всплывающего уведомления должен быть красным, потому что случилась ошибка. Чаще всего, нам нужно получить какое-то свойство элемента только для того, чтобы сразу же проверить его значение. Мы хотим проверить, что отображается правильный текст или элементу присвоен нужный CSS-класс.
С другой стороны, иногда нам нужно, все же, уметь получать свойства элементов для промежуточных действий. Например, мы хотим посмотреть, сколько сейчас строк в таблице, удалить одну и проверить, что строк стало меньше на одну. Для того, чтобы организовать такую проверку, нам нужно вычислить, сколько всего строк было до того, как мы удалили последнюю строчку. Если в таблице было X
строк, то, после нажатия, должно быть X-1
. Найдите икс, получается? И вот тут нам нужна "ручка", которую мы дернем и получим число, без всяких assert'ов.
В этом разделе мы будем говорить о возможностях работы с локатором в двух плоскостях: мы будем говорить, как получить свойство элемента и как его проверить.
Текст элемента
Давайте начнем с простого примера - получение и проверка текста.
Задача для практики
Напишем скрипт, который открывает страницу и забирает текст у первого на странице элемента по локатору [field=descr]
.
const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => {
await page.goto("<https://inzhenerka.tech/>");
const description = await page.locator("[field=descr]").first().textContent();
console.log(description);
});
В консоль выведется текст "Помогаем инженерам повысить свою квалификацию на рынке труда и приобрести навыки международного уровня". Почему мы увидели его в консоли – потому что строка console.log(description);
. А почему в переменной description
оказалось значение – потому что мы использовали метод textContent()
, который возвращает нам текст переданного локатора.
Что еще за first()?
Вы могли заметить, что мы используем у локатора какой-то метод
first()
перед тем, как запросить текст элемента. Нужно ли его использовать каждый раз, когда я хочу получить текст элемента? Или что будет, если этот метод не вызвать? Объясняем.Дело в том, что, по нашему локатору
[field=descr]
, на странице обнаруживается 4 элемента. Playwright, в таких случаях, выбрасывает ошибкуError: strict mode violation: locator('[field=descr]') resolved to 4 elements
. Что переводится примерно как"разберись, че ты хочешь, потом приходи""по такому локатору определяется 4 элемента". PW не выбирает за нас, с каким элементом работать, а просто останавливается. Хотите выполнения кода – давайте более точные инструкции. Ведь методtextContent()
работает только с одним элементом, а тут их больше одного.Итак, что же делать? Путя всего 2:
Путя 1й: напишите более точный локатор. И это - хорошая практика. Если у вас есть возомжность, посмотрите, что еще можно написать в локаторе, чтобы точно идентифицировать элемент.
Путя 2й и последний: объясните PW, какой из найденных элементов нужно выбрать. В нашем случае, мы просим взять первый - first. Кстати, угадайте, какой по порядку элемент мы получим, если напишем не
.first()
, а.last()
?Раз уж мы умеем обращаться к первому подходящему и последнему подходящему элементу, возникает вопрос - а что, если я хочу обратиться к 4 из 10 элементов? Да или просто - к третьему и я не знаю, сколько их там будет всего? Здесь у нас есть метод
.nth(number)
, который принимает на вход число - порядковый номер элемента. И да, индексация начинается с 0.Получается, что
nth(1)
вернет мне второй по порядку элемент? Ага! А еще получается, чтоnth(0)
– то же самое, что иfirst()
? Ага! Просто "ферст" читается как-то проще, согласны?Ссылочки на эти методы, если вы их читаете: nth, first и last
Итак, мы умеем получать текст элемента. И тут, если вы работали с selenium'ом, например, вам уже все понятно: чтобы написать тест, нам нужно получить текст и сравнить его с ожидаемым. Ну как-то так, например:
`const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => { await page.goto("https://inzhenerka.tech/");
// сохранили текст элемента в переменную const description = await page.locator("[field=descr]").first().textContent(); // проверили, что текст в переменной равен тому, который мы указали expect(description).toEqual( "Помогаем инженерам повысить свою квалификацию на рынке труда и приобрести навыки международного уровня" ); });`
И это даже будет работать.
С другой стороны, если открыть документацию, можно увидеть вот такое предупреждение:
Разработчики инструмента прямым текстом нам говорят, что, если хотите проверить текст, используйте лучше метод toHaveText()
. Мы с вами в интернете давно и знаем, что в таких ситуациях нужно сразу спрашивать - а чем жто "лучше"?
Сначала давайте посмотрим, как будет выглядеть наш тест, если мы будем использовать рекомендуемый метод:
const { test, expect } = require("@playwright/test");
test("get text", async ({ page }) => {
await page.goto("<https://inzhenerka.tech/>");
await expect(page.locator("[field=descr]").first()).toHaveText(
"Помогаем инженерам повысить свою квалификацию на рынке труда и приобрести навыки международного уровня"
);
});
Смотрите, обошлись без переменной description
- сразу написали проверку, мол такой-то элемент должен содержать такой-то текст. В критерию "читаемость", один балл записываем в пользу второго подхода. Заметили, кстати, что теперь у expect()
можно вызвать другой набор методов? Это все потому, что на вход мы передали не page
, как раньше, а locator
. Вот и методы подходящие появились.
У toHaveText()
есть еще пара трюков в пороховницах.
Во-первых, этот метод умеет сравнивать, игнорируя регистр. Это пригодится вам, когда выяснится, что в HTML'е текст написан маленькими буквами, а на странице отображается КАПСОМ (спросите у своего фронтэнд разработчика, как такое можно организовать). И вот для того, чтобы не собирать шишки, подбирая правильный регистр у ожидаемого результата, мы можем просто передать правильную настройку:
await expect(page.locator("")).toHaveText("ожидаемый текст", {
ignoreCase: true,
});
Вторая интересная фича метода toHaveText()
- он умеет проверять текст у группы элементов. Как это работает: если ваш локатор определяет не один элемент на странице, а группу (например, список), то и для проверки текста у элементов мы должны передать группу (массив) значений. Метод соотнесет полученные и ожидаемые тексты 1-к-1. Если что-то не совпадет - ошибка. Примеры:
<!-- вот у нас есть вот такой список на странице -->
<ul>
<li>Билли</li>
<li>Вилли</li>
<li>Дилли</li>
</ul>
// ✓ Вот этот код проверит, что тексты у элементов соответственно равны переданным.
await expect(page.locator("ul > li")).toHaveText(["Билли", "Вилли", "Дилли"]);
// ✖ Вот такая проверка упадет, потому что текстовки идут в другом порядке
await expect(page.locator("ul > li")).toHaveText(["Дилли", "Билли", "Вилли"]);
// ✖ Такой тест тоже упадет, потому что текст одного из элементов не совпадем с ожидаемым
await expect(page.locator("ul > li")).toHaveText([
"Билли",
"Вилли",
"Джонатан?",
]);
// ✖ Вот тут сложнее.
// Тест упадет, потому что локатор собирает не группу элементов (li), а только один (ul).
// Нельзя сравнить текст одного элемента с группой текстов.
await expect(page.locator("ul")).toHaveText(["Text 1", "Text 2", "Text 3"]);
Ссылка на документацию В общем-то, действительно и удобнее, и код более читаемый. Давайте так и будем поступать: хотим получить данные - используем метод класса Locator. Хотим проверку - заносим локатор в метод expect и вызываем нам интересный метод.
Это бесплатная демо-часть урока тренажера по Playwright от INZHENERKA.TECH, написаная Дмитрием Ереминым. Больше обсуждений по теме проходит в нашем сообществе по Playwright в телеграмме
Напомню о цели этой статьи: поделитесь своим мнением о примерах в тексте, как вам? Считаете ли вы их достаточно информативными?