# Test Category Taxonomy

The categories a complete `@strongtie/design-system` component suite covers, with what each one is actually proving. This is the completeness checklist to run a new suite against; the authoritative worked example of every category is `packages/design-system/tests/button.test.tsx`, and the reasoning behind the load-bearing ones is in that skill's `SKILL.md`.

## What a good suite covers

**Rendering.** The component renders with default props and its semantic class is present (`toHaveClass("button")`). This is the smoke test — if it fails, nothing else is meaningful.

**Variants.** Each CVA variant renders without error. You are asserting the variant table wires up, not pinning exact utility classes (those churn). Where a `data-variant` hook exists, assert on it rather than on the emitted Tailwind string.

**Sizes.** Same shape as variants, for the `size` axis: each size renders.

**`className` merge.** A custom `className` and the semantic class both survive on the element. This catches a wrapper that overwrites instead of merging with `cn()`.

**`asChild` (when the component supports it).** Rendering `asChild` with a child element produces the child's element (e.g. an anchor with `role="link"`) still carrying the component's semantic class and content. Proves the `Slot.Root` pass-through works.

**Prop forwarding.** Arbitrary props (`data-testid`, `aria-label`, `type`, `disabled`) reach the underlying element. This is the `{...props}` spread working end to end.

**Ref forwarding.** `React.createRef()`, render, then assert `ref.current?.tagName` and `ref.current?.textContent` — the ref points at the real DOM node. Not a `vi.fn()` ref: a fired callback proves nothing about where the ref landed.

**Interaction.** `userEvent.click` (and keyboard where relevant) fires the handler the expected number of times; a disabled component does not fire it.

**Accessibility.** `axe(container)` then `expect(results).toHaveNoViolations()` for the default render and for any state that changes the accessible tree (disabled especially). Keyboard reachability: tab to the element and assert focus; tab *past* a disabled one to prove it is out of tab order.

## Composite components

Components with sub-parts (Card, Alert, and the like) add two categories: that every sub-component renders its content, and that each part carries its own semantic class (`.card`, `.card-header`, and so on). Assert the parts compose, not just that the root renders.

## Completeness checklist

- [ ] Renders with default props; semantic class present
- [ ] Every variant renders
- [ ] Every size renders
- [ ] Custom `className` merges with the semantic class
- [ ] `asChild` passes through (if supported)
- [ ] Arbitrary props forward to the element
- [ ] Ref points at the DOM node (`createRef` + `ref.current`)
- [ ] Click / keyboard fires the handler; disabled does not
- [ ] No axe violations (default and disabled)
- [ ] Keyboard focusable; disabled out of tab order
- [ ] Sub-components render and carry their classes (composite only)
