Playwright — Примеры

Пример 1 — Селектор, описывающий оформление, и пауза, которая угадывает

Тест добавляет товар и проверяет корзину, но ломается при каждом изменении дизайна и работает медленно. Скажите, к чему привязана каждая строка, затем перепишите тест.

test("adds an item to the basket", async ({ page }) => {
  await page.goto("/shop");
  await page.click(".btn-primary.add");       // CSS-класс
  await page.waitForTimeout(2000);            // явная пауза
  await expect(page.locator("#basket-count")).toHaveText("1");
});

Решение

test("adds an item to the basket", async ({ page }) => {
  await page.goto("/shop");
  await page.getByRole("button", { name: "Add to basket" }).click();
  await expect(
    page.getByRole("listitem").filter({ hasText: "Keyboard" }),
  ).toHaveCount(1);
});

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

Пример 2 — Одна страница, общая для всех тестов

Набор открывает одну страницу браузера и входит через интерфейс перед каждым тестом, поэтому поздние тесты наследуют корзины ранних, а отказ в конвейере не оставляет ничего для разбора. Покажите, как инструмент убирает обе проблемы.

const page = await browser.newPage();
await login(page);                  // ввод в форму каждый раз
// тест 3 видит корзину, которую наполнил тест 1
// отказ в конвейере: ни снимка, ни трассировки, только красная строка

Решение

test.describe("checkout", () => {
  test.use({ storageState: "auth.json" });   // вход выполнен, свежий контекст на каждый тест
});

test("an empty basket shows the message", async ({ page }) => {
  await page.goto("/basket");
  await expect(page.getByText("Your basket is empty")).toBeVisible();
});

// конфигурация: трассировка и снимок экрана при отказе, открываются потом для разбора прогона

Каждый тест получает собственный контекст браузера — чистые cookie, чистое хранилище, никакой общей сессии, — поэтому порядок не может протечь состоянием между тестами, а переиспользуемый вход настраивается один раз и хранится, вместо того чтобы каждый раз проходить через форму. Трассировка, записанная при отказе, превращает красную строку в конвейере в записанную последовательность действий, снимков DOM и вывода консоли, по которой можно пройти локально. В этом и разница между исправлением нестабильного теста за десять минут и догадками о нём на весь день.