feat(storybook): testing grid WIP#6317
Conversation
|
📚 Branch Preview Links🔍 First Generation Visual Regression Test ResultsWhen a visual regression test fails (or has previously failed while working on this branch), its results can be found in the following URLs:
Deployed to Azure Blob Storage: If the changes are expected, update the |
Revert accidental 03_project-planning doc deletions from this branch so the PR stays focused on Storybook testing grid work. Co-authored-by: Cursor <cursoragent@cursor.com>
Reset the full CONTRIBUTOR-DOCS tree to match origin/main so this PR does not include unrelated planning doc changes. Co-authored-by: Cursor <cursoragent@cursor.com>
There was a problem hiding this comment.
im curious why we need this file if we can get a configured template from wc-toolkit? Is this that default story thing you mentioned in slack?
There was a problem hiding this comment.
@caseyisonit Since there a lot of items per cell in the grid, using wc-toolkit in each cell would invoke template() → useArgs() again and again, which violates React’s rules of hooks and produces the “Rendered more hooks than during the previous render” error we hit during development.
This template file is a lightweight Lit template file is VRT only where you have the creative freedom to create a sample or group of component artifacts to display in the grid effectively.
There was a problem hiding this comment.
thank you for investigating!
There was a problem hiding this comment.
Can any of our document stories be used in the vrt grid so we are also testing what we are rendering in production? it should potentially reduce the complexity of this file since those are already set up with args
Rajdeepc
left a comment
There was a problem hiding this comment.
Good going!
I am expecting to see at minimum tests for testing-grid.ts as this piece of infrastructure will be depended upon by every component.
Can you start with unit tests for isChromatic() , renderContent(), heading() , Container() and a smoke test that renders Variants() should be good.
If you want to discuss on the blocking vectors we can chat!
…om component css file
|
|
||
| /** Foreground text color on each static-color demo background. */ | ||
| export const STATIC_COLOR_DEMO_FOREGROUNDS = { | ||
| white: 'white', |
|
|
||
| ## Testing grid (`test/*.vrt.ts`) | ||
|
|
||
| Spectrum CSS keeps VRT case lists in a sibling module (e.g. `button.test.js`) that is **imported** by `button.stories.ts`, not indexed as its own Storybook file. |
There was a problem hiding this comment.
Is this a true fact for SWC? If so can we update the language to not reference Spectrum CSS?
There was a problem hiding this comment.
should live in decorator directory
There was a problem hiding this comment.
should live in helpers directory
There was a problem hiding this comment.
since this looks to only be used in helpers (correct me if im wrong) we should just roll this in to that file or rename this to a semantically correct helper and store it in the helpers directory along side the file using it
There was a problem hiding this comment.
not sure what this file is lol
There was a problem hiding this comment.
might need to add to gitignore?
There was a problem hiding this comment.
@caseyisonit Don't need this. It was generated after vite unit test was run for helpers in test grid
| function capitalize(str: string): string { | ||
| if (!str) { | ||
| return str; | ||
| } | ||
| return str.charAt(0).toUpperCase() + str.slice(1); | ||
| } |
There was a problem hiding this comment.
- we have a capitalize util in core we can reuse
- the if statement is confusing me, im reading this as if str is false meaning doesnt exist, wasnt passed in.... the there would be nothing for the return to send. Im not seeing a need for this check or the return needs to be empty OR it should throw a warning that str is required?
5t3ph
left a comment
There was a problem hiding this comment.
Really good work to get it this far! 👏
| return nothing; | ||
| } | ||
|
|
||
| const headingStyles: Record<string, string> = { |
There was a problem hiding this comment.
Typography styles should be loaded, so can you use existing classes instead? The dark/light mode handling might be excessive, too, since that color should already be inherited.
| } as const; | ||
|
|
||
| /** Same detection logic as `chromatic/isChromatic` (browser Storybook + CI). */ | ||
| export function isChromatic(windowArgument?: Window): boolean { |
There was a problem hiding this comment.
Why not import the existing one?
import isChromatic from 'chromatic/isChromatic';
| ); | ||
| } | ||
|
|
||
| function capitalize(str: string): string { |
There was a problem hiding this comment.
Import from 2nd-gen/packages/core/utils/capitalize.ts
| // automatically while browsing the dev UI. Chromatic renders each story via that | ||
| // same initial path, so without this it would snapshot the pre-play state. Enable | ||
| // autoplay only under Chromatic to restore correct visual regression snapshots. | ||
| autoplay: isChromatic(), |
There was a problem hiding this comment.
This needs added back - it's required for Tooltip and any other story that relies on play() for correct snapshots.
|
|
||
| import { augmentTree } from './pseudo-states.js'; | ||
|
|
||
| export type PseudoState = |
There was a problem hiding this comment.
Do you need disabled and focus-visible here? It looks like you're relying on component attributes for disabled and normalizing to just focus.
| host?.shadowRoot?.querySelector(innerSelector)?.classList.add(`is-${state}`); | ||
| } | ||
|
|
||
| function getInternalButton(host: Element): HTMLButtonElement | null { |
There was a problem hiding this comment.
I assume this is an outstanding question, but this will need generalized somehow - maybe consuming component will need to pass the right element, or maybe it can somehow pickup on the component name to find .swc-${componentName}? Same for other "button" specific portions.
| .spectrum-examples-static-colors > *:first-child { | ||
| color: white; | ||
| background: ${staticColorSettings.white}; | ||
| color: ${STATIC_COLOR_DEMO_FOREGROUNDS.white}; |
| .swc-Button:focus-visible, | ||
| .swc-Button.is-focus-visible { |
There was a problem hiding this comment.
This can be removed now, right?
| .swc-Button:focus-visible, | |
| .swc-Button.is-focus-visible { | |
| .swc-Button:focus-visible { |

Description
Adds a Storybook testing grid for 2nd-gen SWC, with Button as the reference implementation. The grid powers local VRT preview and Chromatic captures, separate from docs-friendly single-instance stories.
Storybook infrastructure
testing-grid/— Modular Lit helpers for VRT matrices (Variants,Container,States,ArgGrid,Sizes,vrtCase, …). Public API re-exported fromhelpers/testing-grid.ts.testing-preview.tsdecorator + Testing preview toolbar global (beaker icon) — maps toparameters.showTestingGridfor local grid preview.pseudo-states-helpers.ts+decorators/pseudo-states.ts— Shadow-root pseudo-state augmentation anddata-vrt-*cell patching for forced hover/focus/active captures.main.ts— Play-function tests stay under**/test/*.test.ts; VRT case lists live in**/test/*.vrt.ts(imported by*.stories.ts, not indexed as separate CSF files).preview.ts— Globalchromatic.disableSnapshot: truewith per-grid opt-in;autoplay: isChromatic()soplay()runs before Chromatic snapshots..storybook/helpers/README.mdfor the VRT file pattern and module layout..storybook/helpers/test/testing-grid.unit.test.ts(yarn test:unit, projectswc-unit).Button reference implementation
button.template.ts— Pure Lit template for grid cells (avoids@wc-toolkit/storybook-helperstemplate(), which callsuseArgs()per cell and triggers React hooks errors in large grids).button.vrt.ts— VRT case list (testData,stateData) imported by stories; not a standalone Storybook entry.button.stories.ts— VRT Grid story wired toButtonVRTRender.data-vrt-host,data-vrt-control, optionaldata-vrt-state, anddata-vrt-layout-classes(icon-only layout). Forced states use class-based pseudo rules (.is-hover,.is-focus-visible,.is-active), not component attributes.Testing grid
The testing grid renders a full variant × state × size matrix for Chromatic VRT. In local Storybook it stays hidden until Testing preview is enabled (or Chromatic runs). Docs stories continue to show a single instance.
Per-component setup (see
helpers/README.md):components/<name>/stories/<name>.template.ts— pure LitTemplate()for grid cellscomponents/<name>/test/<name>.vrt.ts—Variants()config (testData,stateData, nestedArgGrid/Containerbuilders)<name>.stories.ts—VRTGridstory withTESTING_GRID_STORY_NAME+TESTING_GRID_STORY_PARAMETERSModule layout (
.storybook/helpers/testing-grid/)testing-grid.ts(barrel)helpers/index.jsorhelpers/testing-grid.js.constants.tsTESTING_GRID_STORY_NAME('VRT Grid'),TESTING_GRID_STORY_PARAMETERS(Chromatic opt-in, pending delay), grid border token, human-readableSIZE_LABELS.types.tsGridTemplateFn,VariantsConfig,ContainerProps,StateItem,TestCaseItem, builder prop types.internal.tsreadStaticColor,wrapWithStaticColorDemo(gradient panel for static white/black sections),isDarkTheme,getRandomId.primitives.tsHeading(SWC typography labels,chromatic-ignore),Container(nested bordered flex sections;levelcontrols scale/spacing),renderContent(recursive nested content).builders.tsStates(interaction-state columns),ArgGrid(sweep one arg across options),Sizes(sizepreset),vrtCase(one-off rows like line wrap / truncation withwithStates: false).variants.tsVariants()— main entry point. Returns a Storybookrenderfunction: singledata-html-previewin docs/dev, fulldata-testing-previewmatrix when Testing preview is on or under Chromatic. OrchestratestestDatasections,stateDatamatrices, optionalSizesrow, and static-color wrapping.Related helpers (outside
testing-grid/):pseudo-states-helpers.tsdata-vrt-host/data-vrt-control/data-vrt-state;applyTestingGridPseudoStatesfor VRT storyplayfunctions.pseudo-states.ts:hover/:focus-visible/ etc. map to.is-*classes.decorators/pseudo-states.tsdecorators/testing-preview.tsparameters.showTestingGrid.VRT cell wrapper attributes (
<name>.template.ts)Each grid cell wraps the component in a
div.vrt-cellwithdata-vrt-*attributes. These are Storybook/VRT only — not part of the public component API.applyTestingGridPseudoStates(VRT storyplayfunction) reads them and patches the correct shadow-DOM node after render.data-vrt-hostswc-button). Used toquerySelectorthe host and tocustomElements.whenDefinedbefore patching.data-vrt-control.swc-Button). Omit only if the host element itself is the control.data-vrt-statehover,focus, oractive. Omit for default and disabled cells. Maps to.is-hover,.is-focus-visible, and.is-activeon the control. Disabled state uses the component'sdisabledattribute instead.data-vrt-layout-classesswc-Button--hasIcon swc-Button--iconOnlyfor icon-only cells). Ensures the correct layout is captured before Chromatic snapshots.Example (Button):
Motivation and context
2nd-gen SWC had hand-rolled option stories (
Sizes,Variants, etc.) but no shared VRT grid or Chromatic-oriented layout. This PR establishes the shared helper layer and proves the pattern on Button. SWC is the long-term home for this workflow as Spectrum CSS sunsets.How to test
Local Storybook
cd 2nd-gen/packages/swc yarn storybookdata-testing-previewwrapper with bordered sections).data-html-preview(docs-style).Unit tests
cd 2nd-gen/packages/swc yarn test:unitChromatic / PR preview
run_vrtis on the PR for 2nd-gen Chromatic when ready.Regression spot-checks
Screenshots
Add VRT Grid + Testing preview on/off screenshots before review.
Open questions for the team
@adobe/spectrum-wcfor Storybook helpers only, or also document the VRT pattern in contributor docs?Known gaps / follow-ups
*.vrt.ts+ grid; pattern not yet applied elsewhere.delay: 1100in grid Chromatic params; real 1s pending animation not fully exercised in all cells.data-vrt-host/data-vrt-controlare generic, but Button is the first consumer — validate pattern on the next component.Author's checklist
testing-grid.unit.test.ts).helpers/README.md).Reviewer's checklist
.storybook/helpers/testing-grid/,decorators/testing-preview.ts,pseudo-states-helpers.ts, andcomponents/button/test/button.vrt.ts/button.template.ts.run_vrtlabel is applied.Manual review test cases
VRT Grid — Button
Testing preview toggle
Device review
Accessibility testing checklist
N/A for Storybook infrastructure. VRT forced states only affect visual presentation in Storybook and do not change runtime a11y behavior for consumers.