Перейти к основному содержимому

Правила тест-маркеров (data-testid) для Frontend

Цель: устойчивые, семантические идентификаторы на ключевых элементах UI — чтобы их было легко находить в DOM при отладке и в будущих автотестах (Testing Library / Playwright), не завязываясь на вёрстку и стили.

Что использовать (и почему)

  • data-testid — канонический атрибут. Это значение по умолчанию у Testing Library (getByTestId) и Playwright (getByTestId, testIdAttribute='data-testid'). Устойчив к рефакторингу стилей/разметки.
  • НЕ id — должен быть уникален на странице; в списках/таблицах легко получить дубликаты, ломается при нескольких экземплярах. Используем id только когда он реально нужен для label htmlFor/a11y.
  • НЕ class — классы для стилей (Tailwind/HeroUI); завязывать тесты на классы хрупко.

Что помечаем (и что НЕ помечаем)

Помечаем значимые, запрашиваемые узлы, а не каждый div:

  • Страница — корневой контейнер: page-<entity> (напр. page-employees).
  • Форма/модалка<entity>-<create|edit>-modal (напр. employee-create-modal).
  • Поле формы — на интерактивном элементе: field-<FieldName>; ошибка поля: field-error-<FieldName>. (В форм-библиотеке проставляется автоматически из имени поля TanStack Form — отдельно делать не нужно.)
  • Таблица/список<entity>-table; пагинация — list-pagination.
  • Действия строки — внутри строки: row-edit, row-delete.
  • Подтверждение удаленияconfirm-dialog, кнопки confirm-dialog-confirm / confirm-dialog-cancel.
  • Первичная кнопка действия<entity>-add-button и т. п.
  • Состояния (по необходимости) — state-empty / state-error / state-loading.

НЕ помечаем: декоративные обёртки, иконки, элементы без самостоятельной ценности для теста/отладки.

Именование

  • kebab/scoped, латиница, стабильно: <область>-<сущность>-<роль> (employee-create-modal, tenants-table, tenants-add-button).
  • Имена полей берём как есть из контракта (field-FirstName, field-Contacts[0].Value) — это даёт однозначную связь поля формы и DOM.
  • Идентификатор стабилен (не зависит от текста подписи/локализации/порядка стилей).

Как реализовано (переиспользуемо)

Базовые компоненты принимают необязательный проп и рендерят data-testid — точечно проставлять на каждом элементе не нужно:

  • Поля форм (shared/ui/form/fields/*) — авто data-testid={field-${field.name}} (+ field-error-…).
  • shared/ui/{FormModal,PageHeader,DataTableCard,TableRowActions,ConfirmDialog,ListPagination,StateSurface} — проп testIddata-testid. FormModalShell прокидывает testId в FormModal.
  • shared/ui/enum-selects/EnumSelectField — проп testId; FormSelect/bound-селекты проставляют field-<name>.

Страницы/виджеты передают testId в эти компоненты (см. примеры в pages/EmployeesPage, widgets/EmployeesTable).

Scope-префиксы (несколько форм на странице)

Чтобы при нескольких формах не было дублей (form-submit, field-DisplayName) и было видно, к какой форме относится элемент, у форм есть scope-префикс:

  • FormModalShell выводит scope из testId (снимая хвост -modal) или принимает явный scope. Внутри: поля → <scope>-field-<name>, кнопки → <scope>-submit / <scope>-cancel (напр. employee-create-field-FirstName, employee-create-submit).
  • Для немодальных форм (page-forms) оборачивайте поля в FormScopeProvider scope="<scope>" (из @shared/ui/form), чтобы получить тот же префикс.
  • Без scope поля остаются field-<name>, кнопки — form-submit/form-cancel (ок для одной формы).

QA-метаданные (data-qa-*, env-gated)

Помимо data-testid (стабильные селекторы) добавляем QA-метаданные — id сущностей для отладки: data-qa-tenant-id, data-qa-entry-id, data-qa-user-id и т. п.

  • Выключаемы через env VITE_QA_METADATA ('true'/'false'); по умолчанию вкл. в dev, выкл. в prod — чтобы лишняя информация (id) не утекала в прод-DOM.
  • Помощник qaAttrs({ 'tenant-id': id, … }) из @shared/lib/qa-metadata возвращает {} при выключенном флаге; распыляйте на элемент: <Table.Row {...qaAttrs({ 'tenant-id': tenant.TenantId })}>.
  • Базовые компоненты PageHeader/FormModal(Shell)/ConfirmDialog принимают проп qadata-qa-*.
  • data-testid — НЕ env-gated (это селектор, не чувствительные данные). Чувствительные id — только в data-qa-*.

Применение

  • Для нового и редактируемого кода — проставлять маркеры по списку выше (boy-scout rule).
  • Базовые примитивы — единый источник; не плодить ad-hoc data-* именования.
  • Совместимо с frontend-rules.md, frontend-jsdoc-rules.md, frontend-fsd-and-atomic-rules.md.

Обратные ссылки

Автоссылки: где используется этот документ.