chore(storybook): drop the redundant setProjectAnnotations setup file
Since Storybook 10.3, @storybook/addon-vitest provisions the preview annotations itself — and *skips* doing so when it finds a setup file calling setProjectAnnotations. So .storybook/vitest.setup.ts was not merely redundant, it was actively opting the project out of the automatic path, which the addon printed a notice about on every run. Remove the file and the `setupFiles` entry from the `storybook` vitest project. A green suite doesn't prove the automatic provisioning works: without the preview annotations, stories would render outside MantineProvider and without App.css, and would very likely still pass. Add src/test/PreviewAnnotations.stories.tsx, which asserts from a play function that the Mantine theme variables and the App.css tokens are actually present in the rendered document, so an unthemed render fails loudly. Verified by emptying `decorators` in preview.tsx and confirming the story goes red. The a11y addon's axe runner can't be introspected from a play function, so it was checked out-of-band: a story with a real violation turned the suite red with the setup file already removed, confirming @storybook/addon-a11y/preview is applied automatically. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0119LaPQ3v4NyBK3ZTdM9j84
This commit is contained in:
parent
a09f2dcf1d
commit
ca70a7cfa7
3 changed files with 87 additions and 8 deletions
|
|
@ -1,7 +0,0 @@
|
|||
import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
|
||||
import { setProjectAnnotations } from "@storybook/react-vite";
|
||||
import * as projectAnnotations from "./preview";
|
||||
|
||||
// This is an important step to apply the right configuration when testing your stories.
|
||||
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
|
||||
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
|
||||
78
clients/web/src/test/PreviewAnnotations.stories.tsx
Normal file
78
clients/web/src/test/PreviewAnnotations.stories.tsx
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
import { Button } from "@mantine/core";
|
||||
import type { Meta, StoryObj } from "@storybook/react-vite";
|
||||
import { expect, within } from "storybook/test";
|
||||
import { theme } from "../theme/theme";
|
||||
|
||||
// Guard for #1898.
|
||||
//
|
||||
// `.storybook/vitest.setup.ts` used to call `setProjectAnnotations([...])` to
|
||||
// hand the preview annotations to the Storybook vitest project. Since Storybook
|
||||
// 10.3 `@storybook/addon-vitest` applies them automatically — and *skips* doing
|
||||
// so when it finds such a setup file — so the file was removed and the
|
||||
// `setupFiles` entry dropped from the `storybook` project in `vite.config.ts`.
|
||||
//
|
||||
// A green suite is not evidence that the automatic path works. Two things the
|
||||
// setup file used to provision are silently losable:
|
||||
//
|
||||
// • `./preview`'s decorator, which wraps every story in `MantineProvider`
|
||||
// with the project theme, and its `import "../src/App.css"`, which defines
|
||||
// the `--inspector-*` tokens. Without them stories render unthemed and
|
||||
// unstyled — and would very likely still pass their play functions.
|
||||
// • `@storybook/addon-a11y/preview`, which runs axe after each play function.
|
||||
// Without it the `a11y: { test: "error" }` parameter is inert and every
|
||||
// story passes its accessibility check vacuously.
|
||||
//
|
||||
// The story below closes the first gap: it asserts the Mantine theme variables
|
||||
// and the `App.css` tokens are actually present in the rendered document, so an
|
||||
// unthemed render fails loudly rather than passing. It also asserts the preview
|
||||
// `parameters` reached the story, which is the same channel the a11y parameter
|
||||
// arrives on. The axe *runner* itself can't be introspected from a play
|
||||
// function; it was verified out-of-band by temporarily giving a story a real
|
||||
// violation and confirming the suite went red (see the PR for #1898).
|
||||
|
||||
// The primary shade the theme pins for the light scheme — the value Mantine
|
||||
// derives `--mantine-primary-color-filled` from. Read from the theme rather
|
||||
// than hard-coded so a palette change can't silently invalidate the guard.
|
||||
const LIGHT_PRIMARY_SHADE = 7;
|
||||
|
||||
function expectedPrimaryColor(): string {
|
||||
const palette = theme.colors?.[theme.primaryColor ?? ""];
|
||||
const color = palette?.[LIGHT_PRIMARY_SHADE];
|
||||
if (!color) throw new Error("theme is missing its primary color palette");
|
||||
return color;
|
||||
}
|
||||
|
||||
const meta: Meta<typeof Button> = {
|
||||
title: "Meta/Preview Annotations",
|
||||
component: Button,
|
||||
args: { children: "Themed" },
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof Button>;
|
||||
|
||||
export const ProjectAnnotationsApplied: Story = {
|
||||
play: async ({ canvasElement, parameters }) => {
|
||||
const canvas = within(canvasElement);
|
||||
expect(canvas.getByRole("button", { name: "Themed" })).toBeInTheDocument();
|
||||
|
||||
const root = getComputedStyle(document.documentElement);
|
||||
|
||||
// `MantineProvider` (the `./preview` decorator) injects the theme's CSS
|
||||
// variables onto `:root`. No provider, no variables.
|
||||
expect(root.getPropertyValue("--mantine-primary-color-filled").trim()).toBe(
|
||||
expectedPrimaryColor(),
|
||||
);
|
||||
|
||||
// `--inspector-brand-primary` is defined in `App.css`, which only reaches
|
||||
// the story through `./preview`'s stylesheet import — and it resolves
|
||||
// *through* the Mantine variable above, so this covers both layers.
|
||||
expect(root.getPropertyValue("--inspector-brand-primary").trim()).toBe(
|
||||
expectedPrimaryColor(),
|
||||
);
|
||||
|
||||
// The preview `parameters` merged into the story context — the same channel
|
||||
// that carries `a11y: { test: "error" }` to the a11y addon.
|
||||
expect(parameters.a11y).toMatchObject({ test: "error" });
|
||||
},
|
||||
};
|
||||
|
|
@ -379,7 +379,15 @@ export default defineConfig(({ command }) => {
|
|||
},
|
||||
],
|
||||
},
|
||||
setupFiles: [".storybook/vitest.setup.ts"],
|
||||
// No `setupFiles`: since Storybook 10.3 `@storybook/addon-vitest`
|
||||
// provisions the preview annotations (`.storybook/preview.tsx` plus
|
||||
// `@storybook/addon-a11y/preview`) itself, and *skips* doing so when
|
||||
// it finds a setup file calling `setProjectAnnotations` — so the old
|
||||
// `.storybook/vitest.setup.ts` was both redundant and actively
|
||||
// opting out of the automatic path (#1898). A green suite doesn't
|
||||
// prove the automatic provisioning works (stories rendered without
|
||||
// the Mantine decorator would very likely still pass), so
|
||||
// `src/test/PreviewAnnotations.stories.tsx` asserts it directly.
|
||||
},
|
||||
},
|
||||
],
|
||||
|
|
|
|||
Loading…
Reference in a new issue