Сценарий управления клавиатурой
В предыдущем уроке мы проверили форму, заполняя поля и нажимая кнопку через API Playwright. Эти действия удобны для исследования результата, но не подтверждают, что до элементов можно добраться с клавиатуры в ожидаемом порядке. Посетитель, использующий Tab и Enter, проходит другой путь взаимодействия.
Теперь проверим часть этого пути на форме поиска: поле запроса, выбор раздела, кнопка и результат. Это не полный аудит доступности, а конкретный сценарий клавиатурного управления. Файлы lesson-08/expected находятся в архиве серии. Браузер лаборатории пока не запускался; описанные состояния остаются ожидаемыми.
Начальная точка и порядок фокуса
Форма поиска содержит сначала поле «Запрос», затем стандартный select «Раздел», затем кнопку «Найти». В HTML этот порядок совпадает с видимым расположением. Нет положительных значений tabindex, которые искусственно переставляли бы элементы. Поэтому можно проверить переход между соседними интерактивными элементами без расчёта всех ссылок хедера.
Сценарий начинает с явного фокуса в поле запроса. Это осознанная граница: мы проверяем движение внутри формы, а не путь от начала документа. В полном наборе полезно отдельно проверить skip-ссылку и главную навигацию, но не стоит молча считать их покрытыми коротким сценарием поиска.
const query = page.getByLabel('Запрос', { exact: true });
const topic = page.getByLabel('Раздел', { exact: true });
const submit = page.getByRole('button', { name: 'Найти', exact: true });
await query.focus();
await query.press('Tab');
await expect(topic).toBeFocused();
Встроенная фикстура уже дождалась четырёх курсов. Поле запроса пустое. Метод focus задаёт стартовую точку, а press('Tab') выполняет следующий клавиатурный шаг. Утверждение о фокусе проверяет, куда действительно перешло управление. Если разработчик добавил между полем и разделом новый интерактивный элемент, ожидание перестанет соответствовать документу.
Такой сигнал нужно разобрать по смыслу. Дополнительная полезная кнопка может быть намеренным изменением формы; случайно фокусируемая обёртка — ошибкой вёрстки. Простое увеличение числа Tab в тесте скроет различие. Сначала выясняют, должен ли новый элемент входить в путь пользователя, и только после этого меняют договорённость.
Выбор пункта стандартного элемента
В этой лаборатории выбран Chromium для настольного сценария. Начальное значение select — all, следующий пункт — frontend. Используем стрелку вниз и проверим полученное значение:
await topic.press('ArrowDown');
await expect(topic).toHaveValue('frontend');
await topic.press('Tab');
await expect(submit).toBeFocused();
await submit.press('Enter');
В предыдущих уроках мы применяли selectOption, потому что задачей был результат фильтра. Здесь важно клавиатурное действие, поэтому переход к нему явный. Стандартные элементы могут иметь особенности управления на разных платформах и браузерах. Этот пример не обещает идентичный набор клавиш для любого мобильного устройства или собственного выпадающего компонента.
После Enter на кнопке ожидается отправка формы без перехода к другой странице: обработчик предотвращает стандартную навигацию и обновляет список. Проверим статус «Найдено курсов: 2» и названия «Основы HTML», «Современный JavaScript». Так мы связываем путь фокуса с прежним пользовательским результатом, а не заканчиваем проверку только на нажатой клавише.
Операции клавиатуры и фокуса описаны в Locator API. Для понимания результата важнее HTML-семантика: настоящая кнопка активируется привычной клавишей, поле получает фокус, стандартный выбор имеет доступное имя. Превращение этих элементов в произвольные кликабельные блоки потребовало бы дополнительного поведения и проверки.
Что автоматическое утверждение не показывает
toBeFocused подтверждает активный элемент документа. Оно не сообщает, достаточно ли заметен контур фокуса для человека. В CSS лаборатории задан зелёный outline для :focus-visible, но автоматическое сравнение состояния не измеряет удобство его восприятия на каждом фоне. Для такого вывода нужно отдельно смотреть интерфейс в соответствующих условиях.
Аналогично доступное имя поля не доказывает, что все сообщения понятны при чтении с экрана. Проверка роли и имени может выявить их отсутствие, но полноценный пользовательский путь с вспомогательной технологией содержит дополнительные наблюдения. Мы сохраняем границу курса: небольшой воспроизводимый сигнал помогает находить регрессии, а не заменяет все способы оценки.
Скрытая на узком экране навигация также должна менять доступность элементов. Наш текущий сценарий выполняется на ширине 1280 и не открывает меню. В следующем уроке зададим ширину 390, нажмём кнопку меню и исследуем его состояние. Нельзя по настольной проверке формы заключить, что весь мобильный хедер доступен клавиатурой.
Порядок фокуса может нарушиться, даже если мышью всё работает. Например, tabindex="-1" у стандартного select исключит его из последовательного обхода. Пользователь перейдёт сразу к кнопке, и проверка после первого Tab обнаружит расхождение. С другой стороны, принудительный focus всё ещё смог бы поставить управление в select; именно поэтому тестируем переход, а не только возможность отдельного фокуса.
Отправка и повторение пути
Для самостоятельного варианта после завершения фильтра верните фокус в запрос и введите JavaScript с помощью клавиатурного API. Пункт frontend уже выбран, поэтому отправка должна дать один курс. Здесь исходное состояние отличается от первого шага: новый сценарий должен либо явно принять прежний выбор, либо начать заново в собственном контексте. Не следует предполагать, что соседняя проверка обязательно успела выбрать раздел.
В основном файле оставлен один завершённый путь. Это упрощает диагностику: начальная форма, переход к выбору, изменение значения, переход к кнопке, отправка, две карточки. Каждое ожидание относится к следующему звену. Если фокус остановился не там, дальнейшее нажатие Enter могло бы выполнить другое действие, поэтому ранняя проверка помогает объяснить причину итоговой ошибки.
Некоторые интерфейсы отправляют поиск по Enter прямо из поля запроса. У нашей формы стандартная отправка также возможна, но это отдельный путь. Он не проверяет доступность пункта раздела и кнопки через Tab. Оба сценария могут быть полезны, если оба обещаны читателю; один нельзя выдавать за проверку другого только потому, что конечный список одинаков.
Принципы оценки доступности в браузерных проверках представлены в Accessibility testing. Мы используем один из практических сигналов: непрерывную цепочку фокуса и активации. Когда она приводит к двум правильным курсам, определённая задача поиска выполнена клавиатурой в заданном окружении. Дальше добавим другую независимую переменную — размер области страницы.
Проверка клавиши должна сопровождаться наблюдением эффекта, потому что доставка события не гарантирует ожидаемое действие. В нашем примере после ArrowDown явно сравнивается значение frontend, а после Enter — состав списка. Если среда иначе обработала стандартный выбор, раннее ожидание значения поможет отличить это от ошибки фильтра.
Для пользовательского собственного списка порядок клавиш задаётся его моделью. Там может потребоваться открытие, перемещение по пунктам и отдельное подтверждение. Нельзя автоматически переносить наш короткий путь стандартного select на такой компонент только потому, что оба визуально похожи на выпадающее меню.