Прогоните интерфейс в браузере и докажите каждый шаг
Методология тестирования веб-приложений в браузере: навигация, формы, скриншоты, консольные ошибки, адаптивность. Используйте для систематической проверки UI/UX в разных браузерах и устройствах.
Как агент работает
Инструмент `browser_interact` ведёт постоянный Chromium: вкладка, cookies и localStorage живут между вызовами. Доступны `navigate` с ожиданием `domcontentloaded` и окном тишины DOM в 250 мс, но не дольше 3 секунд суммарно, `snapshot` с деревом доступности, `act` по интенту, `click`, `fill`, `type`, `select`, `check`, `press_key`, `upload_file`, `scroll` шагом ровно 500 px, `wait` по CSS-селектору, `screenshot` и `back`. В десктоп-приложении подключается локальный браузер и набор `mcp__chrome-devtools__*`.
Адресация идёт через три двери. `ref` быстр и точен, но номера перенумеровываются на каждом снимке и действительны до первой мутации DOM, после неё нужен свежий `snapshot`. `act` разрешает интент по дереву, при неудаче помечает до 80 элементов красными бейджами и выбирает элемент по картинке; успешный `act` кэшируется на 7 дней по ключу «задача + домен + хэш интента», а три промаха подряд выбивают запись. CSS-селектор допустим ровно в одном месте: в действии `wait`.
Доказательством служит `outcome`: вердикт «unchanged» (DOM не шелохнулся) это кандидат в дефект номер один, «unknown» успехом не считается, а для полей ввода движок читает значение обратно и показывает mismatch: так ловятся маска, режущая хвост телефона, и ИНН, обрезанный до 10 знаков там, где нужно 12. Сетевые коды читаются по смыслу: 401 и 403 посреди сценария означают протухшую сессию, 404 на API рассинхрон релизов фронта и бэка, 5xx требует `request-id` и точного времени с поясом.
Адаптивность проверяется на 320–360, 375–390, 768 и 1280 px, причём горизонтальный скролл ищется измерением ширины документа против окна, а не глазом. Дефекты раскладываются по шкале: S1: деньги и данные, S2: сценарий непроходим или проходим обходом, S3: сломанное представление, S4: косметика. Чего Chromium не покажет: мобильный Safari с его `100vh`, автозумом при `font-size` меньше 16 px и ограничениями на сторонние куки, и эти дефекты остаются за пределами прогона.
Инструмент: browser_interact. Он ведёт постоянный Chromium: вкладка живёт между вызовами, cookies и localStorage сохраняются между шагами сценария.
navigate(url): переход:domcontentloaded+ тишина DOM; баннеры и модальные окна остаются на странице.snapshot: дерево доступности с номерамиref.act(intent): интент на естественном языке → элемент → действие.click,hover,check(ref): клик, наведение, отметка чекбокса.fill,type,select(ref+value): значение целиком, посимвольно, выбор опции.press_key(key):Enter,Tab,Escape,ArrowDown.upload_file(ref+file_path): файл вinput[type=file].scroll(direction): шаг колеса ровно 500 px.wait(selector): ждёт появления CSS-селектора.screenshot: кадр видимой области;back: история назад.
timeout: 1–120 с, по умолчанию 30, на одно действие. Каждый успешный шаг возвращает кадр в чат, кроме заполнения поля секретом сессии: там кадр гасится намеренно. Ключевое ограничение: вьюпорт и user-agent в облаке фиксированы: headless Chromium с UA десктопного Windows Chrome. Сменить размер окна или притвориться iPhone этим инструментом нельзя.
2. Вторая поверхность: локальный браузер
В приложении для компьютера browser_interact не водит страницу сам, а запускает браузер на компьютере пользователя и отвечает «подключён». Дальше доступны mcp__chrome-devtools__*: navigate_page, take_snapshot, click, fill_form, wait_for, take_screenshot, resize_page, emulate, list_console_messages, list_network_requests, performance_start_trace.
Брейкпоинты, полный лог консоли и сетевой лог доступны только там. Прогнал в облаке, так и пиши: «вьюпорт не менялся, сетевой лог недоступен».
3. Как читать снимок страницы
snapshot возвращает не HTML, а дерево доступности:
Потолок: 200 элементов и 8 уровней вложенности, поэтому длинная таблица обрежется: нет нужного элемента, делай scroll к нему. Три сигнала важнее самого дерева:
4. Адресация элементов: три двери
ref: быстро и точно, но привязан к узлу, который его получил: клик по строке списка → список перерисовался → старый ref отвечает отказом «устарел», а не попадает в соседа.
act с интентом: движок сам снимает страницу и отдаёт дерево модели-наблюдателю; если та не справилась, включается зрение: страница помечается красными бейджами (до 80 элементов), элемент выбирается по картинке. Действие выводится из роли, а не из твоего глагола: link/button/tab → click; checkbox/radio/switch → check; combobox/listbox/menu → select с подписью опции; textbox/searchbox/spinbutton/slider → fill. Значение вкладывай в интент («заполнить поле Телефон значением +79991234567») или передавай value: действие ввода без значения приходит отказом.
CSS-селектор доступен ровно в одном месте: action: "wait". Селектор проверяет наличие, а не намерение, поэтому кликать по нему нельзя.
Почему локатор по видимому тексту хрупкий
- Одна кнопка живёт под тремя подписями: «Войти» / «Вход» / «Login» (язык, A/B-тест, состояние авторизации); «ё» пишут и не пишут («Всё»/«Все»).
- Числа приходят с неразрывным пробелом (U+00A0) и узким неразрывным (U+202F):
1 200 ₽на экране и в DOM не совпадут при обычном сравнении. - Русский текст на 15–30% длиннее английского оригинала, подпись обрезается: в DOM «Подтвердить оформление», на экране «Подтвердить оформ…». А
text-transform: uppercaseдаёт «ОФОРМИТЬ» на экране при «Оформить» в DOM.
Отсюда: опирайся на роль + доступное имя, а не на видимую строку: именно эта пара кэшируется движком как устойчивый ключ и переживает смену регистра и классов. Элемент без доступного имени это уже дефект доступности; фиксируй его, а не обходи скриншотом.
Успешный act кэшируется на 7 дней по ключу «задача + домен + хэш интента» и проигрывается мимо модели; три подряд промаха выбивают запись. Поэтому формулируй интент одинаково на всех прогонах, а падение первого прогона после деплоя, переименовавшего кнопку, перепроверяй тем же интентом: промах дважды значит, что имя действительно изменилось, и это находка.
5. Ожидание готовности, а не времени
navigateждётdomcontentloaded, затем окно тишины DOM: 250 мс без мутаций, но не дольше 3 с суммарно. Медленный XHR за данными таблицы в это окно не попадёт.- После действия движок ждёт короткое окно (клик 500 мс, наведение и клавиша 300 мс) и в нём измеряет мутации. Явное ожидание:
waitс селектором и своимtimeout.
6. Доказательство эффекта: поле outcome
| Вердикт | Значение | Действие |
|---|---|---|
navigated | Страница сменила документ | Сверь url и title |
changed | DOM изменился (N DOM mutation(s)) либо действие открыло вкладку или начало скачивание | Проверь, что изменилось ожидаемое |
unchanged | Реакции в DOM нет | Кандидат в дефект №1 |
unknown | Замер не удался (canvas/WebGL, клик по координатам) | Проверь по снимку/кадру, успехом не считай |
unchanged: самая ценная строка вывода. Причины по убыванию частоты: обработчик не навешен (кнопка-муляж), элемент перекрыт прозрачным оверлеем, клик ушёл в родителя, disabled без визуального признака, обработчик упал до первой мутации. У canvas и iframe действие могло сработать и без мутаций основного документа.
Вердикт для полей ввода
Для fill/type/select/check движок читает значение обратно:
filledс хвостомfield value is now "+7 (999) 123-45-67" (matches the requested value): норма.filledс хвостом... but "+79991234567" was requested (mismatch): маска или валидатор режут ввод. Российская классика: телефон с маской теряет хвост, ИНН обрезается до 10 знаков там, где нужно 12, поле даты не принимает31.12.2026, ожидаяГГГГ-ММ-ДД, поле суммы теряет копейки.checkedс хвостомcheckbox is now uncheckedпослеcheck: переключения не было, перекрытие или программный сброс.
Значение ставится нативным сеттером с событиями input и change: маски и contenteditable заполняются корректно, disabled/readonly дают явную ошибку вместо таймаута. Но это не посимвольный набор: валидация и автодополнение на keydown (ДаData, подсказка ФИО) не сработают, там нужен type с задержкой 30 мс на клавишу.
Шум
Отдельным списком «мелочи» или мимо отчёта: предупреждения про key в списках React, депрекейшены, «Download the React DevTools», 404 на favicon.ico, non-passive event listener, сообщения расширений.
Симптом
Всегда указывай, на каком шаге сценария ошибка появилась: та же строка на главной и на шаге оплаты стоит разного. Секреты в отчёт не переноси, кадр такого шага движок гасит сам.
8. Сетевые ошибки и как их читать
Сетевого лога в облаке нет: дефект видно по симптому в UI либо проверяешь снаружи: sandbox_bash с curl даёт статус, заголовки и редиректы. Локально есть list_network_requests.
- 4xx: сломан контракт на клиенте.
401/403посреди сценария: протухла сессия или не хватает прав роли; смотри, показывает ли UI «войдите заново» или молча пустую таблицу (второе дефект).404на API: рассинхрон релизов фронта и бэка.400/422на отправке формы: дефект валидации, а не пользователя. - 5xx: дефект сервера. Сними
request-id/trace-idи точное время с поясом, иначе запрос не найдут в логах. - CORS.
Access to fetch at ... blocked by CORS policy: причина в продолжении фразы: нетAccess-Control-Allow-Origin; предзапросOPTIONSответил не 2xx; заголовок внеAccess-Control-Allow-Headers; запрос сcredentials, а сервер ответил*вместо домена. Проверка снаружи:curl -i -X OPTIONSсOriginиAccess-Control-Request-Method. Частый случай: прод настроен, а стенд нет. - Mixed content. HTTPS-страница тянет ресурс по HTTP: браузер блокирует молча, в UI просто нет картинки или не работает виджет.
- Оборванный запрос. Статус 0,
ERR_CONNECTION_RESET,net::ERR_FAILED,canceled. Источника три: пользователь ушёл со страницы (норма),AbortControllerпо таймауту, запрос убил прокси; отличай по тому, была ли навигация. Оборванный POST оплаты это S1: клиент не знает, прошёл платёж или нет. - Заблокированный домен. Отказ навигации запоминается: повторный переход вернёт отказ без обращения, не долби. Для кабинетов Ozon и Wildberries отказ штатен: они закрыты от браузерной автоматизации, данные берутся API-коннектором, а не браузером.
429там же: назови в отчёте, чей это лимит: свой бэкенд или внешний API площадки.
9. Адаптивность: брейкпоинты
Вьюпорт меняется только локально (resize_page, emulate); в облаке помечай как непроверенное.
| Ширина | Кого моделирует | Что смотреть |
|---|---|---|
| 320–360 | Бюджетный Android | Горизонтальный скролл, обрезанные подписи, таблицы без обёртки |
| 375–390 | Массовый iPhone | Нижняя панель поверх контента, safe-area, модалка выше экрана, position: fixed при открытой клавиатуре |
| 768 | Планшет вертикально | Точка переключения меню: бургер уже есть, десктопная навигация ещё не спряталась |
| 1280 | Рабочий ноутбук | Базовая эталонная вёрстка |
Горизонтальный скролл ищут измерением: сравни ширину документа и окна через evaluate_script. Виновники по частоте: длинное слово без переносов (артикул, email, номер счёта), таблица цен, min-width карточки.
10. Мобильный Safari: чего не будет в Chromium
Ни облако, ни локальный Chrome не WebKit; эмуляция размера не эмуляция Safari. Всё ниже помечай «требует проверки на устройстве».
100vhвключает адресную строку: нижняя кнопка уезжает под панель браузера (лечится100dvh/svh), а фокус вinputсfont-sizeменьше 16px вызывает автоматический зум, который пользователь сам не отменит.- Ограничения на сторонние куки бьют по авторизации через редирект и по оплате с возвратом на сайт: пользователь возвращается разлогиненным.
11. Дефекты, видимые только в браузере
Сдвиг макета при загрузке шрифта
Кириллический веб-шрифт тяжелее латинского (лишний набор глифов): страница успевает нарисоваться системным и прыгает. Ловля: navigate, сразу screenshot, затем wait по признаку готовности и второй screenshot. Кнопка переехала, и клик в промежутке попадёт мимо.
Повторная отправка формы по двойному клику
Два click подряд без ожидания. Признак дефекта: у обоих outcome вида changed: два заказа, два платежа, два письма. Кнопка обязана уйти в disabled на первом клике; там, где есть деньги, это S1.
Диалоги
В облаке alert/confirm/prompt по умолчанию отклоняются, текст возвращается в dialogs.
Действие могло не состояться. Для ветки принятия повтори тот же вызов с accept_dialog=true, если
это соответствует проверяемому сценарию; результат проверь отдельно. Локально обрабатывай диалог
явно через handle_dialog. В отчёте укажи выбранную ветку: автоматическое отклонение не доказывает,
что сайт не показал подтверждение.
13. Шаблон карточки дефекта
Шкала серьёзности
- S1, деньги или данные: дубль платежа или заказа по двойному клику, оборванный POST оплаты с неизвестным исходом, потеря заполненной формы, белый экран после деплоя (
ChunkLoadError). - S2, сценарий непроходим или только обходом: кнопка без реакции (
unchanged), маска режет значение и заявку не отправить, модалка не закрывается,401без внятного сообщения. - S3, ломается представление: горизонтальный скролл на мобильном, контент под фиксированной панелью, сдвиг макета при загрузке шрифта, залипший
:hover. - S4, косметика: обрезанная подпись, шумные предупреждения консоли, отсутствие
alt. Невидимый фокус при Tab это S3, если интерфейсом пользуются с клавиатуры.
Карточка годна, если по ней дефект повторит человек, не видевший твоего прогона: хватает ли окружения, точных шагов и точного времени.
Похожие навыки
Попробуйте этот навык
Зарегистрируйтесь и используйте навык «Тестирование в браузере» бесплатно.