Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Data-Testid Naming Convention

Convention for data-testid attributes in apps/jaguar for E2E testing.

Consistent data-testid attributes make E2E tests reliable and maintainable. They decouple tests from the UI structure, so tests keep working when markup or styling changes. Following this convention keeps selectors predictable across apps/jaguar.

Naming Pattern

{component}-{element}-{type}

Test ID Conventions

Authentication

Elementdata-testid
Login pagelogin-page
Email inputlogin-form-email-input
Password inputlogin-form-password-input
Name inputlogin-form-name-input
Submit buttonlogin-form-submit-button
Google buttonlogin-form-google-button
Toggle modelogin-form-toggle-mode-button
Go to homepages buttonlogin-form-go-to-homepages-button
Elementdata-testid
Sidebarsidebar
Nav itemsnav-{slugified-title} (dynamic)
Nav sub-itemsnav-{parent}-{child} (dynamic)
User Menunav-user-{action} (menu, trigger, account-item, notifications-item, logout-button)
Team Switcherteam-switcher-{action} (menu, trigger, add-team-button, item-{team-name})
Projectsnav-projects-{action} (nav-projects, item-{project-name}, more-button-{project-name}, view-action, share-action, delete-action)
Brand Logohungryhub-logo

List Components

Componentdata-testid Pattern
HomepageListhomepage-list-{action} (search-input, create-button, clear-filters-button, refresh-button)
BannerListbanner-list-{action} (search-input, create-button, clear-filters-button, refresh-button)
SectionListsection-list-{action} (search-input, create-button, clear-filters-button, refresh-button)
HomeIconListhomeicon-list-{action} (search-input, create-button, clear-filters-button, refresh-button)
TagSectionListtagsection-list-{action} (search-input, create-button, refresh-button)
CityListcity-list-{action} (search-input, sync-button, clear-filters-button, refresh-button, popover-trigger, popover-content)
CountryListcountry-list-{action} (search-input, sync-button, clear-filters-button, refresh-button)
LanguageListlanguage-list-{action} (search-input, create-button, clear-filters-button, refresh-button)
RestaurantTagListrestauranttag-list-{action} (search-input, sync-button, clear-filters-button, refresh-button)

Form Components

Componentdata-testid Pattern
HomepageFormhomepage-form-{action} (name-input, description-input, city-select, country-select, active-checkbox, submit-button, cancel-button, delete-button)
BannerFormbanner-form-{action} (position-input, location-select, city-selector, country-select, active-checkbox, ai-translate-button, submit-button, cancel-button, delete-button)
SectionFormsection-form-{action} (slug-input, section-number-select, type-select, template-select, banner-type-select, data-source-type-select, endpoint-api-input, tag-section-button, group-landing-page-button, ai-translate-button, submit-button, cancel-button, delete-button)
HomeIconFormhomeicon-form-{action} (icon-type-select, image-upload, link-url-input, position-input, city-selector, restaurant-tag-button, active-checkbox, ai-translate-button, submit-button, cancel-button, delete-button)
TagSectionFormtagsection-form-{action} (name-input, add-item-button, submit-button, cancel-button, delete-button); tagsection-form-item-{index}-{action} (restaurant-tag-button, active-checkbox)

Detail View Components

Componentdata-testid Pattern
HomepageViewhomepage-view (container) and homepage-view-{action} (edit-button, visit-button, {device}-section-{id}-{action} for edit/toggle/view)
SectionViewsection-view (container) and section-view-{action} (edit-button, back-button, retry-button, visit-link-button, manage-group-landing-page-button, manage-tag-section-button)
BannerViewbanner-view (container) and banner-view-{action} (edit-button, back-button, retry-button)
HomeIconViewhomeicon-view (container) and homeicon-view-{action} (edit-button, back-button, retry-button)
TagSectionViewtagsection-view (container) and tagsection-view-{action} (edit-button, back-button, retry-button)

Search Dialogs

