Web-first assertions

Проверки в Playwright тоже умеют ждать — они повторяют попытку, пока условие не станет верным.

Web-first assertion — это проверка через expect(locator), которая автоматически повторяется до тех пор, пока ожидаемое условие не выполнится или не выйдет таймаут.

Обычная проверка против web-first

Если бы проверка выполнялась мгновенно, она бы упала на асинхронном вебе: текст ещё не подгрузился. Рассмотрим неправильный и правильный варианты.

// ПЛОХО: получаем текст «прямо сейчас», без ожидания
const text = await page.getByRole('heading').textContent();
expect(text).toBe('Привет');  // упадёт, если текст ещё не появился

// ХОРОШО: web-first assertion ждёт нужный текст
await expect(page.getByRole('heading')).toHaveText('Привет');

Во втором случае Playwright будет периодически перепроверять элемент, пока в нём не появится «Привет» (или не истечёт таймаут). Это убирает целый класс флаки-тестов, которые возникают из-за чтения ещё не готового состояния.

Важная деталь: await

Web-first assertions всегда с await, потому что они асинхронные (ждут). А вот проверки обычных значений (чисел, строк, которые уже у вас в руках) — без await. Перепутать легко, а ошибка коварная: без await проверка «как будто проходит», но на деле не дожидается результата.

await expect(locator).toBeVisible();   // ждёт → await
expect(2 + 2).toBe(4);                 // мгновенно → без await

Главные проверки

ПроверкаЧто утверждает
toBeVisible()элемент виден на странице
toBeHidden()элемент скрыт или отсутствует
toHaveText('...')текст элемента точно равен
toContainText('...')текст содержит подстроку
toHaveValue('...')значение поля ввода
toBeEnabled() / toBeDisabled()элемент активен / неактивен
toBeChecked()чекбокс отмечен
toHaveCount(n)столько-то элементов в наборе
toHaveURL('...')адрес страницы

Примеры из жизни

// после отправки формы видно сообщение об успехе
await page.getByRole('button', { name: 'Отправить' }).click();
await expect(page.getByText('Спасибо за заявку')).toBeVisible();

// поле email содержит введённое значение
await expect(page.getByLabel('Email')).toHaveValue('[email protected]');

// кнопка отправки заблокирована, пока форма не заполнена
await expect(page.getByRole('button', { name: 'Отправить' })).toBeDisabled();

Отрицание через not

Любую проверку можно инвертировать через .not — например, убедиться, что баннер с ошибкой исчез:

await expect(page.getByText('Ошибка')).not.toBeVisible();

Почему это снижает флаки

Web-first assertions — это второй (после авто-ожиданий действий) столп устойчивости Playwright. Вместо «считай состояние сейчас и сравни» они говорят «дождись, пока состояние станет таким». Большинство нестабильных тестов в других инструментах ломаются именно на мгновенных проверках текста, которого ещё нет. Правило простое: предпочитайте expect(locator).что-то() ручному чтению значений через textContent() и сравнению.

Итог

  • Web-first assertion (expect(locator)) повторяет проверку, пока условие не станет верным.
  • Такие проверки всегда с await; проверки готовых значений — без.
  • Ключевые: toBeVisible, toHaveText, toHaveValue, toBeEnabled, toHaveURL.
  • Они убирают флаки, возникающие из-за мгновенного чтения ещё не готового состояния.
Проверьте себя
1. Чем web-first assertion отличается от обычного сравнения значений?
AОна выполняется мгновенно и не ждёт
BОна автоматически повторяется, пока условие не станет верным или не выйдет таймаут
CОна работает только с числами
DОна не требует локатора
2. Почему перед expect(locator).toBeVisible() ставят await?
AЭто синтаксическая формальность без смысла
BПроверка асинхронная — она ждёт нужного состояния
CБез await тест выполнится дважды
Dawait ускоряет проверку
3. Какая проверка убедится, что текст элемента точно равен 'Привет'?
Aexpect(locator).toBeVisible()
Bexpect(locator).toHaveText('Привет')
Cexpect(locator).toHaveCount('Привет')
Dexpect(locator).toBeEnabled()
Поддержать проект