Author economical visual tests — full visual coverage in the fewest billable snapshots. Applies to any per-snapshot visual tool (UI Verify, Chromatic, Percy, Playwright screenshots), which all bill and diff per rendered story/test. Use when a component's variants/states are exploding into one snapshot per combination, when the visual-testing bill or noise is driven by snapshot count, or when writing new stories/captures and you want the cheapest layout that still covers every variant. Covers gallery/matrix stories, data-driven states, and the coarse-granularity tradeoff.
77
97%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Passed
No findings from the security scan
Every per-snapshot visual tool — UI Verify, Chromatic, Percy, Playwright screenshots — renders and bills per story. So the number of stories is the cost and the noise surface. The naive pattern (one story per variant × state × theme) multiplies both fast: a component with 5 sizes × 3 states × 2 themes is 30 snapshots the naive way. This skill collapses that to a handful while keeping full coverage.
The technique is tool-agnostic; the payoff (fewer billed shots, fewer places to flake) is the same everywhere.
Render the whole matrix together in a single story: a grid of every size/state side by side. One snapshot then covers the entire matrix.
// Button.stories.tsx — ONE story covers every size × variant
export const AllVariants = () => (
<div
style={{
display: "grid",
gap: 16,
gridTemplateColumns: "repeat(3, max-content)",
}}
>
{(["sm", "md", "lg"] as const).flatMap((size) =>
(["primary", "secondary", "danger"] as const).map((variant) => (
<Button key={`${size}-${variant}`} size={size} variant={variant}>
{size}/{variant}
</Button>
))
)}
</div>
);9 buttons, 1 snapshot instead of 9.
For a component that normally fetches, don't write a story per response state. Render each state from a fixed fixture — a table of props/mock-responses — in one story. Deterministic input in, deterministic pixels out, many states, few shots.
const CASES: { label: string; items?: Item[]; error?: string }[] = [
{ label: "empty", items: [] },
{ label: "one", items: [fixtures.one] },
{ label: "many", items: fixtures.many },
{ label: "error", error: "Failed to load" },
];
export const AllStates = () => (
<div style={{ display: "grid", gap: 24 }}>
{CASES.map((c) => (
<section key={c.label}>
<h4>{c.label}</h4>
<List items={c.items} error={c.error} />
</section>
))}
</div>
);(If the component fetches internally rather than taking props, mock the request instead — see storybook-visual-testing, "mock data." The point is the same: fixtures, not N stories.)
Consolidating into one snapshot is coarser granularity: a diff anywhere in the gallery flags the whole story, and you lose the per-variant baseline/accept. So this is a balance, not "merge everything":
When you refactor, state the delta so the value is legible:
This collapses 28 stories → 2 snapshots (the size×variant×theme matrix into one gallery, the four data states into one story). ~93% fewer billed shots, same coverage.
Loading, Empty, Error, Loaded as four stories) → one data-driven story (move 2).FranciscoMoretti/chat-js
8dbcc37
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.