Modern QA2026Контексты, ожидания и утверждения
Join

Course13 Browser Automation with Playwright

Foundations · Chapter 13

Контексты, ожидания и утверждения

Updated Jul 2026

Три концепции формируют основу преимущества надёжности Playwright перед предыдущими инструментами: контексты браузера для изоляции, автоожидание для устранения ошибок тайминга и web-first утверждения, которые повторяются до выполнения условия. Освойте эти три концепции — и большинство проблем нестабильности исчезнет.

Контексты браузера

Контекст браузера — это легковесная изолированная сессия, подобная окну инкогнито. Каждый контекст имеет собственные cookies, localStorage и кэш. В отличие от Selenium, где каждый тест обычно запускает новый процесс браузера, Playwright создаёт контексты внутри одного экземпляра браузера.

// Каждый тест автоматически получает свой контекст в @playwright/test
test('пользователь A видит свою панель', async ({ page }) => {
  // `page` принадлежит свежему контексту — изолирован от других тестов
});

// Ручное создание контекстов для многопользовательских сценариев
test('два пользователя сотрудничают', async ({ browser }) => {
  const adminContext = await browser.newContext();
  const userContext = await browser.newContext();
  const adminPage = await adminContext.newPage();
  const userPage = await userContext.newPage();

  // Админ и пользователь имеют полностью отдельные сессии
  await adminPage.goto('/admin');
  await userPage.goto('/dashboard');
});

Почему контексты важны

Подход Selenium Подход Playwright
Один браузер на тест (медленный запуск) Один браузер, много контекстов (быстро)
Общее состояние просачивается между тестами Полная изоляция для каждого контекста
Параллельность = несколько процессов браузера Параллельность = несколько контекстов в одном браузере
Очистка cookies между тестами — вручную Контексты одноразовые — очистка не нужна

Автоожидание

В Selenium источник нестабильности тестов №1 — тайминг: тест пытается взаимодействовать с элементом до его готовности. Playwright устраняет это автоожиданием перед каждым действием.

Когда вы вызываете page.click('button'), Playwright автоматически ожидает, что элемент:

  1. Прикреплён к DOM
  2. Видим (не скрыт CSS)
  3. Стабилен (не анимируется)
  4. Активен (не отключён)
  5. Принимает события (не перекрыт другим элементом)

Только после этого выполняется клик. Если любое условие не выполнено, Playwright повторяет попытки до таймаута.

// Playwright: просто кликните — автоожидание обработает тайминг
await page.getByRole('button', { name: 'Submit' }).click();

// Selenium: необходимо вручную ждать, затем кликнуть
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

WebDriverWait(driver, 10).until(
    EC.element_to_be_clickable((By.XPATH, "//button[text()='Submit']"))
).click()

Что покрывает автоожидание

Действие Ожидает
click() Прикреплён, видим, стабилен, активен, принимает события
fill() Прикреплён, видим, активен, редактируем
check() Прикреплён, видим, стабилен, активен
selectOption() Прикреплён, видим, активен
textContent() Прикреплён
isVisible() Ничего (возвращает немедленно)

Когда всё ещё нужны явные ожидания

Автоожидание обрабатывает взаимодействия, но иногда нужно дождаться условия перед продолжением:

// Ожидание конкретного ответа после запуска действия
await page.waitForResponse('**/api/orders');

// Ожидание навигации
await page.waitForURL('**/dashboard');

// Ожидание исчезновения элемента (спиннер загрузки)
await page.getByTestId('spinner').waitFor({ state: 'hidden' });

Web-First утверждения

Утверждения expect() в Playwright являются «web-first» — они повторяются до выполнения условия или истечения таймаута. Это принципиально отличается от мгновенных утверждений, которые проверяют один раз и падают.

// Web-first: повторяет до появления текста (до 5 секунд по умолчанию)
await expect(page.getByRole('alert')).toHaveText('Сохранено успешно');

// Мгновенное утверждение: проверяет один раз, падает если не готово
// НЕ ДЕЛАЙТЕ ТАК:
const text = await page.getByRole('alert').textContent();
expect(text).toBe('Сохранено успешно'); // хрупко!

Распространённые web-first утверждения

// Состояние элемента
await expect(page.getByRole('button')).toBeVisible();
await expect(page.getByRole('button')).toBeEnabled();
await expect(page.getByTestId('input')).toHaveValue('hello');
await expect(page.getByRole('alert')).toHaveText('Успех');

// Состояние страницы
await expect(page).toHaveTitle(/Панель/);
await expect(page).toHaveURL(/\/dashboard/);

// Количество элементов
await expect(page.getByRole('listitem')).toHaveCount(5);

// CSS и атрибуты
await expect(page.getByTestId('status')).toHaveClass(/active/);
await expect(page.getByRole('link')).toHaveAttribute('href', '/about');

Таймаут утверждений

// Таймаут по умолчанию: 5 секунд. Переопределение для конкретного утверждения:
await expect(page.getByText('Отчёт готов')).toBeVisible({ timeout: 30_000 });

// Или установить глобально в конфигурации:
// expect: { timeout: 10_000 }

Всё вместе

test('добавление товара в корзину', async ({ page }) => {
  await page.goto('/products');

  // Автоожидание: кликает когда кнопка готова
  await page.getByRole('button', { name: 'В корзину' }).first().click();

  // Web-first утверждение: повторяет до отображения «1» в бейдже корзины
  await expect(page.getByTestId('cart-count')).toHaveText('1');

  // Навигация и проверка
  await page.getByRole('link', { name: 'Корзина' }).click();
  await expect(page).toHaveURL(/.*cart/);
  await expect(page.getByRole('listitem')).toHaveCount(1);
});

Никаких явных ожиданий. Никаких sleep-операторов. Никаких проблем с таймингом. Автоожидание и web-first утверждения обрабатывают всю синхронизацию.

Ключевые выводы

  • Контексты браузера обеспечивают легковесные изолированные сессии — нет утечек состояния между тестами
  • Автоожидание проверяет готовность (видимость, стабильность, активность) перед каждым взаимодействием
  • Web-first утверждения повторяются до выполнения условия, устраняя состояния гонки
  • Используйте waitFor() и waitForResponse() только когда нужно ждать асинхронные операции за пределами простых взаимодействий
  • Никогда не используйте мгновенные утверждения для динамического контента — всегда используйте expect() из @playwright/test