diff --git a/docs/test-conventions.md b/docs/test-conventions.md new file mode 100644 index 0000000..2439ebe --- /dev/null +++ b/docs/test-conventions.md @@ -0,0 +1,170 @@ +# Test Conventions Reference + +Concrete selector and ARIA conventions used across this repository. +Intended for Copilot agent sessions (heal, code review, new tests) so they +do not need to re-read every source file. + +--- + +## 1. Login message — ARIA roles and `aria-live` + +**Source:** `src/pages/Login.js` + +The message `
` rendered below the form uses a **dynamic role**: + +| State | `role` | CSS class | +|---------|----------|------------------| +| Success | `status` | `message success` | +| Error | `alert` | `message error` | + +Both states also carry `aria-live="polite"` (static attribute — it does not +change with the role). + +```jsx +
+ {message} +
+``` + +--- + +## 2. How Playwright specs assert on login messages + +**Source:** `tests/login.spec.ts` + +Specs use `getByRole` — never a CSS selector or `#message` ID — because the +role itself encodes the pass/fail state. + +```ts +// Success +const message = page.getByRole('status'); +await expect(message).toBeVisible(); +await expect(message).toHaveClass(/success/); +await expect(message).toContainText('Welcome'); + +// Error +const message = page.getByRole('alert'); +await expect(message).toBeVisible(); +await expect(message).toHaveClass(/error/); +``` + +Form field selectors use `getByRole('textbox', { name: … })` and +`getByRole('button', { name: … })`, matching the `