CSS и XPath — отстой. Секрет стабильных автотестов в test-id
По фактам: почему CSS и XPath — путь в ад, а test-id — спасение. В статье — реальные советы, как договориться с командой, внедрить test-id и писать автотесты, которые не разваливаются каждую пятницу.
Вступление
Вы вообще в курсе, что такое CSS и XPath селекторы? Ну конечно в курсе — раз уж кликнули на эту статью, наверняка пережили хотя бы один из тех унылых споров в духе «а что лучше: CSS или XPath?» Спойлер: ни то, ни другое. Все эти разговоры — просто шум, рожденный из некомпетентности. Вот эти бесконечные обсуждения — «а XPath может по тексту», «а CSS быстрее», «а вот тут индекс нужен»... Да какая, к чёрту, разница, когда можно просто использовать тестовые идентификаторы?
Серьёзно. Если у элемента есть тестовый идентификатор — всё, точка. Найти его можно быстро, стабильно и без плясок с бубном вокруг селекторов. А выбор между CSS и XPath становится вообще неважным. Это уже вкусовщина, типа «а ты как макароны солишь — до или после закипания воды?». Умным людям не до таких споров.
Возникает логичный вопрос: если всё так круто с тестовыми идентификаторами, почему о них не кричат с каждого угла? Почему в 2025-м году тесты всё ещё ломаются от смены цвета кнопки? Ответ простой: либо люди не знают, либо не умеют. Иногда и то, и другое. В этой статье мы как раз это исправим. Покажем, как правильно и без боли внедрять тестовые идентификаторы в фронтенд‑приложении. Без теории ради теории — только практика и здравый смысл.
И давайте скажем это вслух: если ваши автотесты сыпятся из‑за смены классов, цвета, или позиции элемента — виноваты не разработчики, не продукт, не космос, не ретроградный Меркурий. Виноваты вы. Да‑да, вы, QA Automation инженер, который решил «ну тут же можно взять по div:nth-child(42), норм же работает». Нет, не норм. Вы создали флак, вы допустили нестабильность, вы наплодили технический долг в автотестах. Хотите стабильности? Учитесь писать тесты правильно. Хотите гордиться своими автотестами, а не прятать их отчеты под стол? Добро пожаловать — сейчас научим.
Эта статья — для всех: от автоматизаторов, уставших от флаков, до фронтендеров, которые хотят помочь команде и не видеть, как в pull request прилетает «починил тест» вместо нормального фидбека.
Что круче — CSS или XPath?
Поехали без прелюдий. Вот эти бесконечные дискуссии «а что круче — CSS или XPath?» — это как спорить, чем лучше копать яму: ложкой или вилкой. Забавно? Вот и мне смешно. Потому что оба варианта — костыли, если вы изначально подходите к задаче неправильно.
Ни CSS, ни XPath не являются оптимальными инструментами для UI‑автотестов. Вообще. Забудьте. Правильный, взрослый, стабильный подход — это кастомные атрибуты типа data-test-id. И когда вы их используете, становится абсолютно по барабану, пишете вы CSS или XPath — элемент будет найден быстро, чётко, без танцев и отрыжек селекторной магии. Тут уже дело не в типе селектора, а в том, на что вы этот селектор навешиваете.
Если вы всё ещё цепляетесь за текст, классы, nth-child, динамически сгенерированные ID, то, простите, не нужно потом жаловаться, что у вас «тесты флакают», «после рефакторинга всё упало» или «а что случилось, я ничего не менял». Сюрприз: вы сами себе враг. Вы выбрали путь страдания.
Возьмите мобильную автоматизацию, например. Там никто даже не думает писать тесты без тестовых идентификаторов. Просто потому, что нельзя. А в вебе исторически можно схалтурить: закинуть на скорую руку CSS или XPath локаторы и вроде как работает. Ключевое слово — «вроде». Работает — пока не перестаёт. А потом боль, костыли, и попытка понять, почему из‑за смены названия класса у вас теперь валится весь регресс.
И чем дальше, тем хуже. Проект обрастает десятками «временно рабочих» CSS/XPath локаторов, и в какой‑то момент вы уже не можете их нормально отрефакторить. Потому что, внимание, тесты становятся заложниками качества и стабильности селекторов. В итоге даже самый простой тест превращается в квест с подземельями, багами и слезами автоматизатора.
CSS и XPath: как НЕ надо
Я не буду тратить ваше и своё время на бессмысленное «сравнение плюсов и минусов» CSS и XPath. Это всё разговоры ради разговоров. Хотите правду? Они оба — не то, чем вы должны пользоваться. Вместо цирка про «что быстрее», давайте честно пройдёмся по главным болячкам этих подходов. Спойлер: всё плохо.
1. Завязка на текст: «А где кнопка?»
О, классика! Работает… до первой правки текста. А потом:
- дизайнер захотел вместо «Отправить» — «Отослать»
- UX‑специалист вспомнил про «Повышение конверсии»
- продакт‑менеджер включил английский язык
- а вы — включили панику
Итог: тесты отвалились. Причём интерфейс-то не поменялся. Только слова. А вы всё ещё ищете кнопку по её бывшему имени, как бывшую — по старому нику в Telegram.
2. Глубокая вложенность: «Интерфейс немного изменился — тесты умерли»
Красота? Нет. Хрупкий кусок боли. Вставили лишний div? Удалили лишний блок? Изменили порядок? Поздравляю, вы снова чините автотест, который не обязан был сломаться.
3. Классы и стили: «Они же стабильны… ага, конечно»
Никогда не забывайте: классы не для тестов, они для внешнего вида. Они меняются. Часто. Не потому что кнопка исчезла, а потому что large больше никому не нравится. А вы снова страдаете. Потому что решили строить автотесты на песке.
4. Случайные ID: «Каждый билд как русская рулетка»
5. Читаемость: «Что это вообще такое?»
Даже если этот локатор работает — понять, что он делает, невозможно.
А теперь посмотрите на это:
Видите разницу? Один селектор — как шифр из «Игры в кальмара». Другой — понятен даже вашему проджекту.
Что такое тестовые идентификаторы?
Всё просто: тестовые идентификаторы — это специальные атрибуты в HTML, которые нужны не для фронтенда, не для верстки, а исключительно для автотестов.
Они не влияют на внешний вид, поведение или UX. Их задача — быть якорем. Стабильным, читаемым и предсказуемым.
Как их называть? Да как хотите:
- data-test-id
- data-testid
- qa-id
- test-id
- data-qa
- хоть data-holy-button
Главное — чтобы было:
- однозначно (один идентификатор — один элемент)
- стабильно (не зависит от текста, стилей, порядков)
- понятно (без m7fg9btn99 и abc123)
Некоторые фреймворки даже подсказывают «дефолтные» названия. Например, Playwright из коробки умеет работать с data-testid. Но и это не догма — в конце концов, вы не роботы. Вы инженеры. Назовите как угодно — главное, начните использовать.
Почему все про них знают, но почти никто не использует?
Потому что, чёрт возьми, это не халява. Нужно:
- понять, как работает фронт
- договориться с командой
- договориться с самимсобой, что «быстро и криво» — это путь в ад
А ещё потому что проще натыкать 20 XPath'ов и свалить с работы пораньше. Только потом те же 20 XPath'ов разнесёт первым же редизайном. А виноват кто? Правильно — вы.
Это как раз и отличает настоящего QA Automation‑инженера от человека, который «просто пишет тесты» — желание строить фундамент, а не временные палатки.
Зачем это вообще?
Вставлять data-test-id в интерфейс — это не «ещё одна фича», это фундамент надёжной автоматизации UI‑тестов. Если вам нужны стабильные, предсказуемые и легко поддерживаемые тесты — это не рекомендация, это must-have.
Вот зачем это работает и почему без него — боль:
1. Стабильность и предсказуемость
CSS/XPath-подходы — как игра в рулетку: чуть поменяли DOM или порядок элементов — всё, локатор умер. А data-test-id живёт, пока вы явно не убрали элемент. Падает только по делу, а не из-за новой обёртки в div.
2. Не зависят от внешнего вида
Классы меняются — стили меняются — верстальщик захотел «посвежее» — CSS/XPath‑селекторы снова мертвы. Атрибут data-test-id изолирован от всего этого. Он не для дизайна. Он для тестов. Его не трогают «просто так».
3. Устойчивость к рефакторингу
Если фронтендер переносит кнопку в другой компонент, но оставляет data-test-id — тест даже не заметит изменений. Без него — «404 Not Found», даже если кнопка визуально на месте.
4. Улучшает коммуникацию
Когда разработчиквидит в DOM data-test-id, он сразу понимает: «Окей, это тестовый якорь, трогаю аккуратно или обсуждаю с QA». Это культура. Это осознанность. Это уменьшает количество внезапных «почему всё упало?!».
5. Чистота и читаемость
Что выглядит понятнее?
против:
Первые — магия и боль. Второй — понятный, читаемый якорь, даже без документации. Такие локаторы приятно писать и удобно поддерживать.
6. Экономия времени на дистанции
Да, на старте CSS/XPath кажутся быстрее. Но дальше — начинается ад: правка верстки → 15 упавших тестов → день на фикс.
С data-test-id:
- тесты не разваливаются
- не приходится «охотиться» за элементами заново
- не нужна реанимация локаторов после каждого спринта
Это инвестиция, которая окупается с первых недель и сохраняет нервы всей команде.
Безопасно ли это?
Ах да, классический довод: «Не‑не‑не, не трогай DOM! Это сломает рендеринг, просадит перформанс и ухудшит UX!»Перевод: »Я просто не хочу, чтобы QA лез в мой священный фронтенд.»
Ну давайте разложим по фактам. Потому что истина тут простая, как
без class.
1. «Сломает стили»
2. «Просадит перформанс»
Серьёзно? Атрибут весом в 15 байт замедлит ваше React-приложение? Вы там случайно не через useEffect рисуете галактику? Измеряем в наносекундах, а обсуждаем как будто у вас сервер под нагрузкой рухнет от одного data-test-id.
3. «Ухудшит UX»
А, ну конечно, пользователь такой открывает страницу… и испытывает острый приступ UX-дискомфорта от атрибута, который он даже не видит. Зато мы все знаем: если у UX что-то не так — это точно data-test-id виноват, а не логика или контент.
4. «Это видно поисковикам! SEO пострадает!»
Во-первых, не пострадает. Во-вторых, если очень хочется — можно даже сделать умный шаблон, где data-test-id → aria-label, и будет только лучше. Так что это уже не про SEO, а про отмазки.
5. А что на самом деле?
- Не влияет на стили
- Не влияет на производительность
- Не отображается пользователям
- Не мешает разработке
- Не ломает компоненты
- Не вызывает глобальное потепление
Это спокойный, неагрессивный, предельно предсказуемый способ дать автотестам якорь. И если ваш фреймворк умеет в HTML — значит он точно умеет в data-test-id.
Если разработчик против data-test-id — скорее всего, он просто не хочет, чтобы вы могли зацепиться за его DOM. Но это уже не про производительность. Это про территорию. И да, она теперь и ваша тоже.
Как расставить тестовые идентификаторы?
Окей, пора перейти от слов к делу. Как именно ставить эти ваши data-test-id, если вы, скажем, не фронтенд-разработчик, а просто честный автоматизатор с хорошими намерениями?
На первый взгляд может показаться, что это что-то из разряда «требуется знание React на уровне Senior++», но на деле — это базовый скилл, как открыть DevTools или запустить тест.
Правда жизни
Каждый день тысячи QA Automation инженеров по всему миру просто открывают HTML, вставляют data-test-id="что-то-понятное" — и всё работает. Даже в мобильной разработке (да-да, с этими вашими Flutter, Jetpack Compose и SwiftUI), где всё как будто из магии и анимаций, идентификаторы всё равно ставят. Это уже не «хак», это индустриальный стандарт.
Шаг 1. Установка Node.js
Да, давайте начнём с азов. Если вы собираетесь трогать хоть один байт фронтенд-кода — вам нужен Node.js. Почему?
Потому что:
Как установить Node.js?
Не буду пересказывать документацию (она шикарна, кстати). Просто заходите сюда: https://nodejs.org/en/download. Выбираете свою ОС, кликаете мышкой — и всё. Node.js сам всё поставит, и бонусом даст вам npm — пакетный менеджер.
Шаг 2. Установка проекта
Ну что, пора, наконец, залезть в проект. Потому что прежде чем что-то в нём менять — будь то стили, компоненты или наши драгоценные data-test-id — надо его хотя бы скачать. Да-да, просто «что‑то поменять на проде» не получится. Сначала к себе на комп, пожалуйста.
Клонируем проект
Для примера будем использовать учебный проект: https://github.com/Nikita-Filonov/qa-automation-engineer-ui-course. Клонируем его как нормальные люди:
Установка зависимостей
Перед тем как нажимать на кнопочки и запускать фронт, надо сначала оживить проект. Потому что пока это просто папка с непонятным node_modules в надежде, что они появятся по магии. Не появятся. Устанавливаем зависимости.
- Если в корне есть файл yarn.lock → значит, используем yarn
- Если там package-lock.json → значит, используем npm
Примеры:
Для yarn:
Для npm:
Ждём немного... Да, установка может занять минутку. Иногда — три. Иногда — вечность, если у вас Wi-Fi в стиле «ловлю соседа на лестничной клетке». Но это нормально. Главное — после установки у вас появится волшебная папка node_modules, и проект оживёт.
Запускаем проект
И вот тут начинается «веселье». Возможно, вы ожидали какую‑то одну универсальную команду вроде npm start, и она сработает. Иногда. Если звёзды сойдутся. Но чаще всего:
- В проекте используется нестандартная структура
- У команды совсем другое имя (например, app:start, dev, run, frontend:start)
- Включён TypeScript, монорепа или ещё какое-нибудь веселье
Что делать? Открываем package.json. Это священный грааль для любого Node.js-проекта. В нём есть блок scripts — и именно там указаны все команды, которые можно запускать. Вот как он может выглядеть:
Если не знаете, что запускать — не страдайте, просто спросите у фронтенд-разработчиков. Серьёзно, они не кусаются (если спросить вежливо). Это лучше, чем устраивать шаманские танцы вокруг терминала.
Для нашего проекта запускаем команду:
После этого у вас локально поднимется фронтенд-приложение по адресу: http://localhost:3000. Вот теперь у вас есть живая страница, которую можно щупать, трогать, ломать, ломать ещё раз — и, конечно же, ставить на неё data-test-id как боженька тестирования.
Шаг 3. Учимся расставлять тестовые идентификаторы
Что такое JSX?
JSX (JavaScript XML) — это такая хитрая смесь HTML и JavaScript, которую придумали для React. Выглядит как HTML, но внутри работает как настоящий JavaScript. Прямо как бургер с сюрпризом: сверху булочка — вроде знакомо, а внутри... JavaScript.
Пример:
Отличия JSX от HTML
JSX похож на HTML, но не вздумайте писать как в старой школе, есть нюансы:
- class нельзя. Вместо class="btn" пишем className="btn", потому что class — это уже ключевое слово в JavaScript, и он вас просто пошлёт компиляться с ошибкой.
- Обработчики событий = camelCase. Вместо onclick="..." пишем onClick={...}. Большая C — это не ошибка, это стиль JSX. Привыкайте.
- Один родитель сверху. JSXне может вернуть два соседних тега. Всё должно быть в одном корневом контейнере:Так нельзя:
А так можно:
4. Все теги должны быть закрыты. Даже <input>! Забудьте про HTML-расслабон.
Что такое компонент?
Компонент — это просто кусок интерфейса. Кнопка, форма, модалка, карточка товара — всё это компоненты. Каждый компонент — мини-приложение внутри большого приложения. Он самодостаточный, переиспользуемый и легко тестируемый.
Пример функционального компонента:
Вот и всё. Это уже компонент. Можно вставлять его в любом месте вот так:
React сам вставит кнопку с нужным data-test-id, и ваш автотест её найдет за миллисекунду.
Компоненты бывают:
- Функциональные (используются в 95% случаев) — как выше.
- Классовые — это старьё. Если вы их видите — бегите или зовите на помощь. Скорее всего, вам они не понадобятся.
Где указывать data-test-id?
Просто: на том JSX-элементе, к которому должен обратиться автотест. Вот и вся философия. Пример:
Никакой магии. Теперь автотест найдёт этот input и будет знать, что именно он — поле для email.
Как найти нужный элемент в коде?
Вы открыли фронт и видите: «Ага, вот тут есть кнопка 'Отправить', а вот заголовок 'Welcome to UI Course application!'». Но возникает логичный вопрос: «А где это в коде, мать его?». Именно туда и надо добавить data-test-id, но сначала это нужно найти.
Ниже — три проверенных способа, которые реально работают и экономят кучу времени.
Способ 1: Поиск по видимому тексту
Прямолинейно, быстро, эффективно. Берете текст с экрана, прокидываете его в поиск по проекту и — бам! — находите нужный компонент.
Вы видите в браузере:
Берете "Welcome to UI Course application!", вбиваете в глобальный поиск (например, в VSCode), и если текст захардкожен, вы сразу окажетесь в JSX-файле, где он написан.
Плюсы:
- Быстро.
- Не требует танцев с бубном.
- Идеально работает в простых проектах.
Минусы:
- Не сработает, если используется локализация (i18n) — там текстов в JSX просто нет.
Способ 2: Поиск по ключу локализации (если проект на i18n)
Если проект многоязычный, то видимого текста в коде вы не найдёте. Вместо этого будет что-то вроде:
Такой код берёт текст из отдельного файла с переводами. Ваша задача:
- Посмотрите текст в браузере.
- Найдите его в одном из .json или .ts файлов локализации.
- Посмотрите, какой у него ключ (ui_course_welcome_page_title).
- По этому ключу ищите в проекте, чтобы понять, где он используется в коде.
Плюсы:
- Работает в 100% i18n проектов.
- Даёт точный ответ — в каком компоненте вы находитесь.
Минусы:
- Надо понимать, как устроены файлы локализации.
- Ключи могут быть переиспользуемыми или составными, так что надо смотреть внимательно.
Способ 3: Просто спросить у фронтендера
Да, это самый очевидный, но почему-то забываемый способ. Подходите (или пишите в чат) и говорите:
“Бро, где живёт кнопка 'Отправить'? Мне туда data-test-id воткнуть надо.”
И вуаля — разработчик:
- Говорит, как называется компонент (WelcomePage, LoginForm, SubmitButton, что угодно);
- Присылает путь к файлу;
- Может даже сам навесить data-test-id по доброте душевной.
Почему это работает:
- Разработчик знает структуру лучше всех.
- Экономит вам часы бестолкового блуждания.
- Заодно улучшите коммуникацию внутри команды.
Лайфхак: Если вы QA в команде — договоритесь с фронтендерами, чтобы сразу ставили data-test-id при создании компонентов. Всё равно потом ставить придётся — лучше сразу.
Как правильно расставлять data-test-id: практические кейсы
Окей, вы нашли нужный элемент в коде. Теперь следующий шаг — пометить его для автотестов. Но делать это нужно не как попало, а с умом. Ниже — три ситуации из реальной практики и чёткий план, как работать с каждой из них.
Случай 1: Простой компонент — просто добавляем data-test-id
Если вы контролируете компонент и элемент доступен напрямую — добавляете идентификатор прямо в JSX. Никаких сложностей.
Пример:
Что происходит:
- У вас есть заголовок с текстом.
- Вы добавляете data-test-id="welcome-title" — и теперь автотест легко найдёт этот элемент.
- Название делаем по шаблону: {контекст}-{тип_элемента}. Например: welcome-title.
Когда так делать:
- Элемент находится в вашем коде, а не во вложенном компоненте.
- Компонент простой, без магии.
- Вы контролируете разметку.
Случай 2: Вложенные компоненты — нужно идти внутрь
Когда нужный элемент внутри другого компонента — просто так data-test-id не добавить. Нужно открыть вложенный компонент и разметить его там.
Пример:
Что происходит:
- В WelcomeView есть компонент FormView.
- Но input и button живут внутри FormView.
- Мы не размечаем их снаружи, а добавляем data-test-id внутри самого FormView.
Когда так делать:
- Элемент спрятан во вложенном компоненте.
- Вы можете открыть компонент и изменить его.
- Важно сохранить локальный контекст — каждый компонент отвечает за свои data-test-id.
Случай 3: Переиспользуемые компоненты — передаём testId через props
Если у вас компонент, который юзается в разных местах — хардкодить data-test-id в нём нельзя. Он потеряет уникальность. Нужно передавать часть ID снаружи, как параметр.
Пример:
Что происходит:
- Компонент ListItem используется несколько раз.
- В каждом вызове мы передаём уникальный testId.
- Внутри компонента формируются уникальные data-test-id — вроде playwright-list-item-title.
Что такое props:
- Это просто входные параметры компонента.
- Через них мы можем гибко конфигурировать поведение и разметку.
- В нашем случае — передаём testId.
Когда так делать:
- Компонент универсальный и используется в разных контекстах.
- Нужно сохранить уникальность data-test-id.
- У компонента нет контекста сам по себе, его дают извне.
Пример с индексами
Если рендерится список, и у вас нет уникального ID — можно использовать индекс:
Но! Если есть item.id — лучше использовать его, а не индекс: testId={course-${item.id}}
Почему?
- Индекс может меняться при изменении списка.
- ID — стабильнее, надёжнее, точнее.
Ставим свой первый тестовый идентификатор
Окей, мы разобрались с базой. Теперь пора поставить свой первый data-test-id. В тестовом приложении, которое мы устанавливали ранее, есть специальная страница:http://localhost:3000/#/welcome — и на ней пока не расставлены data-test-id.
Давайте попробуем сделать это пошагово.
Шаг 1: Найти нужный элемент
На странице /welcome вы увидите крупный заголовок: Welcome to UI Course application!
Он расположен в самом верху, внутри компонента с белым фоном (обёрнут в Paper) и визуально является главным заголовком страницы.
Шаг 2: Найти компонент в коде
Этот заголовок находится в компоненте WelcomeView, который расположен по пути: /src/Views/Welcome/WelcomeView.tsx. Фрагмент кода до изменений:
Открываем этот файл в редакторе и видим знакомую структуру JSX.
Шаг 3: Добавить data-test-id
Теперь добавим data-test-id к элементу , который содержит заголовок.
Было:
Стало:
Почему welcome-view-main-title?
Разберём идентификатор по частям:
- welcome-view — контекст, в котором находится элемент.
- main-title — тип и смысл элемента: это основной заголовок страницы.
Такой шаблон делает data-test-id:
- читаемым,
- понятным,
- уникальным в пределах проекта.
Это лучше, чем просто main-title или title, так как изолирует идентификатор в контексте WelcomeView.
Шаг 4: Проверить в DOM
Сохраняем изменения, обновляем страницу в браузере и открываем инструменты разработчика (DevTools). Ищем элемент с data-test-id="welcome-view-main-title":
Если вы его видите — значит всё сделано правильно.
Вывод
Как видите, поставить data-test-id — это просто. В большинстве случаев вам нужно:
- Найти нужный элемент в интерфейсе.
- Найти соответствующий компонент в коде.
- Добавить data-test-id, опираясь на контекст и роль элемента.
Со временем это станет автоматическим навыком, который занимает буквально пару секунд.
Как обстоят дела на самом деле в реальных проектах?
Реальность: data-test-id? Ха! Его почти никогда нет
Добро пожаловать в настоящий мир. В большинстве реальных проектов — особенно если вы подключаетесь не с первого дня — тестовые идентификаторы отсутствуют напрочь. Вообще. Ни одного.
Почему? Потому что (внимание, шок-контент) продукт делают для пользователей, а не для ваших автотестов. Вот так поворот.
Так что если вы видите чистый, идентификаторно-девственный DOM — это не баг, это фича.
Что с этим делать? Брать ситуацию в свои руки
Да, вам, скорее всего, придётся инициировать обсуждение. Да, возможно, даже сделать презентацию. Но кто, если не вы?
Вот что реально работает:
- Проведите 15-минутный митинг. Без скучного буллшита, только боль и правда.
- Покажите разваливающиеся локаторы на CSS или XPath. Чем больше — тем больнее.
- Объясните,сколько часов жизни уходит на «починил → снова сломалось».
- Скажите магическую фразу: «Мы будем чинить старьё вместо того, чтобы покрывать новое. Это не автотесты, это технический долг с таймером.»
Уверяю, после этих слов хотя бы один человек в зале начнёт молча гуглить data-test-id best practices.
Как внедрять data-test-id и не развалить проект?
Спокойно. Никто не говорит "стопаем разработку и начинаем добавлять ID-шники". Всё можно делать аккуратно и параллельно:
- Пока нет автотестов — вы всё равно делаете ручное тестирование.
- Потратьте 1–2 часа в день на расстановку ID в ключевых местах.
- Когда основные зоны покрыты — начинайте писать тесты.
- Самые жирные точки входа — формы, списки, кнопки. Туда — в первую очередь.
Подключайте фронтенд-разработчиков (сюрприз: они не против)
Серьёзно, для фронтенда поставить data-test-id — это даже не задача. Это полсекунды внимания.
- Не требует архитектуры.
- Не трогает бизнес-логику.
- Помогает сразу понять, какие элементы проверяются в тестах.
- Идеально живёт рядом с рефакторингом.
Хотите, чтобы они помогали? Дайте им гайд на одну страницу. Или бросьте ссылку в Confluence. Всё.
Важно понимать
data-test-id — не панацея. Тесты всё равно будут падать: баги, переделки, жизнь. Но! Вы минимизируете 95% случайных падений, которые происходят потому что:
- поменяли текст,
- стиль ушёл на три пикселя влево,
- элемент телепортировался в другой угол DOM.
Это не спасёт от апокалипсиса, но спасёт от тысячи мелких проблем.
Вывод
Хотите стабильные автотесты — возьмите data-test-id под контроль. Не ждите, пока кто-то вспомнит о тестах в пятницу вечером перед релизом. Сделайте это сами, сделайте красиво.
Общий принцип именования data-test-id
Вы, конечно, можете назвать кнопку btn123 или elementX. А можете — как человек, который уважает своих будущих коллег (и себя через неделю).
Базовый шаблон:
Главное правило: уникальность в рамках страницы. Не устраивайте "битву кнопок" с одинаковыми ID.
Шаблоны и примеры
Рекомендации
- Используйте kebab-case (через дефис), а не camelCase или, прости господи, PascalCase.
- Делайте ID осмысленным. login-page-submit-button гораздо понятнее, чем btn5.
- Не пишите ерунду вроде button-button или input-input-field — вы не робот.
- Для повторяющихся элементов всегда указывайте индекс или ID — это спасёт от ада при кликах по спискам.
Запомните мантру: Контекст + Суть + Уникальность = Надёжный data-test-id. Потом скажете себе спасибо. Или хотя бы не будете себя проклинать на ретро.
Пример: как Playwright дружит с data-test-id
Если вы используете Playwright — поздравляю, вы в хорошей компании. И вот приятная новость: он по умолчанию заточен под работу с data-testid. Но если у вас в проекте решили изобрести своё — типа data-qa-id, data-pw, qa-id или test-id — не проблема.
Вот как сделать всё красиво:
Магия в том, что get_by_test_id(...) теперь будет искать по data-qa-id="...", а не data-testid.
И да, это работает с любыми кастомными вариантами:
- data-test-id
- data-qa
- data-id
- qa-id
- data-pwГлавное — задать атрибут один раз, и пользоваться как человек.
Зачем вообще это нужно?
Чтобы не городить XPath на полэкрана или кликать по «второму div, где третий span, у которого сосед справа с классом .active». Вместо этого:
Просто. Прозрачно. Поддерживаемо. Прямо как вы хотели, когда только мечтали писать автотесты.
Заключение
Если вы всё ещё думаете, что data-test-id — это какая‑то «штука для автоматизаторов», давайте скажу прямо: это часть инженерной культуры. Такой же как читаемый код, линтер, или адекватные названия переменных.
Писать автотесты без data-test-id — это как строить небоскрёб без лифта: можно, но по лестнице долго и устаёшь.
И помните:
- data-test-id — это не костыль, а инструмент предсказуемости.
- Это не «сделка с совестью», а договор между тестами и интерфейсом.
- Это не про «удобно тестерам», а про меньше багов в проде, меньше хаоса в команде.
CSS и XPath — это прошлое. А data-test-id — это то, что делает автотесты надёжными, предсказуемыми и стабильными. Хотите вы этого или нет — он победит.