В этой статье мы поговорим о том, что можно проверить у локатора (элемента) и какие вообще есть возможности проверок. Более того, в этой статье я описал упражнения, которые вы можете выполнить и отработать в качестве практики.

Обычно мои статьи были холиварными, а не техническими. Но в этот раз решила выложить что-то действительно техническое и полезное. Тестировщики, налетай! Очень хочу, чтобы опытные ребята, которые с 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()? Ага! Просто "ферст" читается как-то проще, согласны?

Ссылочки на эти методы, если вы их читаете: nthfirst и 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( "Помогаем инженерам повысить свою квалификацию на рынке труда и приобрести навыки международного уровня" ); });`

И это даже будет работать.

С другой стороны, если открыть документацию, можно увидеть вот такое предупреждение:

Untitled

Разработчики инструмента прямым текстом нам говорят, что, если хотите проверить текст, используйте лучше метод 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 в телеграмме

Напомню о цели этой статьи: поделитесь своим мнением о примерах в тексте, как вам? Считаете ли вы их достаточно информативными?

Комментарии (0)