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

Проверка формы

Форма сообщения об ошибке даёт читателю возможность указать проблему в курсе. Для её проверки недостаточно убедиться, что поля существуют. Нужно различать ввод, отклонение недопустимого значения и принятие допустимого сообщения. Иначе кнопка может срабатывать, но посетитель не поймёт, что произошло с его текстом.

В нашей лаборатории сообщения никуда не отправляются и не сохраняются. Сервер только проверяет учебный запрос и возвращает ответ. В lesson-07/expected/lesson.spec.js описан один связный путь: неправильный адрес почты, понятная ошибка, исправление значения и успешный ответ. Исходники доступны в архиве; результаты выполнения пока отсутствуют.

Поле, метка и сообщение об ошибке

У формы есть доступное имя «Сообщение об ошибке». Внутри расположены поле «Электронная почта», поле «Сообщение» и кнопка «Отправить сообщение». Это отдельная форма рядом с поиском. Начнём с её выбора, чтобы одинаковые элементы будущего интерфейса не попали в другой сценарий.

const form = page.getByRole('form', { name: 'Сообщение об ошибке' });
const email = form.getByLabel('Электронная почта', { exact: true });
await email.fill('не-почта');
await form.getByLabel('Сообщение', { exact: true })
  .fill('В курсе HTML опечатка');
await form.getByRole('button', { name: 'Отправить сообщение' }).click();

В полном тесте page является именем полученной catalogPage. Поле содержит недопустимый адрес, а сообщение заполнено, чтобы не смешивать две ошибки ввода. Атрибут novalidate формы отключает блокирующее стандартное окно браузера: приложение само показывает текст рядом с полем. При этом свойство validity.valid используется обработчиком для проверки типа email.

Ожидаемое состояние после отправки включает несколько связанных деталей:

await expect(form.getByRole('alert'))
  .toHaveText('Введите корректный адрес почты');
await expect(email).toHaveAttribute('aria-invalid', 'true');
await expect(email).toBeFocused();

Текст сообщает способ исправления, атрибут обозначает ошибку поля, а фокус возвращает читателя к месту исправления. Это разные части одного результата. Видимый текст без связи с полем может быть труднее обнаружить; фокус без объяснения оставит причину неизвестной. Проверка не сводит понятность ошибки к единственному изменению DOM.

Исправленный ввод и HTTP-ответ

Заменим значение на student@example.invalid. Это учебный адрес из зарезервированного домена; лаборатория не пытается доставлять письма. Перед нажатием установим ожидание ответа, соответствующего отправке:

await email.fill('student@example.invalid');
const responsePromise = page.waitForResponse(response =>
  response.url().endsWith('/api/feedback') &&
  response.request().method() === 'POST');
await form.getByRole('button', { name: 'Отправить сообщение' }).click();
const response = await responsePromise;
expect(response.status()).toBe(201);
await expect(form.getByRole('alert')).toBeHidden();
await expect(page.getByTestId('feedback-status'))
  .toHaveText('Сообщение принято учебным сервером');

Ожидание зарегистрировано до действия, чтобы быстрый ответ не прошёл незамеченным. Условие включает и путь, и метод. На настоящей странице один адрес может обслуживать разные операции, поэтому одной строки URL не всегда достаточно. Здесь известно, что отправка формы выполняет POST к конкретному endpoint.

Статус 201 связан с договорённостью учебного API о принятом запросе. Текст интерфейса проверяется отдельно: получение ответа ещё не означает, что программа объяснила результат человеку. Например, ошибка обработчика после fetch могла бы оставить старое сообщение, хотя сервер уже вернул нужный статус. Совместное наблюдение различает сетевой результат и его отображение.

Регистрировать ответ после нажатия было бы опасно даже с дополнительной задержкой. Задержка не возвращает уже прошедшее событие. Документация сетевых событий Playwright объясняет работу наблюдений за запросами и ответами; здесь применяем её к одной операции, сохраняя связь с действием формы.

Клиентская ошибка и серверная ошибка

Неправильная почта в первом шаге отклоняется до отправки. Это удобно для человека, но не является защитой серверного API. Можно отправить запрос напрямую, изменив JavaScript или вовсе не открывая форму. Поэтому /api/feedback повторно проверяет значения и возвращает 400 для недопустимого ввода. В отдельном уроке мы исследуем именно этот ответ.

Клиент использует проверку стандартного поля, а учебный сервер — небольшое регулярное выражение и непустое сообщение. Это не универсальная проверка всех возможных почтовых адресов. Формат лаборатории выбран для понятных входов, а не для доказательства доставки письма или существования ящика. Не следует переносить упрощённую проверку в продукт без определения настоящих требований.

Если сервер недоступен, приложение пишет «Сервер недоступен». Если сервер вернул статус, отличный от 201, появляется «Сообщение не принято». Это ещё два состояния, которые можно воспроизвести отдельной подменой. Они не включены в текущий основной путь, потому что его результат — исправление поля и принятие допустимого сообщения. Позже подобные варианты удобно оформлять небольшими независимыми тестами.

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

Разбор состояния после исправления

Обработчик в начале каждой отправки скрывает прежнюю ошибку и снимает aria-invalid. Если правильное значение принято, прежний alert должен оставаться скрытым. Это важная часть пути: человек уже исправил проблему, поэтому устаревший сигнал не должен противоречить новому результату. Проверка видимости после успешного ответа обнаружит такое рассогласование.

Фокус после успешного запроса в этой версии не переносится автоматически. Мы не утверждаем обратное и не добавляем ожидание, для которого отсутствует поведение приложения. Если продукт решит выделять подтверждение фокусом, это станет отдельной договорённостью с собственным доступным элементом. Проверочный код должен следовать принятому решению, а не случайно навязывать его.

Для самостоятельного варианта оставьте сообщение пустым при допустимой почте. Ожидается текст «Добавьте сообщение» и фокус в соответствующем поле. Не сравнивайте этот текст с alert почты: у него другой источник и другой элемент результата. Такое различие помогает строить локаторы по назначению, сохраняя понятную структуру формы.

Мы получили связный сценарий исправления: недопустимый ввод обозначен, нужное поле получает фокус, исправленная отправка получает ожидаемый HTTP-ответ и понятное подтверждение. Следующий урок рассмотрит управление без указателя мыши. Там будут важны не только значения полей, но и порядок фокуса между ними.

Значение поля после ошибки

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

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

В основном примере сообщение короткое и без специальных символов. Мы не утверждаем, что проверили предел длины, HTML, Unicode или защиту от злоупотреблений. Каждое из этих требований нуждается в согласованном вводе и результате; неправильная почта не является универсальной проверкой всей формы.