I used to ask the agent for “Storybook coverage for this component.” It came back with one mega-story: default, hover, focus, error, loading, disabled, and a knobs panel that looked impressive and tested almost nothing.
Reviewers clicked the Control panel once, shrugged, and merged. Then Playwright started failing on the empty state we never actually rendered as its own story.
Now I force a boring rule: one interaction (or one meaningful state) per story. The agent can still generate many stories — just not one blob that pretends to be coverage.
What “one interaction” means
Not “one prop.” One thing a human would verify in isolation:
-
Default— happy path, no extras -
Empty— zero items / blank slate -
Loading— skeleton or spinner only -
Error— recoverable failure message -
Disabled— cannot activate -
KeyboardFocus— focus ring visible without hover -
WithLongLabel— truncation / wrap edge
Hover-only variants are fine as separate stories when hover changes layout or reveals controls. Don’t bury them behind a state select in Controls.
Why agents invent mega-stories
Models optimize for “looks complete.” One file with every arg mapped to a Control feels thorough. It’s also:
- hard to screenshot for visual regression (which state is the baseline?)
- easy to miss in review (you never open every Control combination)
- useless as a failing repro — “open the story and toggle Error” is not a stable handoff
A failing Storybook story should be a URL + a story name, not a checklist of knobs.
Prompt I paste now
Add Storybook stories for `ShippingForm` in `ShippingForm.stories.tsx` only.
Rules:
- One story export per meaningful state/interaction (Default, Empty, Error, Loading, Disabled, KeyboardFocus).
- No mega-story with a `state` enum Control that switches everything.
- Prefer `args` / `render` per story over nested conditionals in one template.
- Each story must render without touching Controls.
- Max ~120 lines for the stories file. No new addons.
- Do not invent props the component doesn’t have — grep the component first.
If the component truly needs a Control (theme, locale), I allow one shared Control at the meta level — not a state machine per story.
What I reject in review
Reject / ask to split
- Single
Playgroundstory that covers empty + error + loading via Controls -
renderwith a giantswitch (args.variant)that duplicates the component’s own branches - Stories that only work after the reviewer toggles three knobs
- “AllStates” grids that pack six UIs into one canvas (fine as a docs appendix, not as the only coverage)
Accept
- Small, boring named stories
-
playfunctions that assert one interaction (tab to submit, see error text) on that story alone - Reused
decoratorsfor providers — shared setup is fine; shared “all states” is not
Visual regression loves this
Chromatic / Playwright story shots become obvious:
ShippingForm--Empty.pngShippingForm--Error.png
When the agent “fixes” empty-state copy, the Empty shot moves. When it only tweaked the happy path, Default moves. Mega-stories hide which branch changed.
Tiny habit
Next time an agent ships a Playground story with twelve Controls, don’t argue taste in the PR thread. Leave a comment: split into named stories, one interaction each, same args — then paste the prompt above into the follow-up.
You’re not asking for more Storybook. You’re asking for stories that can fail out loud.
Top comments (0)