Componentdata-testid Pattern
GroupLandingPageSearchDialoggrouplanding-search-{action} (input, clear-button, cancel-button)
RestaurantSearchDialogrestaurant-search-{action} (input, clear-button, close-button)
RestaurantTagSearchDialogrestauranttag-search-{action} (input, clear-button, cancel-button)
SectionSearchDialogsection-search-{action} (input, clear-button, cancel-button)
TagSectionSearchDialogtagsection-search-{action} (input, clear-button, cancel-button)
BranchSearchDialogbranch-search-{action} (input, clear-button, cancel-button, result-{id})

Dialogs & Modals

Componentdata-testid Pattern
LanguageFormDialoglanguage-form-{action} (dialog, language-select, direction-select, active-checkbox, cancel-button, submit-button)
HomepageLinkDialoghomepage-link-dialog (content), homepage-link-dialog-{action} (base-url-input, use-default-button, cancel-button, continue-button)
HomepagesListDialoghomepages-list-dialog (content), homepages-list-dialog-homepage-link-{id}

AI Translation Components

Componentdata-testid Pattern
AITranslationConfigureStepai-translation-{action} (cancel-button, translate-button, review-button)
AITranslationProgressStepai-translation-{action} (retry-button, retry-all-button, continue-button)
AITranslationReviewStepai-translation-{action} (close-button, translate-more-button, apply-all-button, discard-all-button)
AITranslationEntityCardai-translation-{action} (edit-button, discard-button, apply-button, save-button, edit-cancel-button)
AITranslationSheetai-translation-sheet

Translation Fields & Managers

Componentdata-testid Pattern
Banner translationsbanner-form-translation-{index}-{field} (name-input, caption-input, description-textarea, description-ext-textarea, link-input, image-desktop-upload, image-mobile-upload)
Section translationssection-form-translation-{index}-{field} (title-input, tagline-input, punchline-input, description-textarea, footer-textarea, image-upload)
HomeIcon translationshomeicon-form-translation-{index}-title-input
TranslationManagertranslation-manager-{action} (add-translation-button, translation-{index}-{action} [toggle, language-select, default-checkbox, remove-button])
TranslationPreviewtranslation-preview (item-{index})

Homepage Section Utilities

Componentdata-testid Pattern
DeviceSectionsdevice-sections-{device} (item-{sectionId}-{action}: drag-handle, active-switch, select-button, actions-button, edit, view, remove; add-button)

Common

Elementdata-testid
Delete confirmation dialogdelete-dialog-confirm-button
Delete cancel dialogdelete-dialog-cancel-button
Confirmation dialogconfirmation-dialog-{action}
File Uploadfile-upload-{action} (input, url-input, dropzone, remove-button)
City Selectorcity-selector-{action} (select-all-checkbox, country-{id}-toggle, country-{id}-select-toggle, city-{id}-checkbox)
Dropdown Actiondropdown-action-{action} (trigger-button, view-link, edit-link, duplicate-link, delete-button)

Preview Components

Componentdata-testid
BannerPreviewbanner-preview
HomeIconsPreviewhome-icons-preview
HhSpecialsPreviewhh-specials-preview

Edge Cases

Apply data-testid only to stable elements that persist across page states. Dynamic or transient elements (e.g., loading spinners, ephemeral popovers) should not be used as test anchors; use wait conditions or target a stable parent instead.

Validation Rules

  • Use only lowercase alphanumeric characters and hyphens (a-z, 0-9, -).
  • Keep values under ~64 characters to preserve readability.

Dynamic Placeholders

Dynamic values such as {index}, {id}, and {action} are placeholders that are replaced at runtime. Document the resolved pattern (e.g., section-form-translation-0-name-input) in code comments so selectors stay traceable.

Usage

// Playwright
await page.getByTestId("homepage-list-create-button").click();
await page.getByTestId("homepage-form-submit-button").click();

// Cypress
cy.get("[data-testid=\"login-form-submit-button\"]").click();