Разбор trace
Сообщение «ожидаемый текст не найден» указывает на невыполненное условие, но не всегда объясняет, что происходило перед ним. Поле могло остаться пустым, кнопка нажалась не в той форме или приложение показало другое состояние. Для разбора полезно восстановить последовательность действий и наблюдений, связанную с конкретным запуском.
В этом уроке подготовим запись trace при неудаче и назовём смысловые шаги поиска. Файл lesson-15/expected доступен в архиве. Здесь нет настоящего trace, скриншотов или результатов запуска: они появятся только при будущем выполнении лаборатории и соответствующих условиях.
Trace и текущая страница
Trace сохраняет материал о выполнении сценария, который можно открыть после его завершения. Это отличается от повторного посещения страницы вручную: текущий каталог уже мог оказаться в другом состоянии. Разбор записи относится к действиям конкретной попытки и помогает сопоставить неудачное утверждение с предшествующей последовательностью.
В конфигурации заменим только настройку trace:
trace: 'retain-on-failure'
Для правильного успешного теста такая настройка обычно не оставляет сохранённую запись. Поэтому после обычного успешного выполнения не нужно ожидать trace.zip как обязательный результат. Мы выбрали хранение при неудаче, чтобы учебная конфигурация не создавала лишние артефакты каждого успешного сценария.
Настройка retries по-прежнему равна нулю. Это важно для объяснения: мы не используем режим записи только на повторной попытке и не ожидаем, что первая ошибка автоматически запустит другой ход. Если позже включить retries, каждый trace нужно связывать с номером попытки, а не смешивать события разных выполнений в одну историю.
В Trace viewer описаны просмотр действий, снимков DOM и сетевой информации. Конкретный состав полезного материала зависит от настроек и того, что действительно произошло. Мы не предполагаем существование записи по одному наличию опции в исходнике; файл должен быть создан настоящим будущим запуском.
Смысловые шаги вместо длинной цепочки
Сценарий ищет слово несуществующийxyz. Ожидается ноль карточек и понятное сообщение. Обернём действия в test.step:
await test.step('Ввести отсутствующий курс', async () => {
await page.getByLabel('Запрос', { exact: true })
.fill('несуществующийxyz');
});
await test.step('Отправить поиск и проверить пустое состояние', async () => {
await page.getByRole('button', { name: 'Найти', exact: true }).click();
await expect(page.getByTestId('results-status'))
.toHaveText('Найдено курсов: 0');
await expect(page.getByText('По этому запросу ничего не найдено', {
exact: true
})).toBeVisible();
await expect(page.getByRole('list', { name: 'Курсы' })
.getByRole('listitem')).toHaveCount(0);
});
Это содержимое одного теста, который получает готовую catalogPage. Названия шагов обозначают пользовательскую задачу, а не повторяют каждую техническую операцию. Такая группировка помогает видеть, где закончился ввод и началась отправка. Утверждения остаются обычными проверками состояния; test.step не меняет их ожидаемый результат.
Не стоит добавлять шаг на каждую строку только ради подробного дерева. Если названия ничего не объясняют, запись станет длиннее, но разбор не упростится. В нашем примере две группы соответствуют двум заметным этапам пути. Подготовка фикстуры остаётся отдельной частью жизненного цикла и также требует внимания при неудаче до начала основного действия.
Получение учебной неудачи
Чтобы в будущем исследовать запись, можно намеренно изменить ожидаемый счётчик с нуля на один и выполнить сценарий отдельно. Такое изменение создаёт неверный тест, а не поломку приложения. После разбора нужно вернуть правильное ожидание. В архивном expected сохранён корректный вариант, поэтому искусственная ошибка не станет частью нормального набора.
Будущая запись неудачного запуска может находиться в рабочей папке test-results внутри каталога конкретного теста. Точный путь сообщает runner; заранее выдуманный путь не является доказательством созданного файла. Для открытия собственного найденного файла предназначена команда:
npx --no-install playwright show-trace /полный/путь/к/своему/trace.zip
Это шаблон с заменяемым путём, а не команда, выполненная авторами. Просмотр следует начинать с имени теста и попытки, затем переходить к последнему успешному действию перед неудачным утверждением. Если в записи другой тест или другая версия исходников, вывод о текущей ошибке будет ненадёжным.
Как читать причину
Для нашего поиска сначала проверьте, что поле действительно получило несуществующийxyz. Затем найдите нажатие «Найти» в форме поиска. После него сравните текст статуса, число карточек и объяснение пустоты. Если эти наблюдения соответствуют договорённости, а тест ждёт один курс, ошибка находится в ожидании, а не в приложении.
Если поле осталось пустым, исследуйте локатор и действие ввода. Если текст введён, но список не изменился, исследуйте отправку формы и обработчик. Если статус показывает ноль, а карточки остались, вероятна рассогласованность отрисовки. Trace помогает восстановить порядок наблюдений, но окончательная причина всё равно требует сверки с кодом и контрактом.
Сетевой ответ в записи не всегда объясняет результат. В этом сценарии каталог подменён фикстурой, а фильтрация происходит локально, без нового запроса. Отсутствие сетевого обращения после кнопки является нормальным условием примера. Искать несуществующий серверный поиск вместо чтения локального обработчика было бы ошибкой модели.
Границы и обращение с артефактом
Trace может содержать тексты страниц, ответы и данные взаимодействия. Для этой лаборатории все значения вымышленные и локальные. При настоящем сайте запись может включать пользовательские данные или состояние сессии, поэтому её не стоит публиковать вместе с исходниками без оценки содержания. Это свойство конкретного артефакта, а не повод выдавать отсутствие trace за выполненный анализ.
Архив примеров содержит только исходники и сценарии ожидаемого поведения. Папки test-results и playwright-report исключены в .gitignore. Наличие этих правил не означает, что отчёты созданы: они заранее описывают будущие рабочие результаты. Так читатель различает код, который можно сохранить, и данные конкретного выполнения.
Не используйте запись как единственный источник истины о всём приложении. Она относится к одному пути и одному окружению. Если проблема зависит от другой ширины, роли или ответа, нужно воспроизвести соответствующие условия. Случайно выбранный trace успешного поиска не подтверждает правильность формы или мобильного меню.
После урока сценарий имеет смысловые шаги и режим сохранения материала неудачи. Это подготовленная возможность диагностики, а не заявление, что ошибку уже воспроизвели. Далее рассмотрим другое наблюдение — визуальное изображение страницы, которому потребуется собственный эталон и гораздо более строгая договорённость об окружении.
Сохранённый trace не является записью видеозвонка или доказательством действия реального посетителя. Это диагностический материал автоматизированного сценария в заданном окружении. Важные детали, которые программа не наблюдала, могут отсутствовать. Поэтому описание причины должно опираться на видимые события и исходный контракт, а предположение следует отделять от подтверждённого наблюдения.
Для передачи проблемы другому разработчику полезны имя сценария, версия исходников, входные данные и последний успешный шаг. Сам архив без этих сведений заставит получателя сначала восстанавливать задачу. В нашей серии все эти условия определены заранее, поэтому будущую запись можно будет связать с конкретным учебным состоянием.