Перейти к содержанию

Первый сценарий Playwright

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

Работа ведётся в отдельной папке catalog-test-lab. Настоящий ProfessorWeb здесь не открывается. Исходники лежат в архиве серии; начало последовательности доступно в оглавлении. Все команды ниже предназначены для будущего самостоятельного выполнения. При подготовке материала пакеты, сервер и тесты не запускались.

Три части лаборатории

Playwright Test получает описание сценария, создаёт браузерный контекст и проверяет утверждения. Учебный Node-сервер отдаёт HTML, стили и небольшое API. Страница загружает каталог из /api/courses. Поэтому одного открытия файла с диска недостаточно: нужен HTTP-адрес, на котором доступны и страница, и её данные.

Зафиксируем Node 24.21.0 LTS и @playwright/test 1.64.0. Версии проверены 11 октября 2026 года по странице выпуска Node и метаданным пакета. Это конкретная учебная точка, а не обещание использовать последнюю версию в любой день. Требования к операционной системе следует сверить с установкой Playwright.

Скопируйте содержимое common в новую папку. Перенесите lesson-02/expected/lesson.spec.js в tests/lesson.spec.js, а конфигурацию из того же состояния — в корень проекта. Название файла заканчивается на .spec.js, чтобы runner мог найти его среди проверок. В package.json закреплён прямой пакет; настоящего package-lock.json пока нет, поскольку установка не выполнялась.

Для будущего запуска предназначены следующие команды:

npm install
npx --no-install playwright install chromium
npm test

Первая команда создаст дерево зависимостей и lockfile. Вторая отдельно загрузит браузер, связанный с установленным Playwright. Третья запустит runner из локального пакета. Параметр --no-install исключает незаметное получение другого пакета при отсутствии установленного инструмента. До появления lockfile нельзя заменять первую команду на npm ci: у этой команды другие предпосылки.

Откуда берётся адрес страницы

В playwright.config.js задаётся baseURL равный http://127.0.0.1:4407. Это отдельный порт лаборатории. Конфигурация webServer запускает node server.mjs и ждёт /health. Самостоятельно поднимать второй экземпляр сервера одновременно не нужно. Значение reuseExistingServer:false защищает от случайного подключения к неизвестному процессу на том же адресе.

Главные настройки имеют следующий смысл:

use: {
  baseURL: 'http://127.0.0.1:4407',
  browserName: 'chromium',
  viewport: { width: 1280, height: 800 },
  trace: 'off', screenshot: 'off'
},
webServer: {
  command: 'node server.mjs',
  url: 'http://127.0.0.1:4407/health',
  reuseExistingServer: false
}

Это фрагмент полной конфигурации из архива, не самостоятельный файл. У общего проекта также заданы каталог проверок, таймауты, язык, часовой пояс и отсутствие повторных попыток. Фиксация условий помогает сравнивать результаты. Она не делает различия операционных систем невозможными, особенно когда позже мы перейдём к изображениям.

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

Первый полный сценарий

Файл tests/lesson.spec.js для этого урока содержит одну проверку:

import { test, expect } from '@playwright/test';

test('каталог показывает четыре курса', async ({ page }) => {
  await page.goto('/');
  await expect(page.getByRole('heading', {
    name: 'Каталог курсов', exact: true
  })).toBeVisible();
  await expect(page.getByTestId('results-status'))
    .toHaveText('Найдено курсов: 4');
  await expect(page.getByRole('list', { name: 'Курсы' })
    .getByRole('listitem')).toHaveCount(4);
});

Функция test получает понятное имя и асинхронное действие. Объект page предоставляет страничную фикстуру runner. Перед операциями браузера и ожиданиями стоит await: следующий шаг начинается после завершения текущего. Без этой последовательности тест может закончиться раньше, чем проверка получит результат, либо оставить необработанную ошибку.

Адрес / разрешается относительно baseURL. Он не обозначает корень файловой системы и не ведёт на ProfessorWeb. Первый локатор ищет видимый заголовок по роли и имени. Слово exact исключает случайное совпадение с более длинным названием. Второе утверждение ждёт конкретный текст статуса, третье проверяет количество элементов внутри именованного списка.

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

Что означает будущий результат

При выполнении правильного примера ожидается успешная проверка с указанным именем. Здесь такой вывод не получен и не приложен. Точное оформление консольного сообщения зависит от reporter и среды. Учебным результатом является сформулированное утверждение, а не заранее напечатанная строка о прохождении теста.

Если /health недоступен, причина находится до открытия страницы. Если заголовок не найден, исследуйте ответ HTML и доступное имя. Если статус остаётся «Загрузка каталога», исследуйте запрос данных. Такое разделение не позволяет считать любую неудачу ошибкой Playwright. Runner показывает, какое ожидание не выполнилось; причину определяют по состоянию страницы и сервера.

Мы пока проверяем один браузер и маленький каталог. Успешный сценарий не подтвердит все маршруты, доступность формы или поведение на телефоне. Зато он задаёт основу: явный адрес, собственное окружение, один результат и утверждения после загрузки. Дальнейшие проверки будут менять предмет наблюдения, сохраняя эту последовательность.

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

Что сохраняется после установки

Будущий lockfile описывает конкретное дерево пакетов. Закрепление одного @playwright/test в package.json полезно, но не следует называть его полным снимком всех зависимостей. Пока установки нет, мы не выдумываем lockfile и не заявляем воспроизведённое окружение. После разрешённой установки этот файл можно сохранить вместе с исходниками отдельной лаборатории.

Рабочие папки node_modules и test-results имеют другое назначение. Первая содержит установленное окружение, вторая — результаты конкретного выполнения. Они исключены в .gitignore. Их отсутствие в архиве нормально: читатель получает воспроизводимый источник, а не чужие бинарники и якобы готовый отчёт.

Runner также отличает отсутствие проверок от успешного выполнения. Если файл скопирован не в tests или имеет неподходящее имя, сообщение о найденных тестах не будет соответствовать ожиданию. Поэтому порядок копирования важен: полный файл урока заменяет tests/lesson.spec.js, а не сохраняется рядом в случайной подпапке. Перед будущим запуском достаточно сверить эту структуру чтением; не нужно создавать дополнительные непонятные варианты сценария.