Лучшие практики Playwright

Урок: Лучшие практики Playwright

Введение

Когда ты только начинаешь писать тесты в Playwright, всё кажется простым: открыл страницу, нажал кнопку, проверил результат — готово.

Но со временем тестов становится больше. Они начинают:

  • падать без очевидной причины;
  • зависеть друг от друга;
  • ломаться при малейших изменениях интерфейса.

Представь, что ты строишь дом. Сначала можно просто складывать кирпичи, и всё будет выглядеть нормально. Но если не соблюдать правила, со временем стены начнут трескаться.

С тестами то же самое. Можно написать «работающий код», но без правильной структуры он быстро станет нестабильным и сложным в поддержке.

Лучшие практики — это не про «красоту кода», а про стабильность, предсказуемость и удобство работы в долгую.


Пиши тесты как сценарии пользователя

Хороший тест — это не набор технических действий, а понятный сценарий.

Плохо:

await page.click('#btn-login');
await page.fill('#input1', 'user');
await page.fill('#input2', '1234');

Лучше:

await page.getByPlaceholder('Логин').fill('user');
await page.getByPlaceholder('Пароль').fill('1234');
await page.getByRole('button', { name: 'Войти' }).click();

Разница в том, что:

  • код читается как действия пользователя;
  • легче понять, что происходит;
  • тест проще поддерживать.

Важно стремиться к тому, чтобы тест можно было «прочитать вслух».


Используй устойчивые селекторы

Одна из самых частых причин падения тестов — нестабильные селекторы.

Плохо:

await page.click('.btn-primary');

Почему плохо:

  • класс может измениться;
  • дизайн поменяется — тест сломается.

Лучше:

await page.getByRole('button', { name: 'Войти' }).click();

Или:

await page.getByTestId('login-button').click();

Идея в том, что селектор должен быть:

  • стабильным;
  • не зависеть от верстки;
  • понятным.

Не используй явные ожидания (wait)

Новички часто делают так:

await page.waitForTimeout(2000);

Это плохая практика.

Почему:

  • тесты становятся медленными;
  • иногда 2 секунд недостаточно;
  • иногда это лишнее ожидание.

Playwright уже умеет ждать автоматически:

await page.click('button');

Он сам подождёт, пока элемент станет доступным.

Если нужно ждать, лучше использовать:

await expect(page.getByText('Успех')).toBeVisible();

Это проверяет условие, а не просто «ждёт время».


Разделяй логику через Page Object

Когда тесты растут, код начинает дублироваться.

Например:

await page.fill('#login', 'user');
await page.fill('#password', '1234');
await page.click('button');

Если это используется в разных тестах — лучше вынести в отдельный класс.

class LoginPage {
  constructor(page) {
    this.page = page;
  }

  async login(username, password) {
    await this.page.fill('#login', username);
    await this.page.fill('#password', password);
    await this.page.click('button');
  }
}

Использование:

const loginPage = new LoginPage(page);
await loginPage.login('user', '1234');

Это делает код:

  • чище;
  • переиспользуемым;
  • удобным для изменений.

Не смешивай тест и логику

Плохой тест:

test('логин', async ({ page }) => {
  await page.goto('/login');

  await page.fill('#login', 'user');
  await page.fill('#password', '1234');
  await page.click('button');

  await page.waitForTimeout(2000);

  const text = await page.textContent('.message');

  if (text === 'Успех') {
    console.log('OK');
  }
});

Здесь:

  • логика проверки смешана с тестом;
  • нет явного утверждения.

Лучше:

await expect(page.getByText('Успех')).toBeVisible();

Тест должен:

  • описывать поведение;
  • проверять результат;
  • не содержать лишней логики.

Используй expect вместо ручных проверок

Плохо:

let text = await page.textContent('.message');

if (text !== 'Успех') {
  throw new Error('Ошибка');
}

Лучше:

await expect(page.getByText('Успех')).toBeVisible();

Почему:

  • expect уже встроен;
  • даёт понятные ошибки;
  • автоматически ждёт результат.

Изолируй тесты

Каждый тест должен быть независимым.

Плохо:

  • тест зависит от предыдущего;
  • данные «протекают» между тестами.

Playwright решает это через context:

test('пример', async ({ page }) => {
  await page.goto('https://example.com');
});

Каждый тест получает:

  • новый контекст;
  • чистую сессию.

Важно не ломать эту изоляцию вручную.


Делай тесты быстрыми

Медленные тесты — это проблема.

Причины:

  • лишние ожидания;
  • повторяющиеся действия;
  • работа с UI там, где можно через API.

Например, вместо логина через UI в каждом тесте можно:

  • создать пользователя через API;
  • использовать сохранённую сессию.

Это ускоряет тесты в разы.


Добавляй осмысленные проверки

Плохой тест:

await page.click('button');

Он ничего не проверяет.

Хороший тест:

await page.click('button');
await expect(page.getByText('Успешно')).toBeVisible();

Тест должен не просто выполнять действия, а проверять результат.


Где это применяется на практике

Лучшие практики важны в реальных проектах:

  • большие тестовые наборы;
  • CI/CD;
  • командная разработка;
  • долгосрочная поддержка.

Без них:

  • тесты становятся нестабильными;
  • сложно находить ошибки;
  • падает доверие к автотестам.

С ними:

  • тесты работают предсказуемо;
  • код легче поддерживать;
  • команда быстрее развивается.

Итоговое понимание

Лучшие практики Playwright — это не набор правил ради правил.

Это подход к написанию тестов, который делает их:

  • стабильными;
  • читаемыми;
  • независимыми;
  • быстрыми.

Ключевая идея в том, что тесты — это тоже код, и к ним применяются те же принципы качества.

Хорошие тесты не просто «работают сегодня», а остаются понятными и надёжными через месяцы и годы.