Skip to content

Commit e9aa4ca

Browse files
committed
components e2e
1 parent de2e4dd commit e9aa4ca

1 file changed

Lines changed: 26 additions & 7 deletions

File tree

.agents/skills/components_e2e/SKILL.md

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ is a **standalone repo** that is also hosted on GitHub as
3535

3636
A Chemical demo app (`app/`) renders every interactive component with stable
3737
`data-testid` hooks. Playwright loads the static output, hydrates, clicks, and asserts
38-
real DOM state (~140 tests):
38+
real DOM state (~177 tests):
3939

4040
- **Hydration correctness** — SSR output becomes interactive without node duplication
4141
(the hydration fix in `page.ch` removes the original SSR text node when a state
@@ -50,11 +50,14 @@ real DOM state (~140 tests):
5050
- **Checkbox/Switch/Radio**: toggle, mutual exclusion, disabled state.
5151
- **ToggleGroup**: single and multiple mode.
5252
- **RadioGroup**: select, defaultValue, no-provider, focusable items.
53-
- **Toast**: auto-dismiss.
54-
- **Collapsible**: toggle + aria-expanded.
55-
- **Sheet**: open/close, inert background.
53+
- **Toast**: auto-dismiss, duration=0 (no auto-dismiss), manual close button, action slot, role=status, title-only and description-only render.
54+
- **Collapsible**: toggle + aria-expanded, controlled mode (external button).
55+
- **Sheet**: open/close, inert background, side prop (left/top/bottom).
5656
- **Dropdown**: portal escapes overflow:hidden, non-modal no-inert.
5757
- **Input**: default/filled/ghost/error/success variants, sm/lg sizes, disabled, type=email/number/password/search, textarea rows, field (label/hint/error), focus ring, typed value via onChange.
58+
- **Dialog**: controlled mode (parent drives open/close via state + Escape).
59+
- **ToggleGroup**: controlled mode (parent drives selection), outline/ghost variants.
60+
- **RadioGroup**: controlled mode (click updates parent).
5861
- **NativeSelect**: <select> renders, placeholder disabled, accepts selection.
5962
- **Tooltip**: hover show/hide, bottom position.
6063
- **Pagination**: prev/next, last page disables next.
@@ -73,12 +76,28 @@ real DOM state (~140 tests):
7376
- **Accessibility** — buttons have names, accordion/collapsible have `aria-expanded`,
7477
dialog has `aria-modal`, separator has `role=separator`.
7578
- **Error boundary** — fallback UI shown on error, page keeps working after fallback mounts.
79+
- **Utility/layout components** — Container (sm/md/lg/full), Stack (direction, gap, align, justify), Grid (cols, gap), Breadcrumbs (links, separator, current page), Divider, Kbd, Skeleton (width/height/circle), Spinner (sm/md/lg, aria-label).
80+
- **Surface components** — Paper, AppBar, Drawer, Snackbar (role=status), Icon, BottomBar, EmptyState, StatCard.
81+
- **Dark mode**`.dark` class on `<html>` applies shadcn dark theme tokens; verified via CSS variable inspection.
82+
- **Text polymorphism**`Text` renders as `<p>`, `<span>`, or `<div>` via the `as` prop.
83+
- **ToggleGroup variants** — outline/ghost variants render (group-level CSS, items use default variant).
7684

7785
**Selector rule**: components that spread `{...props}` (Button, Input, Checkbox,
7886
Switch, Radio, Select, Slider, Progress) accept `data-testid` directly. Components
79-
that do NOT spread props (Card, Badge, Avatar, Typography, Tooltip, Alert, Separator)
80-
require text-based, role-based, or attribute-based selectors (e.g. `getByText`,
81-
`locator('[role="alert"]')`, `locator('[data-variant="info"]')`).
87+
that do NOT spread props (Card, Badge, Avatar, Typography, Tooltip, Alert, Separator,
88+
Stack, Grid, Skeleton, Spinner, Text) require text-based, role-based, or attribute-
89+
based selectors (e.g. `getByText`, `locator('[role="alert"]')`,
90+
`locator('[data-variant="info"]')`, `locator('.chx-stack-row')`).
91+
92+
**Component → selector cheat sheet**:
93+
| Component | Forward testid? | Selector pattern |
94+
|---|---|---|
95+
| Button, Input, Checkbox, Switch, Radio, Select, Slider, Progress | Yes | `getByTestId()` |
96+
| Card, Badge, Avatar, Typography, Tooltip, Alert, Separator | No | `getByText()`, `locator('[role=...]')`, `locator('[data-variant=...]')` |
97+
| Stack, Grid | No | `locator('.chx-stack-row')`, `locator('.chx-grid-gap-sm')` |
98+
| Skeleton, Spinner | No | `locator('span')` or `locator('[role=status]')` within fixture |
99+
| Dialog, Sheet (portaled) | No (portaled) | `page.getByRole('dialog')`, not fixture-scoped |
100+
| Toast (portaled to viewport) | On wrapper | Scoped via fixture `data-testid` |
82101

83102
Every fixture lives in `app/src/main.ch` inside a wrapper with `data-testid`, and state
84103
lives in the fixture (so tests exercise SSR → hydration → click).

0 commit comments

Comments
 (0)