{
  "name": "resources/testing",
  "title": "Testing with Playwright",
  "description": "How to find, operate and assert eurodata-ui elements with Playwright — three rules, and the locator on each element's page.",
  "docs": "https://test-apps.eurodata.de/a/eurodata-ui/docs/resources/testing/",
  "sections": [
    {
      "heading": "Testing with Playwright",
      "markdown": "eurodata-ui elements are tested with two of Playwright's user-facing locators: `getByTestId` finds the `data-testid` you set, and `getByRole` reads the **accessibility tree** — the roles and names a screen reader announces. Both look inside the elements' shadow roots by themselves, so a test never needs a CSS or XPath selector, nor an element's internal markup."
    },
    {
      "heading": "Three rules",
      "markdown": "### Rule 1: find an element by the testid you put on it\n\nPut a `data-testid` on the element itself, not on a wrapper around it:\n\n```html\n<ed-select data-testid=\"country\" label=\"Country\">…</ed-select>\n```\n\n```ts\nconst country = page.getByTestId('country');\n```\n\nThe testid is yours — the library sets none of its own — so it finds exactly one element.\n\n### Rule 2: reach what is inside from there, by role and exact name\n\n```ts\nawait page.getByTestId('country').getByRole('combobox').click();\nawait page.getByTestId('country').getByRole('option', { name: 'Germany', exact: true }).click();\n```\n\n-   **Always `exact: true`.** Without it a name matches any part of a name: \"Germany\" also finds \"East Germany\", \"Page 1\" also finds \"Page 10\".\n-   **Always from the testid.** `page.getByRole('button', { name: 'Save', exact: true })` searches the whole page and finds every Save button on it.\n-   **Names follow the element's language** — its own `lang`, or the page's. Run a test in one language and write the names of that language.\n\n### Rule 3: assert the live state\n\n```ts\nawait expect(page.getByTestId('terms').getByRole('checkbox')).toBeChecked();\nawait expect(page.getByTestId('country').getByRole('combobox')).toHaveValue('Germany');\nawait expect(page.getByTestId('country').getByRole('combobox')).toHaveAttribute('aria-expanded', 'true');\n```\n\nAssert through the same locator you operate with, and assert the state, not an attribute that only looks like it: `toHaveAttribute('checked')` on a checkbox reads the state it started in. Playwright has no `toBeExpanded()`; an open list or section is `toHaveAttribute('aria-expanded', 'true')`."
    },
    {
      "heading": "The locator on each element's page",
      "markdown": "Every element's docs page shows its locator in the header, with a button that copies it, in one of two forms:\n\n-   `getByTestId('…')` — the element itself; reach what is inside it by rule 2.\n-   `getByTestId('…').getByRole('checkbox')` — the one control the element renders.\n\nReplace `…` with the testid you put on the element."
    },
    {
      "heading": "Good to know",
      "markdown": "-   **Overlays have no box of their own.** `ed-dialog`, `ed-drawer`, `ed-alert-dialog` and `ed-tooltip` are `0×0` while closed: assert the host `open` attribute, or `toBeVisible()` on the role inside while open, by its name — `page.getByTestId('settings').getByRole('dialog', { name: 'Settings', exact: true })` — since an open date picker inside it is a dialog too.\n-   **Formatters render text.** Assert `ed-format-number`, `ed-format-bytes`, `ed-format-date` and `ed-relative-time` with `toHaveText()`.\n-   **Never reach into an element's markup.** `page.getByTestId('save').locator('button')` depends on markup that can change in any release; `getByRole('button', { name: 'Save', exact: true })` reaches the same node and stays the same."
    }
  ]
}
