',
+ target: ['.css-1av19vu'],
+ },
+ ],
+ impact: 'serious',
+ message:
+ 'Element has insufficient color contrast of 2.76 (foreground color: #029cfd, background color: #f6f9fc, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1',
+ '_constructor-name_': 'CheckResult',
+ },
+ ],
+ all: [],
+ none: [],
+ impact: 'serious',
+ html: '
',
+ target: ['.css-1mjgzsp'],
+ failureSummary:
+ 'Fix any of the following:\n Element has insufficient color contrast of 2.76 (foreground color: #029cfd, background color: #f6f9fc, font size: 10.5pt (14px), font weight: normal). Expected contrast ratio of 4.5:1',
+ },
+ ],
+ },
+];
+
+describe('afterEach', () => {
+ beforeEach(() => {
+ vi.mocked(getIsVitestRunning).mockReturnValue(false);
+ vi.mocked(getIsVitestStandaloneRun).mockReturnValue(true);
+ });
+
+ const createContext = (overrides: Partial = {}): StoryContext =>
+ ({
+ reporting: {
+ reports: [],
+ addReport: vi.fn(),
+ },
+ parameters: {
+ a11y: {},
+ },
+ globals: {
+ a11y: {},
+ },
+ tags: [A11Y_TEST_TAG],
+ ...overrides,
+ }) as any;
+
+ it('should run accessibility checks and report results', async () => {
+ const context = createContext();
+ const result = {
+ violations,
+ };
+
+ mockedRun.mockResolvedValue(result as any);
+
+ await expect(() => experimental_afterEach(context)).rejects.toThrow();
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'failed',
+ });
+ });
+
+ it('should run accessibility checks and report results without throwing', async () => {
+ const context = createContext();
+ const result = {
+ violations,
+ };
+
+ mockedRun.mockResolvedValue(result as any);
+ mocks.getIsVitestStandaloneRun.mockReturnValue(false);
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'failed',
+ });
+ });
+
+ it('should report passed status when there are no violations', async () => {
+ const context = createContext();
+ const result = {
+ violations: [],
+ };
+ mockedRun.mockResolvedValue(result as any);
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'passed',
+ });
+ });
+
+ it('should report warning status when there are only warnings', async () => {
+ const context = createContext({
+ parameters: {
+ a11y: {
+ warnings: ['minor'],
+ },
+ },
+ });
+ const result = {
+ violations: [
+ { impact: 'minor', nodes: [] },
+ { impact: 'critical', nodes: [] },
+ ],
+ };
+ mockedRun.mockResolvedValue(result as any);
+
+ await expect(async () => experimental_afterEach(context)).rejects.toThrow();
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'failed',
+ });
+ });
+
+ it('should report error status when there are warnings and errors', async () => {
+ const context = createContext({
+ parameters: {
+ a11y: {
+ warnings: ['minor'],
+ },
+ },
+ });
+ const result = {
+ violations: [
+ { impact: 'minor', nodes: [] },
+ { impact: 'critical', nodes: [] },
+ ],
+ };
+ mockedRun.mockResolvedValue(result as any);
+
+ await expect(async () => experimental_afterEach(context)).rejects.toThrow();
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'failed',
+ });
+ });
+
+ it('should run accessibility checks if "a11ytest" flag is not available and is not running in Vitest', async () => {
+ const context = createContext({
+ tags: [],
+ });
+ const result = {
+ violations: [],
+ };
+ mockedRun.mockResolvedValue(result as any);
+ vi.mocked(getIsVitestRunning).mockReturnValue(false);
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result,
+ status: 'passed',
+ });
+ });
+
+ it('should not run accessibility checks when manual is true', async () => {
+ const context = createContext({
+ parameters: {
+ a11y: {
+ manual: true,
+ },
+ },
+ });
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).not.toHaveBeenCalled();
+ expect(context.reporting.addReport).not.toHaveBeenCalled();
+ });
+
+ it('should not run accessibility checks when disable is true', async () => {
+ const context = createContext({
+ parameters: {
+ a11y: {
+ disable: true,
+ },
+ },
+ });
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).not.toHaveBeenCalled();
+ expect(context.reporting.addReport).not.toHaveBeenCalled();
+ });
+
+ it('should not run accessibility checks when globals manual is true', async () => {
+ const context = createContext({
+ globals: {
+ a11y: {
+ manual: true,
+ },
+ },
+ });
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).not.toHaveBeenCalled();
+ expect(context.reporting.addReport).not.toHaveBeenCalled();
+ });
+
+ it('should not run accessibility checks if vitest is running and story is not tagged with a11ytest', async () => {
+ const context = createContext({
+ tags: [],
+ });
+ vi.mocked(getIsVitestRunning).mockReturnValue(true);
+
+ await experimental_afterEach(context);
+
+ expect(mockedRun).not.toHaveBeenCalled();
+ expect(context.reporting.addReport).not.toHaveBeenCalled();
+ });
+
+ it('should report error when run throws an error', async () => {
+ const context = createContext();
+ const error = new Error('Test error');
+ mockedRun.mockRejectedValue(error);
+
+ await expect(() => experimental_afterEach(context)).rejects.toThrow();
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result: {
+ error,
+ },
+ status: 'failed',
+ });
+ });
+
+ it('should report error when run throws an error', async () => {
+ const context = createContext();
+ const error = new Error('Test error');
+ mockedRun.mockRejectedValue(error);
+
+ await expect(() => experimental_afterEach(context)).rejects.toThrow();
+
+ expect(mockedRun).toHaveBeenCalledWith(context.parameters.a11y);
+ expect(context.reporting.addReport).toHaveBeenCalledWith({
+ type: 'a11y',
+ version: 1,
+ result: {
+ error,
+ },
+ status: 'failed',
+ });
+ });
+});
diff --git a/code/addons/a11y/src/preview.tsx b/code/addons/a11y/src/preview.tsx
index 1325793c119a..f7d2f9aa43ff 100644
--- a/code/addons/a11y/src/preview.tsx
+++ b/code/addons/a11y/src/preview.tsx
@@ -1 +1,95 @@
-import './a11yRunner';
+// Source: https://github.com/chaance/vitest-axe/blob/main/src/to-have-no-violations.ts
+import * as matchers from 'vitest-axe/matchers';
+
+import type { AfterEach } from 'storybook/internal/types';
+
+import { expect } from '@storybook/test';
+
+import { run } from './a11yRunner';
+import { A11Y_TEST_TAG } from './constants';
+import type { A11yParameters } from './params';
+import { getIsVitestRunning, getIsVitestStandaloneRun } from './utils';
+
+expect.extend(matchers);
+
+// eslint-disable-next-line @typescript-eslint/naming-convention
+export const experimental_afterEach: AfterEach = async ({
+ reporting,
+ parameters,
+ globals,
+ tags,
+}) => {
+ const a11yParameter: A11yParameters | undefined = parameters.a11y;
+ const a11yGlobals = globals.a11y;
+ const warnings = a11yParameter?.warnings ?? [];
+
+ const shouldRunEnvironmentIndependent =
+ a11yParameter?.manual !== true &&
+ a11yParameter?.disable !== true &&
+ a11yGlobals?.manual !== true;
+
+ if (shouldRunEnvironmentIndependent) {
+ if (getIsVitestRunning() && !tags.includes(A11Y_TEST_TAG)) {
+ return;
+ }
+ try {
+ const result = await run(a11yParameter);
+
+ if (result) {
+ const hasViolations = (result?.violations.length ?? 0) > 0;
+
+ const hasErrors = result?.violations.some(
+ (violation) => !warnings.includes(violation.impact!)
+ );
+
+ reporting.addReport({
+ type: 'a11y',
+ version: 1,
+ result: result,
+ status: hasErrors ? 'failed' : hasViolations ? 'warning' : 'passed',
+ });
+
+ /**
+ * When Vitest is running outside of Storybook, we need to throw an error to fail the test
+ * run when there are accessibility issues.
+ *
+ * @todo In the future, we want to always throw an error when there are accessibility
+ * issues. This is a temporary solution. Later, portable stories and Storybook should
+ * implement proper try catch handling.
+ */
+ if (getIsVitestStandaloneRun()) {
+ if (hasErrors) {
+ // @ts-expect-error - todo - fix type extension of expect from @storybook/test
+ expect(result).toHaveNoViolations();
+ }
+ }
+ }
+ /**
+ * @todo Later we don't want to catch errors here. Instead, we want to throw them and let
+ * Storybook/portable stories handle them on a higher level.
+ */
+ } catch (e) {
+ reporting.addReport({
+ type: 'a11y',
+ version: 1,
+ result: {
+ error: e,
+ },
+ status: 'failed',
+ });
+
+ if (getIsVitestStandaloneRun()) {
+ throw e;
+ }
+ }
+ }
+};
+
+export const initialGlobals = {
+ a11y: {
+ manual: false,
+ },
+};
+
+// A11Y_TEST_TAG constant in ./constants.ts. Has to be statically analyzable.
+export const tags = ['a11ytest'];
diff --git a/code/addons/a11y/src/types.ts b/code/addons/a11y/src/types.ts
new file mode 100644
index 000000000000..9e116e5aab2b
--- /dev/null
+++ b/code/addons/a11y/src/types.ts
@@ -0,0 +1,3 @@
+import type { AxeResults } from 'axe-core';
+
+export type A11YReport = AxeResults | { error: Error };
diff --git a/code/addons/a11y/src/utils.ts b/code/addons/a11y/src/utils.ts
new file mode 100644
index 000000000000..0864a2e3b2f7
--- /dev/null
+++ b/code/addons/a11y/src/utils.ts
@@ -0,0 +1,25 @@
+export function getIsVitestStandaloneRun() {
+ try {
+ return process.env.VITEST_STORYBOOK === 'false';
+ } catch {
+ try {
+ // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.
+ return import.meta.env.VITEST_STORYBOOK === 'false';
+ } catch (e) {
+ return false;
+ }
+ }
+}
+
+export function getIsVitestRunning() {
+ try {
+ return process?.env.MODE === 'test';
+ } catch {
+ try {
+ // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.
+ return import.meta.env.MODE === 'test';
+ } catch (e) {
+ return false;
+ }
+ }
+}
diff --git a/code/addons/actions/package.json b/code/addons/actions/package.json
index efb51f302fc5..fe4159ba7501 100644
--- a/code/addons/actions/package.json
+++ b/code/addons/actions/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-actions",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Get UI feedback when an action is performed on an interactive element",
"keywords": [
"storybook",
diff --git a/code/addons/backgrounds/package.json b/code/addons/backgrounds/package.json
index 2bfa78900bc6..e16e07c7a3b9 100644
--- a/code/addons/backgrounds/package.json
+++ b/code/addons/backgrounds/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-backgrounds",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Switch backgrounds to view components in different settings",
"keywords": [
"addon",
diff --git a/code/addons/controls/package.json b/code/addons/controls/package.json
index 255546cd3bd6..0eedc655d161 100644
--- a/code/addons/controls/package.json
+++ b/code/addons/controls/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-controls",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Interact with component inputs dynamically in the Storybook UI",
"keywords": [
"addon",
diff --git a/code/addons/docs/package.json b/code/addons/docs/package.json
index f5834a822026..daf9acd64148 100644
--- a/code/addons/docs/package.json
+++ b/code/addons/docs/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-docs",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Document component usage and properties in Markdown",
"keywords": [
"addon",
diff --git a/code/addons/essentials/package.json b/code/addons/essentials/package.json
index 4f7ad700ec0d..23bad764705f 100644
--- a/code/addons/essentials/package.json
+++ b/code/addons/essentials/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-essentials",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Curated addons to bring out the best of Storybook",
"keywords": [
"addon",
diff --git a/code/addons/gfm/package.json b/code/addons/gfm/package.json
index 277e1663e385..8641c5a7f4ef 100644
--- a/code/addons/gfm/package.json
+++ b/code/addons/gfm/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-mdx-gfm",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "GitHub Flavored Markdown in Storybook",
"keywords": [
"addon",
diff --git a/code/addons/highlight/package.json b/code/addons/highlight/package.json
index dc5588ee1d30..f78228db1657 100644
--- a/code/addons/highlight/package.json
+++ b/code/addons/highlight/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-highlight",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Highlight DOM nodes within your stories",
"keywords": [
"storybook-addons",
diff --git a/code/addons/interactions/package.json b/code/addons/interactions/package.json
index 801c627195a0..f8123e69278a 100644
--- a/code/addons/interactions/package.json
+++ b/code/addons/interactions/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-interactions",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Automate, test and debug user interactions",
"keywords": [
"storybook-addons",
diff --git a/code/addons/interactions/src/components/Interaction.tsx b/code/addons/interactions/src/components/Interaction.tsx
index 610d0c1b032b..4ceef384d02a 100644
--- a/code/addons/interactions/src/components/Interaction.tsx
+++ b/code/addons/interactions/src/components/Interaction.tsx
@@ -37,7 +37,7 @@ const RowContainer = styled('div', {
? transparentize(0.93, theme.color.negative)
: theme.background.warning,
}),
- paddingLeft: call.ancestors.length * 20,
+ paddingLeft: (call.ancestors?.length ?? 0) * 20,
}),
({ theme, call, pausedAt }) =>
pausedAt === call.id && {
@@ -164,7 +164,7 @@ export const Interaction = ({
pausedAt?: Call['id'];
}) => {
const [isHovered, setIsHovered] = React.useState(false);
- const isInteractive = !controlStates.goto || !call.interceptable || !!call.ancestors.length;
+ const isInteractive = !controlStates.goto || !call.interceptable || !!call.ancestors?.length;
if (isHidden) {
return null;
diff --git a/code/addons/interactions/src/components/MethodCall.tsx b/code/addons/interactions/src/components/MethodCall.tsx
index fbe5ee038afb..c272f7863065 100644
--- a/code/addons/interactions/src/components/MethodCall.tsx
+++ b/code/addons/interactions/src/components/MethodCall.tsx
@@ -429,7 +429,7 @@ export const MethodCall = ({
return ;
}
- const path = call.path.flatMap((elem, index) => {
+ const path = call.path?.flatMap((elem, index) => {
// eslint-disable-next-line no-underscore-dangle
const callId = (elem as CallRef).__callId__;
return [
@@ -443,7 +443,7 @@ export const MethodCall = ({
];
});
- const args = call.args.flatMap((arg, index, array) => {
+ const args = call.args?.flatMap((arg, index, array) => {
const node = ;
return index < array.length - 1
? [node, , , ]
diff --git a/code/addons/jest/package.json b/code/addons/jest/package.json
index 42f5f52b88aa..9794ab8acede 100644
--- a/code/addons/jest/package.json
+++ b/code/addons/jest/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-jest",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "React storybook addon that show component jest report",
"keywords": [
"addon",
diff --git a/code/addons/links/package.json b/code/addons/links/package.json
index 5a99aa4267c9..18de0fcea3ab 100644
--- a/code/addons/links/package.json
+++ b/code/addons/links/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-links",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Link stories together to build demos and prototypes with your UI components",
"keywords": [
"storybook-addons",
@@ -65,7 +65,7 @@
"prep": "jiti ../../../scripts/prepare/addon-bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/global": "^5.0.0",
"ts-dedent": "^2.0.0"
},
diff --git a/code/addons/measure/package.json b/code/addons/measure/package.json
index dfebd2ef6b2d..181306c74e48 100644
--- a/code/addons/measure/package.json
+++ b/code/addons/measure/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-measure",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Inspect layouts by visualizing the box model",
"keywords": [
"storybook-addons",
diff --git a/code/addons/onboarding/package.json b/code/addons/onboarding/package.json
index 0fc9ef53a4ef..2ae0859fb9d3 100644
--- a/code/addons/onboarding/package.json
+++ b/code/addons/onboarding/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-onboarding",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Addon Onboarding - Introduces a new onboarding experience",
"keywords": [
"storybook-addons",
diff --git a/code/addons/outline/package.json b/code/addons/outline/package.json
index 05786228223d..42eb08c6be81 100644
--- a/code/addons/outline/package.json
+++ b/code/addons/outline/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-outline",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Outline all elements with CSS to help with layout placement and alignment",
"keywords": [
"storybook-addons",
diff --git a/code/addons/storysource/package.json b/code/addons/storysource/package.json
index 104218a0957c..e8a04d1edff9 100644
--- a/code/addons/storysource/package.json
+++ b/code/addons/storysource/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-storysource",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "View a story’s source code to see how it works and paste into your app",
"keywords": [
"addon",
diff --git a/code/addons/test/package.json b/code/addons/test/package.json
index 9bcf07d466d2..1652327a9801 100644
--- a/code/addons/test/package.json
+++ b/code/addons/test/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/experimental-addon-test",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Integrate Vitest with Storybook",
"keywords": [
"storybook-addons",
@@ -80,7 +80,7 @@
"prep": "jiti ../../../scripts/prepare/addon-bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/global": "^5.0.0",
"@storybook/icons": "^1.2.12",
"@storybook/instrumenter": "workspace:*",
diff --git a/code/addons/test/src/components/Interaction.tsx b/code/addons/test/src/components/Interaction.tsx
index 610d0c1b032b..4ceef384d02a 100644
--- a/code/addons/test/src/components/Interaction.tsx
+++ b/code/addons/test/src/components/Interaction.tsx
@@ -37,7 +37,7 @@ const RowContainer = styled('div', {
? transparentize(0.93, theme.color.negative)
: theme.background.warning,
}),
- paddingLeft: call.ancestors.length * 20,
+ paddingLeft: (call.ancestors?.length ?? 0) * 20,
}),
({ theme, call, pausedAt }) =>
pausedAt === call.id && {
@@ -164,7 +164,7 @@ export const Interaction = ({
pausedAt?: Call['id'];
}) => {
const [isHovered, setIsHovered] = React.useState(false);
- const isInteractive = !controlStates.goto || !call.interceptable || !!call.ancestors.length;
+ const isInteractive = !controlStates.goto || !call.interceptable || !!call.ancestors?.length;
if (isHidden) {
return null;
diff --git a/code/addons/test/src/components/MethodCall.tsx b/code/addons/test/src/components/MethodCall.tsx
index fbe5ee038afb..59b907d13daa 100644
--- a/code/addons/test/src/components/MethodCall.tsx
+++ b/code/addons/test/src/components/MethodCall.tsx
@@ -425,11 +425,11 @@ export const MethodCall = ({
return null;
}
- if (call.method === 'step' && call.path.length === 0) {
+ if (call.method === 'step' && call.path?.length === 0) {
return ;
}
- const path = call.path.flatMap((elem, index) => {
+ const path = call.path?.flatMap((elem, index) => {
// eslint-disable-next-line no-underscore-dangle
const callId = (elem as CallRef).__callId__;
return [
@@ -443,7 +443,7 @@ export const MethodCall = ({
];
});
- const args = call.args.flatMap((arg, index, array) => {
+ const args = call.args?.flatMap((arg, index, array) => {
const node = ;
return index < array.length - 1
? [node, , , ]
diff --git a/code/addons/test/src/components/TestProviderRender.stories.tsx b/code/addons/test/src/components/TestProviderRender.stories.tsx
index 9345ebbaff82..dead913949cf 100644
--- a/code/addons/test/src/components/TestProviderRender.stories.tsx
+++ b/code/addons/test/src/components/TestProviderRender.stories.tsx
@@ -64,6 +64,7 @@ const baseState: TestProviderState = {
status: 'passed',
duration: 100,
testRunId: 'test-run-id',
+ reports: [],
},
],
},
diff --git a/code/addons/test/src/components/TestProviderRender.tsx b/code/addons/test/src/components/TestProviderRender.tsx
index 16197a7c7ced..abc6790849c9 100644
--- a/code/addons/test/src/components/TestProviderRender.tsx
+++ b/code/addons/test/src/components/TestProviderRender.tsx
@@ -1,11 +1,12 @@
-import React, { type ComponentProps, type FC, useCallback, useRef, useState } from 'react';
+import React, { type ComponentProps, type FC, useCallback, useMemo, useRef, useState } from 'react';
-import { Button, ListItem } from 'storybook/internal/components';
+import { Button, ListItem, ProgressSpinner } from 'storybook/internal/components';
import {
TESTING_MODULE_CONFIG_CHANGE,
type TestProviderConfig,
type TestProviderState,
} from 'storybook/internal/core-events';
+import { addons } from 'storybook/internal/manager-api';
import type { API } from 'storybook/internal/manager-api';
import { styled, useTheme } from 'storybook/internal/theming';
@@ -16,12 +17,14 @@ import {
PlayHollowIcon,
PointerHandIcon,
ShieldIcon,
- StopAltHollowIcon,
+ StopAltIcon,
} from '@storybook/icons';
import { isEqual } from 'es-toolkit';
import { debounce } from 'es-toolkit/compat';
+// Relatively importing from a11y to get the ADDON_ID
+import { ADDON_ID as A11Y_ADDON_ID } from '../../../a11y/src/constants';
import { type Config, type Details } from '../constants';
import { type TestStatus } from '../node/reporter';
import { Description } from './Description';
@@ -63,6 +66,14 @@ const Checkbox = styled.input({
},
});
+const Progress = styled(ProgressSpinner)({
+ margin: 2,
+});
+
+const StopIcon = styled(StopAltIcon)({
+ width: 10,
+});
+
const statusOrder: TestStatus[] = ['failed', 'warning', 'pending', 'passed', 'skipped'];
const statusMap: Record['status']> = {
failed: 'negative',
@@ -83,12 +94,51 @@ export const TestProviderRender: FC<
const theme = useTheme();
const coverageSummary = state.details?.coverageSummary;
+ const isA11yAddon = addons.experimental_getRegisteredAddons().includes(A11Y_ADDON_ID);
+
const [config, updateConfig] = useConfig(
api,
state.id,
state.config || { a11y: false, coverage: false }
);
+ const a11yResults = useMemo(() => {
+ if (!isA11yAddon) {
+ return [];
+ }
+
+ return state.details?.testResults?.flatMap((result) =>
+ result.results
+ .filter((it) => !entryId || it.storyId === entryId || it.storyId.startsWith(`${entryId}-`))
+ .map((r) => r.reports.find((report) => report.type === 'a11y'))
+ );
+ }, [isA11yAddon, state.details?.testResults, entryId]);
+
+ const a11yStatus = useMemo<'positive' | 'warning' | 'negative' | 'unknown'>(() => {
+ if (!isA11yAddon || config.a11y === false) {
+ return 'unknown';
+ }
+
+ if (!a11yResults) {
+ return 'unknown';
+ }
+
+ const failed = a11yResults.some((result) => result?.status === 'failed');
+ const warning = a11yResults.some((result) => result?.status === 'warning');
+
+ if (failed) {
+ return 'negative';
+ } else if (warning) {
+ return 'warning';
+ }
+
+ return 'positive';
+ }, [a11yResults, isA11yAddon, config.a11y]);
+
+ const a11yNotPassedAmount = a11yResults?.filter(
+ (result) => result?.status === 'failed' || result?.status === 'warning'
+ ).length;
+
const storyId = entryId?.includes('--') ? entryId : undefined;
const results = (state.details?.testResults || [])
.flatMap((test) => {
@@ -140,11 +190,13 @@ export const TestProviderRender: FC<
api.cancelTestProvider(state.id)}
disabled={state.cancelling}
>
-
+
+
+
) : (
}
/>
+ {isA11yAddon && (
+ }
+ right={
+ updateConfig({ a11y: !config.a11y })}
+ />
+ }
+ />
+ )}
) : (
@@ -219,6 +285,13 @@ export const TestProviderRender: FC<
icon={ }
/>
)}
+ {isA11yAddon && (
+ }
+ right={a11yNotPassedAmount || null}
+ />
+ )}
)}
diff --git a/code/addons/test/src/manager.tsx b/code/addons/test/src/manager.tsx
index 0664fc140627..c5c4b9f21402 100644
--- a/code/addons/test/src/manager.tsx
+++ b/code/addons/test/src/manager.tsx
@@ -77,29 +77,60 @@ addons.register(ADDON_ID, (api) => {
return;
}
- api.experimental_updateStatus(
- TEST_PROVIDER_ID,
- Object.fromEntries(
- update.details.testResults.flatMap((testResult) =>
- testResult.results
- .filter(({ storyId }) => storyId)
- .map(({ storyId, status, testRunId, ...rest }) => [
- storyId,
- {
- title: 'Component tests',
- status: statusMap[status],
- description:
- 'failureMessages' in rest && rest.failureMessages
- ? rest.failureMessages.join('\n')
- : '',
- data: { testRunId },
- onClick: openAddonPanel,
- sidebarContextMenu: false,
- } as API_StatusObject,
- ])
+ (async () => {
+ await api.experimental_updateStatus(
+ TEST_PROVIDER_ID,
+ Object.fromEntries(
+ update.details.testResults.flatMap((testResult) =>
+ testResult.results
+ .filter(({ storyId }) => storyId)
+ .map(({ storyId, status, testRunId, ...rest }) => [
+ storyId,
+ {
+ title: 'Component tests',
+ status: statusMap[status],
+ description:
+ 'failureMessages' in rest && rest.failureMessages
+ ? rest.failureMessages.join('\n')
+ : '',
+ data: { testRunId },
+ onClick: openAddonPanel,
+ sidebarContextMenu: false,
+ } as API_StatusObject,
+ ])
+ )
)
- )
- );
+ );
+
+ await api.experimental_updateStatus(
+ 'storybook/addon-a11y/test-provider',
+ Object.fromEntries(
+ update.details.testResults.flatMap((testResult) =>
+ testResult.results
+ .filter(({ storyId }) => storyId)
+ .map(({ storyId, status, testRunId, reports, ...rest }) => {
+ const a11yReport = reports.find((r: any) => r.type === 'a11y');
+ return [
+ storyId,
+ a11yReport
+ ? {
+ title: 'Accessibility tests',
+ description: '',
+ status: statusMap[a11yReport.status],
+ data: { testRunId },
+ onClick: () => {
+ api.setSelectedPanel('storybook/a11y/panel');
+ api.togglePanel(true);
+ },
+ sidebarContextMenu: false,
+ }
+ : null,
+ ] as const;
+ })
+ )
+ )
+ );
+ })();
},
} as Addon_TestProviderType);
}
diff --git a/code/addons/test/src/node/reporter.ts b/code/addons/test/src/node/reporter.ts
index 7405cf740c7b..69b9b0222118 100644
--- a/code/addons/test/src/node/reporter.ts
+++ b/code/addons/test/src/node/reporter.ts
@@ -6,15 +6,11 @@ import type {
TestingModuleProgressReportPayload,
TestingModuleProgressReportProgress,
} from 'storybook/internal/core-events';
+import type { Report } from 'storybook/internal/preview-api';
import type { API_StatusUpdate } from '@storybook/types';
import type { Suite } from '@vitest/runner';
-// TODO
-// We can theoretically avoid the `@vitest/runner` dependency by copying over the necessary
-// functions from the `@vitest/runner` package. It is not complex and does not have
-// any significant dependencies.
-import { getTests } from '@vitest/runner/utils';
import { throttle } from 'es-toolkit';
import { TEST_PROVIDER_ID } from '../constants';
@@ -28,6 +24,7 @@ export type TestResultResult =
storyId: string;
testRunId: string;
duration: number;
+ reports: Report[];
}
| {
status: Extract;
@@ -35,6 +32,7 @@ export type TestResultResult =
duration: number;
testRunId: string;
failureMessages: string[];
+ reports: Report[];
};
export type TestResult = {
@@ -72,7 +70,13 @@ export class StorybookReporter implements Reporter {
this.start = Date.now();
}
- getProgressReport(finishedAt?: number) {
+ async getProgressReport(finishedAt?: number) {
+ // TODO
+ // We can theoretically avoid the `@vitest/runner` dependency by copying over the necessary
+ // functions from the `@vitest/runner` package. It is not complex and does not have
+ // any significant dependencies.
+ const { getTests } = await import('@vitest/runner/utils');
+
const files = this.ctx.state.getFiles();
const fileTests = getTests(files).filter((t) => t.mode === 'run' || t.mode === 'only');
@@ -113,16 +117,30 @@ export class StorybookReporter implements Reporter {
const status = statusMap[t.result?.state || t.mode] || 'skipped';
const storyId = (t.meta as any).storyId as string;
+ const reports =
+ ((t.meta as any).reports as Report[])?.map((report) => ({
+ status: report.status,
+ type: report.type,
+ })) ?? [];
const duration = t.result?.duration || 0;
const testRunId = this.start.toString();
switch (status) {
case 'passed':
case 'pending':
- return [{ status, storyId, duration, testRunId } as TestResultResult];
+ return [{ status, storyId, duration, testRunId, reports } as TestResultResult];
case 'failed':
const failureMessages = t.result?.errors?.map((e) => e.stack || e.message) || [];
- return [{ status, storyId, duration, failureMessages, testRunId } as TestResultResult];
+ return [
+ {
+ status,
+ storyId,
+ duration,
+ failureMessages,
+ testRunId,
+ reports,
+ } as TestResultResult,
+ ];
default:
return [];
}
@@ -147,6 +165,11 @@ export class StorybookReporter implements Reporter {
numTotalTests,
startedAt: this.start,
finishedAt,
+ percentageCompleted: finishedAt
+ ? 100
+ : numTotalTests
+ ? ((numPassedTests + numFailedTests) / numTotalTests) * 100
+ : 0,
} as TestingModuleProgressReportProgress,
details: {
testResults,
@@ -159,7 +182,7 @@ export class StorybookReporter implements Reporter {
this.sendReport({
providerId: TEST_PROVIDER_ID,
status: 'pending',
- ...this.getProgressReport(),
+ ...(await this.getProgressReport()),
});
} catch (e) {
this.sendReport({
@@ -190,7 +213,7 @@ export class StorybookReporter implements Reporter {
const unhandledErrors = this.ctx.state.getUnhandledErrors();
const isCancelled = this.ctx.isCancelling;
- const report = this.getProgressReport(Date.now());
+ const report = await this.getProgressReport(Date.now());
const testSuiteFailures = report.details.testResults.filter(
(t) => t.status === 'failed' && t.results.length === 0
diff --git a/code/addons/test/src/node/test-manager.ts b/code/addons/test/src/node/test-manager.ts
index 544a23f5da49..430fd45eb409 100644
--- a/code/addons/test/src/node/test-manager.ts
+++ b/code/addons/test/src/node/test-manager.ts
@@ -45,6 +45,9 @@ export class TestManager {
if (payload.providerId !== TEST_PROVIDER_ID) {
return;
}
+
+ process.env.VITEST_STORYBOOK_CONFIG = JSON.stringify(payload.config);
+
if (this.coverage !== payload.config.coverage) {
try {
this.coverage = payload.config.coverage;
@@ -71,6 +74,13 @@ export class TestManager {
return;
}
+ if (payload.config) {
+ this.handleConfigChange({
+ providerId: payload.providerId,
+ config: payload.config as any,
+ });
+ }
+
if (this.watchMode !== payload.watchMode) {
this.watchMode = payload.watchMode;
await this.vitestManager.restartVitest({ watchMode: this.watchMode, coverage: false });
diff --git a/code/addons/test/src/node/vitest-manager.ts b/code/addons/test/src/node/vitest-manager.ts
index 9ce9139821bb..78c929732d7d 100644
--- a/code/addons/test/src/node/vitest-manager.ts
+++ b/code/addons/test/src/node/vitest-manager.ts
@@ -63,18 +63,32 @@ export class VitestManager {
: { enabled: false }
) as CoverageOptions;
- this.vitest = await createVitest('test', {
- watch: watchMode,
- passWithNoTests: false,
- changed: watchMode,
- // TODO:
- // Do we want to enable Vite's default reporter?
- // The output in the terminal might be too spamy and it might be better to
- // find a way to just show errors and warnings for example
- // Otherwise it might be hard for the user to discover Storybook related logs
- reporters: ['default', new StorybookReporter(this.testManager)],
- coverage: coverageOptions,
- });
+ this.vitest = await createVitest(
+ 'test',
+ {
+ watch: watchMode,
+ passWithNoTests: false,
+ changed: watchMode,
+ // TODO:
+ // Do we want to enable Vite's default reporter?
+ // The output in the terminal might be too spamy and it might be better to
+ // find a way to just show errors and warnings for example
+ // Otherwise it might be hard for the user to discover Storybook related logs
+ reporters: ['default', new StorybookReporter(this.testManager)],
+ coverage: coverageOptions,
+ },
+ {
+ define: {
+ // polyfilling process.env.VITEST_STORYBOOK to 'true' in the browser
+ 'process.env.VITEST_STORYBOOK': 'true',
+ },
+ }
+ );
+
+ this.vitest.configOverride.env = {
+ // We signal to the test runner that we are running it via Storybook
+ VITEST_STORYBOOK: 'true',
+ };
if (this.vitest) {
this.vitest.onCancel(() => {
diff --git a/code/addons/test/src/postinstall.ts b/code/addons/test/src/postinstall.ts
index dc4710a9ea7d..fc7fc1e8d862 100644
--- a/code/addons/test/src/postinstall.ts
+++ b/code/addons/test/src/postinstall.ts
@@ -22,10 +22,14 @@ import { dedent } from 'ts-dedent';
import { type PostinstallOptions } from '../../../lib/cli-storybook/src/add';
import { printError, printInfo, printSuccess, step } from './postinstall-logger';
+import { getAddonNames } from './utils';
const ADDON_NAME = '@storybook/experimental-addon-test' as const;
const EXTENSIONS = ['.js', '.jsx', '.ts', '.tsx', '.cts', '.mts', '.cjs', '.mjs'] as const;
+const addonInteractionsName = '@storybook/addon-interactions';
+const addonA11yName = '@storybook/addon-a11y';
+
const findFile = async (basename: string, extraExtensions: string[] = []) =>
findUp([...EXTENSIONS, ...extraExtensions].map((ext) => basename + ext));
@@ -145,12 +149,7 @@ export default async function postInstall(options: PostinstallOptions) {
return;
}
- const addonInteractionsName = '@storybook/addon-interactions';
- const interactionsAddon = info.addons.find((addon: string | { name: string }) => {
- // account for addons as objects, as well as addons with PnP paths
- const addonName = typeof addon === 'string' ? addon : addon.name;
- return addonName.includes(addonInteractionsName);
- });
+ const interactionsAddon = info.addons.find((addon) => addon.includes(addonInteractionsName));
if (!!interactionsAddon) {
let shouldUninstall = options.yes;
@@ -286,16 +285,33 @@ export default async function postInstall(options: PostinstallOptions) {
(config) => existsSync(config)
);
+ const a11yAddon = info.addons.find((addon) => addon.includes(addonA11yName));
+
+ const imports = [
+ `import { beforeAll } from 'vitest';`,
+ `import { setProjectAnnotations } from '${annotationsImport}';`,
+ ];
+
+ const projectAnnotations = [];
+
+ if (a11yAddon) {
+ imports.push(`import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';`);
+ projectAnnotations.push('a11yAddonAnnotations');
+ }
+
+ if (previewExists) {
+ imports.push(`import * as projectAnnotations from './preview';`);
+ projectAnnotations.push('projectAnnotations');
+ }
+
await writeFile(
vitestSetupFile,
dedent`
- import { beforeAll } from 'vitest';
- import { setProjectAnnotations } from '${annotationsImport}';
- ${previewExists ? `import * as projectAnnotations from './preview';` : ''}
+ ${imports.join('\n')}
// 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
- const project = setProjectAnnotations(${previewExists ? '[projectAnnotations]' : '[]'});
+ const project = setProjectAnnotations([${projectAnnotations.join(', ')}]);
beforeAll(project.beforeAll);
`
@@ -491,6 +507,7 @@ async function getStorybookInfo({ configDir, packageManager: pkgMgr }: Postinsta
const frameworkName = typeof framework === 'string' ? framework : framework?.name;
validateFrameworkName(frameworkName);
const frameworkPackageName = extractProperFrameworkName(frameworkName);
+ const addons = getAddonNames(config);
const presets = await loadAllPresets({
corePresets: [join(frameworkName, 'preset')],
@@ -529,6 +546,6 @@ async function getStorybookInfo({ configDir, packageManager: pkgMgr }: Postinsta
frameworkPackageName,
builderPackageName,
rendererPackageName,
- addons: config.addons,
+ addons,
};
}
diff --git a/code/addons/test/src/utils.ts b/code/addons/test/src/utils.ts
index d890c6ec66e6..066f09af15f1 100644
--- a/code/addons/test/src/utils.ts
+++ b/code/addons/test/src/utils.ts
@@ -1,5 +1,7 @@
import { type StorybookTheme, useTheme } from 'storybook/internal/theming';
+import type { StorybookConfig } from '@storybook/types';
+
import Filter from 'ansi-to-html';
import stripAnsi from 'strip-ansi';
@@ -39,3 +41,19 @@ export function useAnsiToHtmlFilter() {
const theme = useTheme();
return createAnsiToHtmlFilter(theme);
}
+
+export function getAddonNames(mainConfig: StorybookConfig): string[] {
+ const addons = mainConfig.addons || [];
+ const addonList = addons.map((addon) => {
+ let name = '';
+ if (typeof addon === 'string') {
+ name = addon;
+ } else if (typeof addon === 'object') {
+ name = addon.name;
+ }
+
+ return name;
+ });
+
+ return addonList.filter((item): item is NonNullable => item != null);
+}
diff --git a/code/addons/test/src/vitest-plugin/global-setup.ts b/code/addons/test/src/vitest-plugin/global-setup.ts
index ac3a5f5a8fcd..bff48208229a 100644
--- a/code/addons/test/src/vitest-plugin/global-setup.ts
+++ b/code/addons/test/src/vitest-plugin/global-setup.ts
@@ -7,6 +7,18 @@ import { logger } from 'storybook/internal/node-logger';
let storybookProcess: ChildProcess | null = null;
+const getIsVitestStandaloneRun = () => {
+ try {
+ // @ts-expect-error Suppress TypeScript warning about wrong setting. Doesn't matter, because we don't use tsc for bundling.
+ return (import.meta.env || process?.env).STORYBOOK !== 'true';
+ } catch (e) {
+ return false;
+ }
+};
+
+const isVitestStandaloneRun = getIsVitestStandaloneRun();
+
+// TODO: Not run when executed via Storybook
const checkStorybookRunning = async (storybookUrl: string): Promise => {
try {
const response = await fetch(`${storybookUrl}/iframe.html`, { method: 'HEAD' });
@@ -56,7 +68,7 @@ const killProcess = (process: ChildProcess) => {
};
export const setup = async ({ config }: GlobalSetupContext) => {
- if (config.watch) {
+ if (config.watch && isVitestStandaloneRun) {
await startStorybookIfNotRunning();
}
};
diff --git a/code/addons/test/src/vitest-plugin/index.ts b/code/addons/test/src/vitest-plugin/index.ts
index fff8419a5a5f..def3eab2b796 100644
--- a/code/addons/test/src/vitest-plugin/index.ts
+++ b/code/addons/test/src/vitest-plugin/index.ts
@@ -18,6 +18,7 @@ import sirv from 'sirv';
import { convertPathToPattern } from 'tinyglobby';
import { dedent } from 'ts-dedent';
+import { TestManager } from '../node/test-manager';
import type { InternalOptions, UserOptions } from './types';
const defaultOptions: UserOptions = {
@@ -154,6 +155,9 @@ export const storybookTest = (options?: UserOptions): Plugin => {
...config.test.env,
// To be accessed by the setup file
__STORYBOOK_URL__: storybookUrl,
+ // We signal the test runner that we are not running it via Storybook
+ // We are overriding the environment variable to 'true' if vitest runs via @storybook/addon-test's backend
+ VITEST_STORYBOOK: 'false',
__VITEST_INCLUDE_TAGS__: finalOptions.tags.include.join(','),
__VITEST_EXCLUDE_TAGS__: finalOptions.tags.exclude.join(','),
__VITEST_SKIP_TAGS__: finalOptions.tags.skip.join(','),
@@ -162,7 +166,27 @@ export const storybookTest = (options?: UserOptions): Plugin => {
config.envPrefix = Array.from(new Set([...(config.envPrefix || []), 'STORYBOOK_', 'VITE_']));
if (config.test.browser) {
+ config.define ??= {
+ ...config.define,
+ // polyfilling process.env.VITEST_STORYBOOK to 'false' in the browser
+ 'process.env.VITEST_STORYBOOK': JSON.stringify('false'),
+ };
+
config.test.browser.screenshotFailures ??= false;
+
+ config.test.browser.commands ??= {
+ getInitialGlobals: () => {
+ const envConfig = JSON.parse(process.env.VITEST_STORYBOOK_CONFIG ?? '{}');
+
+ const isA11yEnabled = process.env.VITEST_STORYBOOK ? (envConfig.a11y ?? false) : true;
+
+ return {
+ a11y: {
+ manual: !isA11yEnabled,
+ },
+ };
+ },
+ };
}
// copying straight from https://github.com/vitejs/vite/blob/main/packages/vite/src/node/constants.ts#L60
diff --git a/code/addons/test/src/vitest-plugin/test-utils.ts b/code/addons/test/src/vitest-plugin/test-utils.ts
index cdd199d3998b..a00ff6d7f6fc 100644
--- a/code/addons/test/src/vitest-plugin/test-utils.ts
+++ b/code/addons/test/src/vitest-plugin/test-utils.ts
@@ -3,29 +3,49 @@
/* eslint-disable no-underscore-dangle */
import { type RunnerTask, type TaskContext, type TaskMeta, type TestContext } from 'vitest';
-import { composeStory } from 'storybook/internal/preview-api';
+import { type Report, composeStory } from 'storybook/internal/preview-api';
import type { ComponentAnnotations, ComposedStoryFn } from 'storybook/internal/types';
+import { server } from '@vitest/browser/context';
+
import { setViewport } from './viewports';
+declare module '@vitest/browser/context' {
+ interface BrowserCommands {
+ getInitialGlobals: () => Promise>;
+ }
+}
+
+const { getInitialGlobals } = server.commands;
+
export const testStory = (
exportName: string,
story: ComposedStoryFn,
meta: ComponentAnnotations,
skipTags: string[]
) => {
- const composedStory = composeStory(story, meta, undefined, undefined, exportName);
return async (context: TestContext & TaskContext & { story: ComposedStoryFn }) => {
+ const composedStory = composeStory(
+ story,
+ meta,
+ { initialGlobals: (await getInitialGlobals?.()) ?? {} },
+ undefined,
+ exportName
+ );
if (composedStory === undefined || skipTags?.some((tag) => composedStory.tags.includes(tag))) {
context.skip();
}
context.story = composedStory;
- const _task = context.task as RunnerTask & { meta: TaskMeta & { storyId: string } };
+ const _task = context.task as RunnerTask & {
+ meta: TaskMeta & { storyId: string; reports: Report[] };
+ };
_task.meta.storyId = composedStory.id;
await setViewport(composedStory.parameters, composedStory.globals);
await composedStory.run();
+
+ _task.meta.reports = composedStory.reporting.reports;
};
};
diff --git a/code/addons/themes/package.json b/code/addons/themes/package.json
index c67ac2dabd3e..57114fdc2b4a 100644
--- a/code/addons/themes/package.json
+++ b/code/addons/themes/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-themes",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Switch between multiple themes for you components in Storybook",
"keywords": [
"css",
diff --git a/code/addons/toolbars/package.json b/code/addons/toolbars/package.json
index 56b19d684c07..67afb0929acc 100644
--- a/code/addons/toolbars/package.json
+++ b/code/addons/toolbars/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-toolbars",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Create your own toolbar items that control story rendering",
"keywords": [
"addon",
diff --git a/code/addons/viewport/package.json b/code/addons/viewport/package.json
index 4c7ad1d5916f..7ce39426636e 100644
--- a/code/addons/viewport/package.json
+++ b/code/addons/viewport/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/addon-viewport",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Build responsive components by adjusting Storybook’s viewport size and orientation",
"keywords": [
"addon",
diff --git a/code/builders/builder-vite/package.json b/code/builders/builder-vite/package.json
index 15111a219775..75ad6ae45767 100644
--- a/code/builders/builder-vite/package.json
+++ b/code/builders/builder-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/builder-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "A plugin to run and build Storybooks with Vite",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/builders/builder-vite/#readme",
"bugs": {
diff --git a/code/builders/builder-webpack5/package.json b/code/builders/builder-webpack5/package.json
index 6c7c000ea5cc..cacc5276d9da 100644
--- a/code/builders/builder-webpack5/package.json
+++ b/code/builders/builder-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/builder-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
diff --git a/code/core/package.json b/code/core/package.json
index cbd3091aeb8d..d3f69bfe4d89 100644
--- a/code/core/package.json
+++ b/code/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/core",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
@@ -274,7 +274,7 @@
"prep": "jiti ./scripts/prep.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"better-opn": "^3.0.2",
"browser-assert": "^1.2.1",
"esbuild": "^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0",
diff --git a/code/core/src/common/versions.ts b/code/core/src/common/versions.ts
index 93a8bf53d3b6..ea14e9cf35be 100644
--- a/code/core/src/common/versions.ts
+++ b/code/core/src/common/versions.ts
@@ -1,88 +1,88 @@
// auto generated file, do not edit
export default {
- '@storybook/addon-a11y': '8.5.0-alpha.18',
- '@storybook/addon-actions': '8.5.0-alpha.18',
- '@storybook/addon-backgrounds': '8.5.0-alpha.18',
- '@storybook/addon-controls': '8.5.0-alpha.18',
- '@storybook/addon-docs': '8.5.0-alpha.18',
- '@storybook/addon-essentials': '8.5.0-alpha.18',
- '@storybook/addon-mdx-gfm': '8.5.0-alpha.18',
- '@storybook/addon-highlight': '8.5.0-alpha.18',
- '@storybook/addon-interactions': '8.5.0-alpha.18',
- '@storybook/addon-jest': '8.5.0-alpha.18',
- '@storybook/addon-links': '8.5.0-alpha.18',
- '@storybook/addon-measure': '8.5.0-alpha.18',
- '@storybook/addon-onboarding': '8.5.0-alpha.18',
- '@storybook/addon-outline': '8.5.0-alpha.18',
- '@storybook/addon-storysource': '8.5.0-alpha.18',
- '@storybook/experimental-addon-test': '8.5.0-alpha.18',
- '@storybook/addon-themes': '8.5.0-alpha.18',
- '@storybook/addon-toolbars': '8.5.0-alpha.18',
- '@storybook/addon-viewport': '8.5.0-alpha.18',
- '@storybook/builder-vite': '8.5.0-alpha.18',
- '@storybook/builder-webpack5': '8.5.0-alpha.18',
- '@storybook/core': '8.5.0-alpha.18',
- '@storybook/builder-manager': '8.5.0-alpha.18',
- '@storybook/channels': '8.5.0-alpha.18',
- '@storybook/client-logger': '8.5.0-alpha.18',
- '@storybook/components': '8.5.0-alpha.18',
- '@storybook/core-common': '8.5.0-alpha.18',
- '@storybook/core-events': '8.5.0-alpha.18',
- '@storybook/core-server': '8.5.0-alpha.18',
- '@storybook/csf-tools': '8.5.0-alpha.18',
- '@storybook/docs-tools': '8.5.0-alpha.18',
- '@storybook/manager': '8.5.0-alpha.18',
- '@storybook/manager-api': '8.5.0-alpha.18',
- '@storybook/node-logger': '8.5.0-alpha.18',
- '@storybook/preview': '8.5.0-alpha.18',
- '@storybook/preview-api': '8.5.0-alpha.18',
- '@storybook/router': '8.5.0-alpha.18',
- '@storybook/telemetry': '8.5.0-alpha.18',
- '@storybook/theming': '8.5.0-alpha.18',
- '@storybook/types': '8.5.0-alpha.18',
- '@storybook/angular': '8.5.0-alpha.18',
- '@storybook/ember': '8.5.0-alpha.18',
- '@storybook/experimental-nextjs-vite': '8.5.0-alpha.18',
- '@storybook/html-vite': '8.5.0-alpha.18',
- '@storybook/html-webpack5': '8.5.0-alpha.18',
- '@storybook/nextjs': '8.5.0-alpha.18',
- '@storybook/preact-vite': '8.5.0-alpha.18',
- '@storybook/preact-webpack5': '8.5.0-alpha.18',
- '@storybook/react-native-web-vite': '8.5.0-alpha.18',
- '@storybook/react-vite': '8.5.0-alpha.18',
- '@storybook/react-webpack5': '8.5.0-alpha.18',
- '@storybook/server-webpack5': '8.5.0-alpha.18',
- '@storybook/svelte-vite': '8.5.0-alpha.18',
- '@storybook/svelte-webpack5': '8.5.0-alpha.18',
- '@storybook/sveltekit': '8.5.0-alpha.18',
- '@storybook/vue3-vite': '8.5.0-alpha.18',
- '@storybook/vue3-webpack5': '8.5.0-alpha.18',
- '@storybook/web-components-vite': '8.5.0-alpha.18',
- '@storybook/web-components-webpack5': '8.5.0-alpha.18',
- '@storybook/blocks': '8.5.0-alpha.18',
- storybook: '8.5.0-alpha.18',
- sb: '8.5.0-alpha.18',
- '@storybook/cli': '8.5.0-alpha.18',
- '@storybook/codemod': '8.5.0-alpha.18',
- '@storybook/core-webpack': '8.5.0-alpha.18',
- 'create-storybook': '8.5.0-alpha.18',
- '@storybook/csf-plugin': '8.5.0-alpha.18',
- '@storybook/instrumenter': '8.5.0-alpha.18',
- '@storybook/react-dom-shim': '8.5.0-alpha.18',
- '@storybook/source-loader': '8.5.0-alpha.18',
- '@storybook/test': '8.5.0-alpha.18',
- '@storybook/preset-create-react-app': '8.5.0-alpha.18',
- '@storybook/preset-html-webpack': '8.5.0-alpha.18',
- '@storybook/preset-preact-webpack': '8.5.0-alpha.18',
- '@storybook/preset-react-webpack': '8.5.0-alpha.18',
- '@storybook/preset-server-webpack': '8.5.0-alpha.18',
- '@storybook/preset-svelte-webpack': '8.5.0-alpha.18',
- '@storybook/preset-vue3-webpack': '8.5.0-alpha.18',
- '@storybook/html': '8.5.0-alpha.18',
- '@storybook/preact': '8.5.0-alpha.18',
- '@storybook/react': '8.5.0-alpha.18',
- '@storybook/server': '8.5.0-alpha.18',
- '@storybook/svelte': '8.5.0-alpha.18',
- '@storybook/vue3': '8.5.0-alpha.18',
- '@storybook/web-components': '8.5.0-alpha.18',
+ '@storybook/addon-a11y': '8.5.0-alpha.19',
+ '@storybook/addon-actions': '8.5.0-alpha.19',
+ '@storybook/addon-backgrounds': '8.5.0-alpha.19',
+ '@storybook/addon-controls': '8.5.0-alpha.19',
+ '@storybook/addon-docs': '8.5.0-alpha.19',
+ '@storybook/addon-essentials': '8.5.0-alpha.19',
+ '@storybook/addon-mdx-gfm': '8.5.0-alpha.19',
+ '@storybook/addon-highlight': '8.5.0-alpha.19',
+ '@storybook/addon-interactions': '8.5.0-alpha.19',
+ '@storybook/addon-jest': '8.5.0-alpha.19',
+ '@storybook/addon-links': '8.5.0-alpha.19',
+ '@storybook/addon-measure': '8.5.0-alpha.19',
+ '@storybook/addon-onboarding': '8.5.0-alpha.19',
+ '@storybook/addon-outline': '8.5.0-alpha.19',
+ '@storybook/addon-storysource': '8.5.0-alpha.19',
+ '@storybook/experimental-addon-test': '8.5.0-alpha.19',
+ '@storybook/addon-themes': '8.5.0-alpha.19',
+ '@storybook/addon-toolbars': '8.5.0-alpha.19',
+ '@storybook/addon-viewport': '8.5.0-alpha.19',
+ '@storybook/builder-vite': '8.5.0-alpha.19',
+ '@storybook/builder-webpack5': '8.5.0-alpha.19',
+ '@storybook/core': '8.5.0-alpha.19',
+ '@storybook/builder-manager': '8.5.0-alpha.19',
+ '@storybook/channels': '8.5.0-alpha.19',
+ '@storybook/client-logger': '8.5.0-alpha.19',
+ '@storybook/components': '8.5.0-alpha.19',
+ '@storybook/core-common': '8.5.0-alpha.19',
+ '@storybook/core-events': '8.5.0-alpha.19',
+ '@storybook/core-server': '8.5.0-alpha.19',
+ '@storybook/csf-tools': '8.5.0-alpha.19',
+ '@storybook/docs-tools': '8.5.0-alpha.19',
+ '@storybook/manager': '8.5.0-alpha.19',
+ '@storybook/manager-api': '8.5.0-alpha.19',
+ '@storybook/node-logger': '8.5.0-alpha.19',
+ '@storybook/preview': '8.5.0-alpha.19',
+ '@storybook/preview-api': '8.5.0-alpha.19',
+ '@storybook/router': '8.5.0-alpha.19',
+ '@storybook/telemetry': '8.5.0-alpha.19',
+ '@storybook/theming': '8.5.0-alpha.19',
+ '@storybook/types': '8.5.0-alpha.19',
+ '@storybook/angular': '8.5.0-alpha.19',
+ '@storybook/ember': '8.5.0-alpha.19',
+ '@storybook/experimental-nextjs-vite': '8.5.0-alpha.19',
+ '@storybook/html-vite': '8.5.0-alpha.19',
+ '@storybook/html-webpack5': '8.5.0-alpha.19',
+ '@storybook/nextjs': '8.5.0-alpha.19',
+ '@storybook/preact-vite': '8.5.0-alpha.19',
+ '@storybook/preact-webpack5': '8.5.0-alpha.19',
+ '@storybook/react-native-web-vite': '8.5.0-alpha.19',
+ '@storybook/react-vite': '8.5.0-alpha.19',
+ '@storybook/react-webpack5': '8.5.0-alpha.19',
+ '@storybook/server-webpack5': '8.5.0-alpha.19',
+ '@storybook/svelte-vite': '8.5.0-alpha.19',
+ '@storybook/svelte-webpack5': '8.5.0-alpha.19',
+ '@storybook/sveltekit': '8.5.0-alpha.19',
+ '@storybook/vue3-vite': '8.5.0-alpha.19',
+ '@storybook/vue3-webpack5': '8.5.0-alpha.19',
+ '@storybook/web-components-vite': '8.5.0-alpha.19',
+ '@storybook/web-components-webpack5': '8.5.0-alpha.19',
+ '@storybook/blocks': '8.5.0-alpha.19',
+ storybook: '8.5.0-alpha.19',
+ sb: '8.5.0-alpha.19',
+ '@storybook/cli': '8.5.0-alpha.19',
+ '@storybook/codemod': '8.5.0-alpha.19',
+ '@storybook/core-webpack': '8.5.0-alpha.19',
+ 'create-storybook': '8.5.0-alpha.19',
+ '@storybook/csf-plugin': '8.5.0-alpha.19',
+ '@storybook/instrumenter': '8.5.0-alpha.19',
+ '@storybook/react-dom-shim': '8.5.0-alpha.19',
+ '@storybook/source-loader': '8.5.0-alpha.19',
+ '@storybook/test': '8.5.0-alpha.19',
+ '@storybook/preset-create-react-app': '8.5.0-alpha.19',
+ '@storybook/preset-html-webpack': '8.5.0-alpha.19',
+ '@storybook/preset-preact-webpack': '8.5.0-alpha.19',
+ '@storybook/preset-react-webpack': '8.5.0-alpha.19',
+ '@storybook/preset-server-webpack': '8.5.0-alpha.19',
+ '@storybook/preset-svelte-webpack': '8.5.0-alpha.19',
+ '@storybook/preset-vue3-webpack': '8.5.0-alpha.19',
+ '@storybook/html': '8.5.0-alpha.19',
+ '@storybook/preact': '8.5.0-alpha.19',
+ '@storybook/react': '8.5.0-alpha.19',
+ '@storybook/server': '8.5.0-alpha.19',
+ '@storybook/svelte': '8.5.0-alpha.19',
+ '@storybook/vue3': '8.5.0-alpha.19',
+ '@storybook/web-components': '8.5.0-alpha.19',
};
diff --git a/code/core/src/components/components/Button/Button.tsx b/code/core/src/components/components/Button/Button.tsx
index 7c0c8db3da44..a1804ebac153 100644
--- a/code/core/src/components/components/Button/Button.tsx
+++ b/code/core/src/components/components/Button/Button.tsx
@@ -11,7 +11,7 @@ import { darken, lighten, rgba, transparentize } from 'polished';
export interface ButtonProps extends ButtonHTMLAttributes {
asChild?: boolean;
size?: 'small' | 'medium';
- padding?: 'small' | 'medium';
+ padding?: 'small' | 'medium' | 'none';
variant?: 'outline' | 'solid' | 'ghost';
onClick?: (event: SyntheticEvent) => void;
disabled?: boolean;
@@ -159,18 +159,18 @@ const StyledButton = styled('button', {
justifyContent: 'center',
overflow: 'hidden',
padding: (() => {
+ if (padding === 'none') {
+ return 0;
+ }
if (padding === 'small' && size === 'small') {
return '0 7px';
}
-
if (padding === 'small' && size === 'medium') {
return '0 9px';
}
-
if (size === 'small') {
return '0 10px';
}
-
if (size === 'medium') {
return '0 12px';
}
diff --git a/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx
new file mode 100644
index 000000000000..b0f03752bede
--- /dev/null
+++ b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.stories.tsx
@@ -0,0 +1,71 @@
+import React from 'react';
+
+import { StopAltIcon } from '@storybook/icons';
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { ProgressSpinner } from './ProgressSpinner';
+
+const meta = {
+ component: ProgressSpinner,
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Forty: Story = {
+ args: {
+ percentage: 40,
+ },
+};
+
+export const Seventy: Story = {
+ args: {
+ percentage: 70,
+ },
+};
+
+export const Zero: Story = {
+ args: {
+ percentage: 0,
+ },
+};
+
+export const Small: Story = {
+ args: {
+ percentage: 40,
+ size: 16,
+ },
+};
+
+export const Thick: Story = {
+ args: {
+ percentage: 40,
+ width: 3,
+ },
+};
+
+export const Paused: Story = {
+ args: {
+ percentage: 40,
+ running: false,
+ },
+};
+
+export const Colored: Story = {
+ args: Forty.args,
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+};
+
+export const WithContent: Story = {
+ ...Colored,
+ args: {
+ ...Colored.args,
+ children: ,
+ },
+};
diff --git a/code/core/src/components/components/ProgressSpinner/ProgressSpinner.tsx b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.tsx
new file mode 100644
index 000000000000..02f81ab6d344
--- /dev/null
+++ b/code/core/src/components/components/ProgressSpinner/ProgressSpinner.tsx
@@ -0,0 +1,93 @@
+import React, { type ComponentProps } from 'react';
+
+import { keyframes, styled } from '@storybook/core/theming';
+
+const XMLNS = 'http://www.w3.org/2000/svg';
+
+const rotate = keyframes({
+ '0%': {
+ transform: 'rotate(0deg)',
+ },
+ '100%': {
+ transform: 'rotate(360deg)',
+ },
+});
+
+const Wrapper = styled.div<{ size: number }>(({ size }) => ({
+ display: 'inline-flex',
+ alignItems: 'center',
+ justifyContent: 'center',
+ position: 'relative',
+ minWidth: size,
+ minHeight: size,
+}));
+
+const Circle = styled.svg<{ size: number; width: number; progress?: boolean; spinner?: boolean }>(
+ ({ size, width }) => ({
+ position: 'absolute',
+ width: `${size}px!important`,
+ height: `${size}px!important`,
+ transform: 'rotate(-90deg)',
+ circle: {
+ r: (size - Math.ceil(width)) / 2,
+ cx: size / 2,
+ cy: size / 2,
+ opacity: 0.15,
+ fill: 'transparent',
+ stroke: 'currentColor',
+ strokeWidth: width,
+ strokeLinecap: 'round',
+ strokeDasharray: Math.PI * (size - Math.ceil(width)),
+ },
+ }),
+ ({ progress }) =>
+ progress && {
+ circle: {
+ opacity: 0.75,
+ },
+ },
+ ({ spinner }) =>
+ spinner && {
+ animation: `${rotate} 1s linear infinite`,
+ circle: {
+ opacity: 0.25,
+ },
+ }
+);
+
+interface ProgressSpinnerProps extends Omit, 'size'> {
+ percentage?: number;
+ running?: boolean;
+ size?: number;
+ width?: number;
+ children?: React.ReactNode;
+}
+
+export const ProgressSpinner = ({
+ percentage = undefined,
+ running = true,
+ size = 24,
+ width = 1.5,
+ children = null,
+ ...props
+}: ProgressSpinnerProps) =>
+ typeof percentage === 'number' ? (
+
+ {children}
+
+
+
+ {running && (
+
+
+
+ )}
+
+
+
+
+ ) : (
+
+ {children}
+
+ );
diff --git a/code/core/src/components/index.ts b/code/core/src/components/index.ts
index eaf6fef4f609..5222b7bd6380 100644
--- a/code/core/src/components/index.ts
+++ b/code/core/src/components/index.ts
@@ -81,6 +81,7 @@ export { StorybookIcon } from './brand/StorybookIcon';
// Loader
export { Loader } from './components/Loader/Loader';
+export { ProgressSpinner } from './components/ProgressSpinner/ProgressSpinner';
// Utils
export { getStoryHref } from './components/utils/getStoryHref';
diff --git a/code/core/src/core-events/data/phases.ts b/code/core/src/core-events/data/phases.ts
new file mode 100644
index 000000000000..d52524d5426b
--- /dev/null
+++ b/code/core/src/core-events/data/phases.ts
@@ -0,0 +1,7 @@
+import type { Report } from '../../preview-api';
+
+export interface StoryFinishedPayload {
+ storyId: string;
+ status: 'error' | 'success';
+ reporters: Report[];
+}
diff --git a/code/core/src/core-events/index.ts b/code/core/src/core-events/index.ts
index 8a1e0a238b8f..4a0371c6c44e 100644
--- a/code/core/src/core-events/index.ts
+++ b/code/core/src/core-events/index.ts
@@ -32,6 +32,7 @@ enum events {
STORY_CHANGED = 'storyChanged',
STORY_UNCHANGED = 'storyUnchanged',
STORY_RENDERED = 'storyRendered',
+ STORY_FINISHED = 'storyFinished',
STORY_MISSING = 'storyMissing',
STORY_ERRORED = 'storyErrored',
STORY_THREW_EXCEPTION = 'storyThrewException',
@@ -142,6 +143,7 @@ export const {
STORY_PREPARED,
STORY_RENDER_PHASE_CHANGED,
STORY_RENDERED,
+ STORY_FINISHED,
STORY_SPECIFIED,
STORY_THREW_EXCEPTION,
STORY_UNCHANGED,
@@ -174,3 +176,4 @@ export * from './data/request-response';
export * from './data/save-story';
export * from './data/whats-new';
export * from './data/testing-module';
+export * from './data/phases';
diff --git a/code/core/src/manager-api/lib/addons.ts b/code/core/src/manager-api/lib/addons.ts
index a7aa438e0863..e893dfa7b984 100644
--- a/code/core/src/manager-api/lib/addons.ts
+++ b/code/core/src/manager-api/lib/addons.ts
@@ -132,6 +132,10 @@ export class AddonStore {
loadAddons = (api: any) => {
Object.values(this.loaders).forEach((value: any) => value(api));
};
+
+ experimental_getRegisteredAddons() {
+ return Object.keys(this.loaders);
+ }
}
// Enforce addons store to be a singleton
diff --git a/code/core/src/manager-api/modules/stories.ts b/code/core/src/manager-api/modules/stories.ts
index e92e7a90ce55..3c5aac769c6a 100644
--- a/code/core/src/manager-api/modules/stories.ts
+++ b/code/core/src/manager-api/modules/stories.ts
@@ -7,6 +7,7 @@ import type {
API_LeafEntry,
API_LoadedRefData,
API_PreparedStoryIndex,
+ API_StatusObject,
API_StatusState,
API_StatusUpdate,
API_StoryEntry,
@@ -268,6 +269,12 @@ export interface SubAPI {
* @returns {Promise} A promise that resolves when the preview has been set as initialized.
*/
setPreviewInitialized: (ref?: ComposedRef) => Promise;
+ /**
+ * Returns the current status of the stories.
+ *
+ * @returns {API_StatusState} The current status of the stories.
+ */
+ getCurrentStoryStatus: () => Record;
/**
* Updates the status of a collection of stories.
*
@@ -630,6 +637,11 @@ export const init: ModuleFn = ({
}
},
+ getCurrentStoryStatus: () => {
+ const { status, storyId } = store.getState();
+ return status[storyId as StoryId];
+ },
+
/* EXPERIMENTAL APIs */
experimental_updateStatus: async (id, input) => {
const { status, internal_index: index } = store.getState();
diff --git a/code/core/src/manager-api/version.ts b/code/core/src/manager-api/version.ts
index b54cfe6a0a07..93047b78f0e7 100644
--- a/code/core/src/manager-api/version.ts
+++ b/code/core/src/manager-api/version.ts
@@ -1 +1 @@
-export const version = '8.5.0-alpha.18';
+export const version = '8.5.0-alpha.19';
diff --git a/code/core/src/manager/components/sidebar/LegacyRender.tsx b/code/core/src/manager/components/sidebar/LegacyRender.tsx
index 065ad061c995..82bc83bd1b34 100644
--- a/code/core/src/manager/components/sidebar/LegacyRender.tsx
+++ b/code/core/src/manager/components/sidebar/LegacyRender.tsx
@@ -1,8 +1,8 @@
import React from 'react';
-import { Button } from '@storybook/core/components';
+import { Button, ProgressSpinner } from '@storybook/core/components';
import { styled } from '@storybook/core/theming';
-import { EyeIcon, PlayHollowIcon, StopAltHollowIcon } from '@storybook/icons';
+import { EyeIcon, PlayHollowIcon, StopAltIcon } from '@storybook/icons';
import type { TestProviders } from '@storybook/core/core-events';
import { useStorybookApi } from '@storybook/core/manager-api';
@@ -35,6 +35,14 @@ const DescriptionWrapper = styled.div(({ theme }) => ({
color: theme.barTextColor,
}));
+const Progress = styled(ProgressSpinner)({
+ margin: 2,
+});
+
+const StopIcon = styled(StopAltIcon)({
+ width: 10,
+});
+
export const LegacyRender = ({ ...state }: TestProviders[keyof TestProviders]) => {
const Description = state.description!;
const Title = state.title!;
@@ -70,11 +78,18 @@ export const LegacyRender = ({ ...state }: TestProviders[keyof TestProviders]) =
api.cancelTestProvider(state.id)}
disabled={state.cancelling}
>
-
+
+
+
) : (
{
+ const onProgressReport = async ({
+ providerId,
+ ...result
+ }: TestingModuleProgressReportPayload) => {
const statusResult = 'status' in result ? result.status : undefined;
api.updateTestProviderState(
providerId,
diff --git a/code/core/src/manager/globals/exports.ts b/code/core/src/manager/globals/exports.ts
index 168a936a4880..e354ce120ffb 100644
--- a/code/core/src/manager/globals/exports.ts
+++ b/code/core/src/manager/globals/exports.ts
@@ -334,6 +334,7 @@ export default {
'P',
'Placeholder',
'Pre',
+ 'ProgressSpinner',
'ResetWrapper',
'ScrollArea',
'Separator',
@@ -404,6 +405,7 @@ export default {
'P',
'Placeholder',
'Pre',
+ 'ProgressSpinner',
'ResetWrapper',
'ScrollArea',
'Separator',
@@ -474,6 +476,7 @@ export default {
'P',
'Placeholder',
'Pre',
+ 'ProgressSpinner',
'ResetWrapper',
'ScrollArea',
'Separator',
@@ -798,6 +801,7 @@ export default {
'STORY_ARGS_UPDATED',
'STORY_CHANGED',
'STORY_ERRORED',
+ 'STORY_FINISHED',
'STORY_INDEX_INVALIDATED',
'STORY_MISSING',
'STORY_PREPARED',
@@ -863,6 +867,7 @@ export default {
'STORY_ARGS_UPDATED',
'STORY_CHANGED',
'STORY_ERRORED',
+ 'STORY_FINISHED',
'STORY_INDEX_INVALIDATED',
'STORY_MISSING',
'STORY_PREPARED',
@@ -928,6 +933,7 @@ export default {
'STORY_ARGS_UPDATED',
'STORY_CHANGED',
'STORY_ERRORED',
+ 'STORY_FINISHED',
'STORY_INDEX_INVALIDATED',
'STORY_MISSING',
'STORY_PREPARED',
diff --git a/code/core/src/preview-api/index.ts b/code/core/src/preview-api/index.ts
index 0a61c7333ab3..d067acad89cc 100644
--- a/code/core/src/preview-api/index.ts
+++ b/code/core/src/preview-api/index.ts
@@ -60,6 +60,6 @@ export { createPlaywrightTest } from './modules/store/csf/portable-stories';
export type { PropDescriptor } from './store';
/** STORIES API */
-export { StoryStore } from './store';
+export { StoryStore, type Report, ReporterAPI } from './store';
export { Preview, PreviewWeb, PreviewWithSelection, UrlStore, WebView } from './preview-web';
export type { SelectionStore, View } from './preview-web';
diff --git a/code/core/src/preview-api/modules/preview-web/Preview.tsx b/code/core/src/preview-api/modules/preview-web/Preview.tsx
index 049fccf90901..e929d6749337 100644
--- a/code/core/src/preview-api/modules/preview-web/Preview.tsx
+++ b/code/core/src/preview-api/modules/preview-web/Preview.tsx
@@ -386,11 +386,6 @@ export class Preview {
throw new CalledPreviewMethodBeforeInitializationError({ methodName: 'onResetArgs' });
}
- // NOTE: we have to be careful here and avoid await-ing when updating a rendered's args.
- // That's because below in `renderStoryToElement` we have also bound to this event and will
- // render the story in the same tick.
- // However, we can do that safely as the current story is available in `this.storyRenders`
-
// NOTE: we have to be careful here and avoid await-ing when updating a rendered's args.
// That's because below in `renderStoryToElement` we have also bound to this event and will
// render the story in the same tick.
diff --git a/code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts b/code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts
index 6505922c842e..2ed2352ae4e7 100644
--- a/code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts
+++ b/code/core/src/preview-api/modules/preview-web/PreviewWeb.mockdata.ts
@@ -12,8 +12,8 @@ import type {
import {
DOCS_RENDERED,
STORY_ERRORED,
+ STORY_FINISHED,
STORY_MISSING,
- STORY_RENDERED,
STORY_RENDER_PHASE_CHANGED,
STORY_THREW_EXCEPTION,
} from '@storybook/core/core-events';
@@ -204,11 +204,11 @@ export const waitForEvents = (
// the async parts, so we need to listen for the "done" events
export const waitForRender = () =>
waitForEvents([
- STORY_RENDERED,
DOCS_RENDERED,
- STORY_THREW_EXCEPTION,
+ STORY_FINISHED,
STORY_ERRORED,
STORY_MISSING,
+ STORY_THREW_EXCEPTION,
]);
export const waitForRenderPhase = (phase: RenderPhase) => {
diff --git a/code/core/src/preview-api/modules/preview-web/render/StoryRender.test.ts b/code/core/src/preview-api/modules/preview-web/render/StoryRender.test.ts
index 2bd3a9ca3830..41fdea4b6771 100644
--- a/code/core/src/preview-api/modules/preview-web/render/StoryRender.test.ts
+++ b/code/core/src/preview-api/modules/preview-web/render/StoryRender.test.ts
@@ -1,12 +1,14 @@
// @vitest-environment happy-dom
import { beforeEach, describe, expect, it, vi } from 'vitest';
+import { STORY_FINISHED } from 'storybook/internal/core-events';
+
import { Channel } from '@storybook/core/channels';
import type { PreparedStory, Renderer, StoryContext, StoryIndexEntry } from '@storybook/core/types';
-import type { StoryStore } from '../../store';
+import { ReporterAPI, type StoryStore } from '../../store';
import { PREPARE_ABORTED } from './Render';
-import { StoryRender } from './StoryRender';
+import { StoryRender, serializeError } from './StoryRender';
const entry = {
type: 'story',
@@ -40,6 +42,7 @@ const buildStory = (overrides: Partial = {}): PreparedStory =>
tags: [],
applyLoaders: vi.fn(),
applyBeforeEach: vi.fn(),
+ applyAfterEach: vi.fn(),
unboundStoryFn: vi.fn(),
playFunction: vi.fn(),
mount: (context: StoryContext) => () => mountSpy(context),
@@ -48,7 +51,9 @@ const buildStory = (overrides: Partial = {}): PreparedStory =>
const buildStore = (overrides: Partial> = {}): StoryStore =>
({
- getStoryContext: () => ({}),
+ getStoryContext: () => ({
+ reporting: new ReporterAPI(),
+ }),
addCleanupCallbacks: vi.fn(),
cleanupStory: vi.fn(),
...overrides,
@@ -255,6 +260,91 @@ describe('StoryRender', () => {
expect(actualMount).toHaveBeenCalled();
});
+ it('should handle the "finished" phase correctly when the story finishes successfully', async () => {
+ // Arrange - setup StoryRender and async gate blocking finished phase
+ const [finishGate, resolveFinishGate] = createGate();
+ const story = buildStory({
+ playFunction: vi.fn(async () => {
+ await finishGate;
+ }),
+ });
+ const store = buildStore();
+
+ const channel = new Channel({});
+ const emitSpy = vi.spyOn(channel, 'emit');
+
+ const render = new StoryRender(
+ channel,
+ store,
+ vi.fn() as any,
+ {} as any,
+ entry.id,
+ 'story',
+ { autoplay: true },
+ story
+ );
+
+ // Act - render, resolve finish gate, teardown
+ render.renderToElement({} as any);
+ await tick(); // go from 'loading' to 'rendering' phase
+ resolveFinishGate();
+ await tick(); // go from 'rendering' to 'finished' phase
+ render.teardown();
+
+ // Assert - ensure finished phase is handled correctly
+ expect(render.phase).toBe('finished');
+ expect(emitSpy).toHaveBeenCalledWith(STORY_FINISHED, {
+ reporters: [],
+ status: 'success',
+ storyId: 'id',
+ });
+ });
+
+ it('should handle the "finished" phase correctly when the story throws an error', async () => {
+ // Arrange - setup StoryRender and async gate blocking finished phase
+ const [finishGate, rejectFinishGate] = createGate();
+ const error = new Error('Test error');
+ const story = buildStory({
+ parameters: {},
+ playFunction: vi.fn(async () => {
+ await finishGate;
+ throw error;
+ }),
+ });
+ const store = buildStore();
+
+ const channel = new Channel({});
+ const emitSpy = vi.spyOn(channel, 'emit');
+
+ const render = new StoryRender(
+ channel,
+ store,
+ vi.fn() as any,
+ {
+ showException: vi.fn(),
+ } as any,
+ entry.id,
+ 'story',
+ { autoplay: true },
+ story
+ );
+
+ // Act - render, reject finish gate, teardown
+ render.renderToElement({} as any);
+ await tick(); // go from 'loading' to 'rendering' phase
+ rejectFinishGate();
+ await tick(); // go from 'rendering' to 'finished' phase
+ render.teardown();
+
+ // Assert - ensure finished phase is handled correctly
+ expect(render.phase).toBe('finished');
+ expect(emitSpy).toHaveBeenCalledWith(STORY_FINISHED, {
+ reporters: [],
+ status: 'error',
+ storyId: 'id',
+ });
+ });
+
describe('teardown', () => {
it('throws PREPARE_ABORTED if torndown during prepare', async () => {
const [importGate, openImportGate] = createGate();
diff --git a/code/core/src/preview-api/modules/preview-web/render/StoryRender.ts b/code/core/src/preview-api/modules/preview-web/render/StoryRender.ts
index 3441a5c64e97..0eacdf7e7551 100644
--- a/code/core/src/preview-api/modules/preview-web/render/StoryRender.ts
+++ b/code/core/src/preview-api/modules/preview-web/render/StoryRender.ts
@@ -14,8 +14,10 @@ import type {
import {
PLAY_FUNCTION_THREW_EXCEPTION,
+ STORY_FINISHED,
STORY_RENDERED,
STORY_RENDER_PHASE_CHANGED,
+ type StoryFinishedPayload,
UNHANDLED_ERRORS_WHILE_PLAYING,
} from '@storybook/core/core-events';
import { MountMustBeDestructuredError, NoStoryMountedError } from '@storybook/core/preview-errors';
@@ -33,11 +35,13 @@ export type RenderPhase =
| 'rendering'
| 'playing'
| 'played'
+ | 'afterEach'
| 'completed'
+ | 'finished'
| 'aborted'
| 'errored';
-function serializeError(error: any) {
+export function serializeError(error: any) {
try {
const { name = 'Error', message = String(error), stack } = error;
return { name, message, stack };
@@ -132,7 +136,9 @@ export class StoryRender implements Render implements Render implements Render = new Set();
+ const unhandledErrors: Set = new Set();
const onError = (event: ErrorEvent | PromiseRejectionEvent) =>
unhandledErrors.add('error' in event ? event.error : event.reason);
@@ -349,9 +356,39 @@ export class StoryRender implements Render
this.channel.emit(STORY_RENDERED, id)
);
+
+ if (this.phase !== 'errored') {
+ await this.runPhase(abortSignal, 'afterEach', async () => {
+ await applyAfterEach(context);
+ });
+ }
+
+ const hasUnhandledErrors = !ignoreUnhandledErrors && unhandledErrors.size > 0;
+
+ const hasSomeReportsFailed = context.reporting.reports.some(
+ (report) => report.status === 'failed'
+ );
+
+ const hasStoryErrored = hasUnhandledErrors || hasSomeReportsFailed;
+
+ await this.runPhase(abortSignal, 'finished', async () =>
+ this.channel.emit(STORY_FINISHED, {
+ storyId: id,
+ status: hasStoryErrored ? 'error' : 'success',
+ reporters: context.reporting.reports,
+ } as StoryFinishedPayload)
+ );
} catch (err) {
this.phase = 'errored';
this.callbacks.showException(err as Error);
+
+ await this.runPhase(abortSignal, 'finished', async () =>
+ this.channel.emit(STORY_FINISHED, {
+ storyId: id,
+ status: 'error',
+ reporters: [],
+ } as StoryFinishedPayload)
+ );
}
// If a rerender was enqueued during the render, clear the queue and render again
diff --git a/code/core/src/preview-api/modules/store/StoryStore.test.ts b/code/core/src/preview-api/modules/store/StoryStore.test.ts
index 4cc27210c5af..b28638960727 100644
--- a/code/core/src/preview-api/modules/store/StoryStore.test.ts
+++ b/code/core/src/preview-api/modules/store/StoryStore.test.ts
@@ -645,6 +645,7 @@ describe('StoryStore', () => {
expect(store.raw()).toMatchInlineSnapshot(`
[
{
+ "applyAfterEach": [Function],
"applyBeforeEach": [Function],
"applyLoaders": [Function],
"argTypes": {
@@ -698,6 +699,7 @@ describe('StoryStore', () => {
"usesMount": false,
},
{
+ "applyAfterEach": [Function],
"applyBeforeEach": [Function],
"applyLoaders": [Function],
"argTypes": {
@@ -751,6 +753,7 @@ describe('StoryStore', () => {
"usesMount": false,
},
{
+ "applyAfterEach": [Function],
"applyBeforeEach": [Function],
"applyLoaders": [Function],
"argTypes": {
diff --git a/code/core/src/preview-api/modules/store/StoryStore.ts b/code/core/src/preview-api/modules/store/StoryStore.ts
index cd7dc40a6ed1..01404a5f1bf5 100644
--- a/code/core/src/preview-api/modules/store/StoryStore.ts
+++ b/code/core/src/preview-api/modules/store/StoryStore.ts
@@ -45,6 +45,7 @@ import {
prepareStory,
processCSFFile,
} from './csf';
+import { ReporterAPI } from './reporter-api';
export function picky, K extends keyof T>(
obj: T,
@@ -253,12 +254,14 @@ export class StoryStore {
getStoryContext(story: PreparedStory, { forceInitialArgs = false } = {}) {
const userGlobals = this.userGlobals.get();
const { initialGlobals } = this.userGlobals;
+ const reporting = new ReporterAPI();
return prepareContext({
...story,
args: forceInitialArgs ? story.initialArgs : this.args.get(story.id),
initialGlobals,
globalTypes: this.projectAnnotations.globalTypes,
userGlobals,
+ reporting,
globals: {
...userGlobals,
...story.storyGlobals,
diff --git a/code/core/src/preview-api/modules/store/csf/composeConfigs.test.ts b/code/core/src/preview-api/modules/store/csf/composeConfigs.test.ts
index 035aa60e7e14..d1539c4791e1 100644
--- a/code/core/src/preview-api/modules/store/csf/composeConfigs.test.ts
+++ b/code/core/src/preview-api/modules/store/csf/composeConfigs.test.ts
@@ -25,6 +25,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -53,6 +54,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -85,6 +87,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -123,6 +126,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -164,6 +168,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -196,6 +201,7 @@ describe('composeConfigs', () => {
loaders: ['1', '2', '3', '4'],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -228,6 +234,7 @@ describe('composeConfigs', () => {
loaders: ['1', '2', '3'],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -256,6 +263,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -285,6 +293,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
runStep: expect.any(Function),
tags: [],
});
@@ -317,6 +326,7 @@ describe('composeConfigs', () => {
loaders: [],
beforeAll: expect.any(Function),
beforeEach: [],
+ experimental_afterEach: [],
render: 'render-2',
renderToCanvas: 'renderToCanvas-2',
applyDecorators: 'applyDecorators-2',
diff --git a/code/core/src/preview-api/modules/store/csf/composeConfigs.ts b/code/core/src/preview-api/modules/store/csf/composeConfigs.ts
index 545ab719e5a3..e5ba4f731b83 100644
--- a/code/core/src/preview-api/modules/store/csf/composeConfigs.ts
+++ b/code/core/src/preview-api/modules/store/csf/composeConfigs.ts
@@ -64,6 +64,7 @@ export function composeConfigs(
loaders: getArrayField(moduleExportList, 'loaders'),
beforeAll: composeBeforeAllHooks(beforeAllHooks),
beforeEach: getArrayField(moduleExportList, 'beforeEach'),
+ experimental_afterEach: getArrayField(moduleExportList, 'experimental_afterEach'),
render: getSingletonField(moduleExportList, 'render'),
renderToCanvas: getSingletonField(moduleExportList, 'renderToCanvas'),
renderToDOM: getSingletonField(moduleExportList, 'renderToDOM'), // deprecated
diff --git a/code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts b/code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts
index 26711a130106..7c5ec15724fb 100644
--- a/code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts
+++ b/code/core/src/preview-api/modules/store/csf/normalizeProjectAnnotations.ts
@@ -26,6 +26,7 @@ export function normalizeProjectAnnotations({
decorators,
loaders,
beforeEach,
+ experimental_afterEach,
globals,
initialGlobals,
...annotations
@@ -44,6 +45,7 @@ export function normalizeProjectAnnotations({
decorators: normalizeArrays(decorators),
loaders: normalizeArrays(loaders),
beforeEach: normalizeArrays(beforeEach),
+ experimental_afterEach: normalizeArrays(experimental_afterEach),
argTypesEnhancers: [
...(argTypesEnhancers || []),
inferArgTypes,
diff --git a/code/core/src/preview-api/modules/store/csf/normalizeStory.test.ts b/code/core/src/preview-api/modules/store/csf/normalizeStory.test.ts
index ddacda230514..e7cad9cb0558 100644
--- a/code/core/src/preview-api/modules/store/csf/normalizeStory.test.ts
+++ b/code/core/src/preview-api/modules/store/csf/normalizeStory.test.ts
@@ -56,6 +56,7 @@ describe('normalizeStory', () => {
"args": {},
"beforeEach": [],
"decorators": [],
+ "experimental_afterEach": [],
"globals": {},
"id": "title--story-export",
"loaders": [],
@@ -127,6 +128,7 @@ describe('normalizeStory', () => {
"args": {},
"beforeEach": [],
"decorators": [],
+ "experimental_afterEach": [],
"globals": {},
"id": "title--story-export",
"loaders": [],
@@ -167,6 +169,7 @@ describe('normalizeStory', () => {
"decorators": [
[Function],
],
+ "experimental_afterEach": [],
"globals": {},
"id": "title--story-export",
"loaders": [
@@ -225,6 +228,7 @@ describe('normalizeStory', () => {
[Function],
[Function],
],
+ "experimental_afterEach": [],
"globals": {},
"id": "title--story-export",
"loaders": [
diff --git a/code/core/src/preview-api/modules/store/csf/normalizeStory.ts b/code/core/src/preview-api/modules/store/csf/normalizeStory.ts
index 2dd2ae957390..7fb9f59d256b 100644
--- a/code/core/src/preview-api/modules/store/csf/normalizeStory.ts
+++ b/code/core/src/preview-api/modules/store/csf/normalizeStory.ts
@@ -60,6 +60,11 @@ export function normalizeStory(
...normalizeArrays(storyObject.beforeEach),
...normalizeArrays(story?.beforeEach),
];
+ // eslint-disable-next-line @typescript-eslint/naming-convention
+ const experimental_afterEach = [
+ ...normalizeArrays(storyObject.experimental_afterEach),
+ ...normalizeArrays(story?.experimental_afterEach),
+ ];
const { render, play, tags = [], globals = {} } = storyObject;
// eslint-disable-next-line no-underscore-dangle
@@ -75,6 +80,7 @@ export function normalizeStory(
argTypes: normalizeInputTypes(argTypes),
loaders,
beforeEach,
+ experimental_afterEach,
globals,
...(render && { render }),
...(userStoryFn && { userStoryFn }),
diff --git a/code/core/src/preview-api/modules/store/csf/portable-stories.ts b/code/core/src/preview-api/modules/store/csf/portable-stories.ts
index 22b449bd98f0..774137dcf85a 100644
--- a/code/core/src/preview-api/modules/store/csf/portable-stories.ts
+++ b/code/core/src/preview-api/modules/store/csf/portable-stories.ts
@@ -26,6 +26,7 @@ import { MountMustBeDestructuredError } from '@storybook/core/preview-errors';
import { dedent } from 'ts-dedent';
import { HooksContext } from '../../../addons';
+import { ReporterAPI } from '../reporter-api';
import { composeConfigs } from './composeConfigs';
import { getValuesFromArgTypes } from './getValuesFromArgTypes';
import { normalizeComponentAnnotations } from './normalizeComponentAnnotations';
@@ -143,12 +144,15 @@ export function composeStory {
const context: StoryContext = prepareContext({
hooks: new HooksContext(),
globals,
args: { ...story.initialArgs },
viewMode: 'story',
+ reporting,
loaded: {},
abortSignal: new AbortController().signal,
step: (label, play) => story.runStep(label, play, context),
@@ -255,6 +259,7 @@ export function composeStory,
play: playFunction!,
run,
+ reporting,
tags: story.tags,
}
);
@@ -405,4 +410,6 @@ async function runStory(
}
await playFunction(context);
}
+
+ await story.applyAfterEach(context);
}
diff --git a/code/core/src/preview-api/modules/store/csf/prepareStory.test.ts b/code/core/src/preview-api/modules/store/csf/prepareStory.test.ts
index e91a6fcfea05..4f3c88bbd55e 100644
--- a/code/core/src/preview-api/modules/store/csf/prepareStory.test.ts
+++ b/code/core/src/preview-api/modules/store/csf/prepareStory.test.ts
@@ -54,6 +54,10 @@ const addExtraContext = (
...context,
hooks: new HooksContext(),
viewMode: 'story' as const,
+ reporting: {
+ reports: [],
+ addReport: vi.fn(),
+ },
loaded: {},
mount: vi.fn(),
abortSignal: new AbortController().signal,
@@ -792,6 +796,7 @@ describe('prepareMeta', () => {
story,
applyLoaders,
applyBeforeEach,
+ applyAfterEach,
originalStoryFn,
unboundStoryFn,
undecoratedStoryFn,
diff --git a/code/core/src/preview-api/modules/store/csf/prepareStory.ts b/code/core/src/preview-api/modules/store/csf/prepareStory.ts
index d6db661270d3..d2d7bba0c6df 100644
--- a/code/core/src/preview-api/modules/store/csf/prepareStory.ts
+++ b/code/core/src/preview-api/modules/store/csf/prepareStory.ts
@@ -92,6 +92,20 @@ export function prepareStory(
return cleanupCallbacks;
};
+ const applyAfterEach = async (context: StoryContext): Promise => {
+ const reversedFinalizers = [
+ ...normalizeArrays(projectAnnotations.experimental_afterEach),
+ ...normalizeArrays(componentAnnotations.experimental_afterEach),
+ ...normalizeArrays(storyAnnotations.experimental_afterEach),
+ ].reverse();
+ for (const finalizer of reversedFinalizers) {
+ if (context.abortSignal.aborted) {
+ return;
+ }
+ await finalizer(context);
+ }
+ };
+
const undecoratedStoryFn = (context: StoryContext) =>
(context.originalStoryFn as ArgsStoryFn)(context.args, context);
@@ -150,6 +164,7 @@ export function prepareStory(
unboundStoryFn,
applyLoaders,
applyBeforeEach,
+ applyAfterEach,
playFunction,
runStep,
mount,
diff --git a/code/core/src/preview-api/modules/store/index.ts b/code/core/src/preview-api/modules/store/index.ts
index f6694ad9017b..ea16e35bc908 100644
--- a/code/core/src/preview-api/modules/store/index.ts
+++ b/code/core/src/preview-api/modules/store/index.ts
@@ -10,3 +10,4 @@ export * from './decorators';
export * from './args';
export * from './autoTitle';
export * from './sortStories';
+export * from './reporter-api';
diff --git a/code/core/src/preview-api/modules/store/reporter-api.ts b/code/core/src/preview-api/modules/store/reporter-api.ts
new file mode 100644
index 000000000000..593124b6b8eb
--- /dev/null
+++ b/code/core/src/preview-api/modules/store/reporter-api.ts
@@ -0,0 +1,14 @@
+export interface Report {
+ type: string;
+ version?: number;
+ result: T;
+ status: 'failed' | 'passed' | 'warning';
+}
+
+export class ReporterAPI {
+ reports: Report[] = [];
+
+ async addReport(report: Report) {
+ this.reports.push(report);
+ }
+}
diff --git a/code/core/src/types/modules/composedStory.ts b/code/core/src/types/modules/composedStory.ts
index 7f8d52add055..c5a58b280cd3 100644
--- a/code/core/src/types/modules/composedStory.ts
+++ b/code/core/src/types/modules/composedStory.ts
@@ -9,6 +9,7 @@ import type {
Tag,
} from '@storybook/csf';
+import type { ReporterAPI } from '../../preview-api';
import type {
AnnotatedStoryFn,
Args,
@@ -49,6 +50,7 @@ export type ComposedStoryFn<
storyName: string;
parameters: Parameters;
argTypes: StrictArgTypes;
+ reporting: ReporterAPI;
tags: Tag[];
globals: Globals;
};
diff --git a/code/core/src/types/modules/csf.ts b/code/core/src/types/modules/csf.ts
index ae949e766fa8..fe0914bd398a 100644
--- a/code/core/src/types/modules/csf.ts
+++ b/code/core/src/types/modules/csf.ts
@@ -3,6 +3,7 @@ import type { ViewMode as ViewModeBase } from '@storybook/csf';
import type { Addon_OptionsParameter } from './addons';
export type {
+ AfterEach,
AnnotatedStoryFn,
Args,
ArgsEnhancer,
@@ -11,6 +12,7 @@ export type {
ArgTypes,
ArgTypesEnhancer,
BaseAnnotations,
+ BeforeEach,
Canvas,
ComponentAnnotations,
ComponentId,
diff --git a/code/core/src/types/modules/story.ts b/code/core/src/types/modules/story.ts
index f8deb8c522f0..c4b07fa1cd30 100644
--- a/code/core/src/types/modules/story.ts
+++ b/code/core/src/types/modules/story.ts
@@ -109,6 +109,7 @@ export type PreparedStory =
unboundStoryFn: LegacyStoryFn;
applyLoaders: (context: StoryContext) => Promise['loaded']>;
applyBeforeEach: (context: StoryContext) => Promise;
+ applyAfterEach: (context: StoryContext) => Promise;
playFunction?: (context: StoryContext) => Promise | void;
runStep: StepRunner;
mount: (context: StoryContext) => () => Promise;
diff --git a/code/core/template/stories/tags-add.stories.ts b/code/core/template/stories/tags-add.stories.ts
index f4b15f2557bf..edb70171eba1 100644
--- a/code/core/template/stories/tags-add.stories.ts
+++ b/code/core/template/stories/tags-add.stories.ts
@@ -17,11 +17,17 @@ export default {
export const Inheritance = {
tags: ['story-one', '!vitest'],
- play: async ({ canvasElement }: PlayFunctionContext) => {
+ play: async ({ canvasElement, tags }: PlayFunctionContext) => {
const canvas = within(canvasElement);
- await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
- tags: ['story-one'],
- });
+ if (tags.includes('a11ytest')) {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['a11ytest', 'story-one'],
+ });
+ } else {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['story-one'],
+ });
+ }
},
parameters: { chromatic: { disable: false } },
};
diff --git a/code/core/template/stories/tags-config.stories.ts b/code/core/template/stories/tags-config.stories.ts
index 0f3269d4d4a1..a57a70390ce1 100644
--- a/code/core/template/stories/tags-config.stories.ts
+++ b/code/core/template/stories/tags-config.stories.ts
@@ -17,11 +17,25 @@ export default {
export const Inheritance = {
tags: ['story-one', '!vitest'],
- play: async ({ canvasElement }: PlayFunctionContext) => {
+ play: async ({ canvasElement, tags }: PlayFunctionContext) => {
const canvas = within(canvasElement);
- await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
- tags: ['dev', 'test', 'component-one', 'component-two', 'autodocs', 'story-one'],
- });
+ if (tags.includes('a11ytest')) {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: [
+ 'dev',
+ 'test',
+ 'a11ytest',
+ 'component-one',
+ 'component-two',
+ 'autodocs',
+ 'story-one',
+ ],
+ });
+ } else {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['dev', 'test', 'component-one', 'component-two', 'autodocs', 'story-one'],
+ });
+ }
},
parameters: { chromatic: { disable: false } },
};
diff --git a/code/core/template/stories/tags-remove.stories.ts b/code/core/template/stories/tags-remove.stories.ts
index cc05e9b23208..468f99614aa0 100644
--- a/code/core/template/stories/tags-remove.stories.ts
+++ b/code/core/template/stories/tags-remove.stories.ts
@@ -17,11 +17,17 @@ export default {
export const Inheritance = {
tags: ['story-one', '!vitest'],
- play: async ({ canvasElement }: PlayFunctionContext) => {
+ play: async ({ canvasElement, tags }: PlayFunctionContext) => {
const canvas = within(canvasElement);
- await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
- tags: ['dev', 'test', 'component-one', 'autodocs', 'story-one'],
- });
+ if (tags.includes('a11ytest')) {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['dev', 'test', 'a11ytest', 'component-one', 'autodocs', 'story-one'],
+ });
+ } else {
+ await expect(JSON.parse(canvas.getByTestId('pre').innerText)).toEqual({
+ tags: ['dev', 'test', 'component-one', 'autodocs', 'story-one'],
+ });
+ }
},
parameters: { chromatic: { disable: false } },
};
diff --git a/code/deprecated/builder-manager/package.json b/code/deprecated/builder-manager/package.json
index 2509c211d6bf..a331b3fa6bb3 100644
--- a/code/deprecated/builder-manager/package.json
+++ b/code/deprecated/builder-manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/builder-manager",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook manager builder",
"keywords": [
"storybook"
diff --git a/code/deprecated/channels/package.json b/code/deprecated/channels/package.json
index abec6882d2dc..a4f681e62e04 100644
--- a/code/deprecated/channels/package.json
+++ b/code/deprecated/channels/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/channels",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/deprecated/client-logger/package.json b/code/deprecated/client-logger/package.json
index caf80b13a3d0..86f72277da7d 100644
--- a/code/deprecated/client-logger/package.json
+++ b/code/deprecated/client-logger/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/client-logger",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/deprecated/components/package.json b/code/deprecated/components/package.json
index 30e9a7ab202f..4f2752072b53 100644
--- a/code/deprecated/components/package.json
+++ b/code/deprecated/components/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/components",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook Components",
"keywords": [
"storybook"
diff --git a/code/deprecated/core-common/package.json b/code/deprecated/core-common/package.json
index ad5da180fdf5..6dfb83618c4f 100644
--- a/code/deprecated/core-common/package.json
+++ b/code/deprecated/core-common/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/core-common",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
diff --git a/code/deprecated/core-events/package.json b/code/deprecated/core-events/package.json
index 9823b20089fb..20dff0d9ce2d 100644
--- a/code/deprecated/core-events/package.json
+++ b/code/deprecated/core-events/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/core-events",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Event names used in storybook core",
"keywords": [
"storybook"
diff --git a/code/deprecated/core-server/package.json b/code/deprecated/core-server/package.json
index 5c42483a47a8..6b77123b1c36 100644
--- a/code/deprecated/core-server/package.json
+++ b/code/deprecated/core-server/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/core-server",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
diff --git a/code/deprecated/csf-tools/package.json b/code/deprecated/csf-tools/package.json
index a13e29cd0c01..74be5d5e9eb1 100644
--- a/code/deprecated/csf-tools/package.json
+++ b/code/deprecated/csf-tools/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/csf-tools",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Parse and manipulate CSF and Storybook config files",
"keywords": [
"storybook"
diff --git a/code/deprecated/docs-tools/package.json b/code/deprecated/docs-tools/package.json
index 9fc426e57327..fb5a9c6bc527 100644
--- a/code/deprecated/docs-tools/package.json
+++ b/code/deprecated/docs-tools/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/docs-tools",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Shared utility functions for frameworks to implement docs",
"keywords": [
"storybook"
diff --git a/code/deprecated/manager-api/package.json b/code/deprecated/manager-api/package.json
index 955551c55c0b..4afb8ef29a3e 100644
--- a/code/deprecated/manager-api/package.json
+++ b/code/deprecated/manager-api/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/manager-api",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook Manager API & Context",
"keywords": [
"storybook"
diff --git a/code/deprecated/manager/package.json b/code/deprecated/manager/package.json
index b1f00d95a22d..a3890fa1e4f7 100644
--- a/code/deprecated/manager/package.json
+++ b/code/deprecated/manager/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/manager",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook UI",
"keywords": [
"storybook"
diff --git a/code/deprecated/node-logger/package.json b/code/deprecated/node-logger/package.json
index d0c86432b964..7afefb239034 100644
--- a/code/deprecated/node-logger/package.json
+++ b/code/deprecated/node-logger/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/node-logger",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/deprecated/preview-api/package.json b/code/deprecated/preview-api/package.json
index e3b092c1a9b1..dbd86a65cc29 100644
--- a/code/deprecated/preview-api/package.json
+++ b/code/deprecated/preview-api/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preview-api",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/deprecated/preview/package.json b/code/deprecated/preview/package.json
index 479c337042d7..c7e152ac19b8 100644
--- a/code/deprecated/preview/package.json
+++ b/code/deprecated/preview/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preview",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/deprecated/router/package.json b/code/deprecated/router/package.json
index af05453070d3..bb6305160f05 100644
--- a/code/deprecated/router/package.json
+++ b/code/deprecated/router/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/router",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook Router",
"keywords": [
"storybook"
diff --git a/code/deprecated/telemetry/package.json b/code/deprecated/telemetry/package.json
index 22e48c1a6ccd..6a54c1ff5729 100644
--- a/code/deprecated/telemetry/package.json
+++ b/code/deprecated/telemetry/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/telemetry",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Telemetry logging for crash reports and usage statistics",
"keywords": [
"storybook"
diff --git a/code/deprecated/theming/package.json b/code/deprecated/theming/package.json
index c82476b5afc5..fce7c7f67bdb 100644
--- a/code/deprecated/theming/package.json
+++ b/code/deprecated/theming/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/theming",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook Components",
"keywords": [
"storybook"
diff --git a/code/deprecated/types/package.json b/code/deprecated/types/package.json
index 13cdd9a8664a..1e6eb337de10 100644
--- a/code/deprecated/types/package.json
+++ b/code/deprecated/types/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/types",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Core Storybook TS Types",
"keywords": [
"storybook"
diff --git a/code/e2e-tests/addon-controls.spec.ts b/code/e2e-tests/addon-controls.spec.ts
index 6ba84552b81e..5ae41a18b2d4 100644
--- a/code/e2e-tests/addon-controls.spec.ts
+++ b/code/e2e-tests/addon-controls.spec.ts
@@ -29,7 +29,7 @@ test.describe('addon-controls', () => {
// Boolean toggle: Primary/secondary
await expect(sbPage.previewRoot().locator('button')).toHaveCSS(
'background-color',
- 'rgb(30, 167, 253)'
+ 'rgb(85, 90, 185)'
);
const toggle = sbPage.panelContent().locator('input[name=primary]');
await toggle.click();
@@ -61,7 +61,7 @@ test.describe('addon-controls', () => {
await reset.click();
const button = sbPage.previewRoot().locator('button');
await expect(button).toHaveCSS('font-size', '14px');
- await expect(button).toHaveCSS('background-color', 'rgb(30, 167, 253)');
+ await expect(button).toHaveCSS('background-color', 'rgb(85, 90, 185)');
await expect(button).toContainText('Button');
});
diff --git a/code/e2e-tests/module-mocking.spec.ts b/code/e2e-tests/module-mocking.spec.ts
index 5dd8ffd66555..3341f6449002 100644
--- a/code/e2e-tests/module-mocking.spec.ts
+++ b/code/e2e-tests/module-mocking.spec.ts
@@ -15,7 +15,7 @@ test.describe('module-mocking', () => {
test('should assert story lifecycle order', async ({ page }) => {
const sbPage = new SbPage(page, expect);
- await sbPage.navigateToStory('lib/test/before-each', 'before-each-order');
+ await sbPage.navigateToStory('lib/test/order-of-hooks', 'order-of-hooks');
await sbPage.viewAddonPanel('Actions');
const logItem = page.locator('#storybook-panel-root #panel-tab-content');
@@ -25,8 +25,12 @@ test.describe('module-mocking', () => {
'1 - [from loaders]',
'2 - [from meta beforeEach]',
'3 - [from story beforeEach]',
- '4 - [from decorator]',
- '5 - [from onClick]',
+ '4 - [before mount]',
+ '5 - [from decorator]',
+ '6 - [after mount]',
+ '7 - [from onClick]',
+ '8 - [from story afterEach]',
+ '9 - [from meta afterEach]',
];
// Assert that each LI text content contains the expected text in order
diff --git a/code/frameworks/angular/package.json b/code/frameworks/angular/package.json
index 3d073e66109b..7308e70929ef 100644
--- a/code/frameworks/angular/package.json
+++ b/code/frameworks/angular/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/angular",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Angular: Develop Angular components in isolation with hot reloading.",
"keywords": [
"storybook",
diff --git a/code/frameworks/angular/src/client/decorators.test.ts b/code/frameworks/angular/src/client/decorators.test.ts
index f7133806e3df..a977e681864b 100644
--- a/code/frameworks/angular/src/client/decorators.test.ts
+++ b/code/frameworks/angular/src/client/decorators.test.ts
@@ -20,6 +20,10 @@ const defaultContext: Addon_StoryContext = {
globals: {},
globalTypes: {},
storyGlobals: {},
+ reporting: {
+ reports: [],
+ addReport: vi.fn(),
+ },
hooks: {},
loaded: {},
originalStoryFn: vi.fn(),
diff --git a/code/frameworks/angular/template/components/button.css b/code/frameworks/angular/template/components/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/frameworks/angular/template/components/button.css
+++ b/code/frameworks/angular/template/components/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.css b/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.css
+++ b/code/frameworks/angular/template/stories_angular-cli-default-ts/signal/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.css b/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.css
+++ b/code/frameworks/angular/template/stories_angular-cli-prerelease/signal/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/frameworks/ember/package.json b/code/frameworks/ember/package.json
index dabea4045fe4..96f7f5cac31c 100644
--- a/code/frameworks/ember/package.json
+++ b/code/frameworks/ember/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/ember",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Ember: Develop Ember Component in isolation with Hot Reloading.",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/frameworks/ember",
"bugs": {
diff --git a/code/frameworks/experimental-nextjs-vite/package.json b/code/frameworks/experimental-nextjs-vite/package.json
index 31810fbfb604..6eafe4815adc 100644
--- a/code/frameworks/experimental-nextjs-vite/package.json
+++ b/code/frameworks/experimental-nextjs-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/experimental-nextjs-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Next.js and Vite",
"keywords": [
"storybook",
diff --git a/code/frameworks/html-vite/package.json b/code/frameworks/html-vite/package.json
index 888dba46797b..83c716b1076e 100644
--- a/code/frameworks/html-vite/package.json
+++ b/code/frameworks/html-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/html-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for HTML and Vite: Develop HTML in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/html-webpack5/package.json b/code/frameworks/html-webpack5/package.json
index e2c55679ed13..a0709bee9e39 100644
--- a/code/frameworks/html-webpack5/package.json
+++ b/code/frameworks/html-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/html-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/nextjs/package.json b/code/frameworks/nextjs/package.json
index 8739b514df43..4e76bf20686d 100644
--- a/code/frameworks/nextjs/package.json
+++ b/code/frameworks/nextjs/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/nextjs",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Next.js",
"keywords": [
"storybook",
diff --git a/code/frameworks/preact-vite/package.json b/code/frameworks/preact-vite/package.json
index 3722bec49c14..681d0ec88df4 100644
--- a/code/frameworks/preact-vite/package.json
+++ b/code/frameworks/preact-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preact-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Preact and Vite: Develop Preact components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/preact-webpack5/package.json b/code/frameworks/preact-webpack5/package.json
index 9a177ab76ba7..a26425c1e6ca 100644
--- a/code/frameworks/preact-webpack5/package.json
+++ b/code/frameworks/preact-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preact-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Preact: Develop Preact Component in isolation.",
"keywords": [
"storybook"
diff --git a/code/frameworks/react-native-web-vite/package.json b/code/frameworks/react-native-web-vite/package.json
index a727cb3fe88d..6a777924f4c0 100644
--- a/code/frameworks/react-native-web-vite/package.json
+++ b/code/frameworks/react-native-web-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/react-native-web-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Develop react-native components an isolated web environment with hot reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/react-vite/package.json b/code/frameworks/react-vite/package.json
index 5f304a9f1abc..c67870c9567d 100644
--- a/code/frameworks/react-vite/package.json
+++ b/code/frameworks/react-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/react-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for React and Vite: Develop React components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/react-webpack5/package.json b/code/frameworks/react-webpack5/package.json
index a2bcd11ae6b5..eed70f2c4fb3 100644
--- a/code/frameworks/react-webpack5/package.json
+++ b/code/frameworks/react-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/react-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/server-webpack5/package.json b/code/frameworks/server-webpack5/package.json
index 69d960f2b567..a89088118de4 100644
--- a/code/frameworks/server-webpack5/package.json
+++ b/code/frameworks/server-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/server-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/svelte-vite/package.json b/code/frameworks/svelte-vite/package.json
index f65153136284..bd0c531637f8 100644
--- a/code/frameworks/svelte-vite/package.json
+++ b/code/frameworks/svelte-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/svelte-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Svelte and Vite: Develop Svelte components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/svelte-webpack5/package.json b/code/frameworks/svelte-webpack5/package.json
index f722bd1d401d..198ff72986af 100644
--- a/code/frameworks/svelte-webpack5/package.json
+++ b/code/frameworks/svelte-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/svelte-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/sveltekit/package.json b/code/frameworks/sveltekit/package.json
index 57329852173a..cd3d90298520 100644
--- a/code/frameworks/sveltekit/package.json
+++ b/code/frameworks/sveltekit/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/sveltekit",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for SvelteKit",
"keywords": [
"storybook",
diff --git a/code/frameworks/vue3-vite/package.json b/code/frameworks/vue3-vite/package.json
index 519802837256..bab6eddec078 100644
--- a/code/frameworks/vue3-vite/package.json
+++ b/code/frameworks/vue3-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/vue3-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Vue3 and Vite: Develop Vue3 components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/vue3-webpack5/package.json b/code/frameworks/vue3-webpack5/package.json
index 3df3e880c3de..e2968fb6cf99 100644
--- a/code/frameworks/vue3-webpack5/package.json
+++ b/code/frameworks/vue3-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/vue3-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/web-components-vite/package.json b/code/frameworks/web-components-vite/package.json
index a1350863cdcd..d918f543bc11 100644
--- a/code/frameworks/web-components-vite/package.json
+++ b/code/frameworks/web-components-vite/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/web-components-vite",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for web-components and Vite: Develop Web Components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/frameworks/web-components-webpack5/package.json b/code/frameworks/web-components-webpack5/package.json
index 9296e9586d5b..57b0679e9f4f 100644
--- a/code/frameworks/web-components-webpack5/package.json
+++ b/code/frameworks/web-components-webpack5/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/web-components-webpack5",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for web-components: View web components snippets in isolation with Hot Reloading.",
"keywords": [
"lit",
diff --git a/code/lib/blocks/package.json b/code/lib/blocks/package.json
index 5d65fafe45d5..430cfd9969d7 100644
--- a/code/lib/blocks/package.json
+++ b/code/lib/blocks/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/blocks",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Doc Blocks",
"keywords": [
"storybook"
@@ -43,7 +43,7 @@
"prep": "jiti ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/icons": "^1.2.12",
"ts-dedent": "^2.0.0"
},
diff --git a/code/lib/cli-sb/package.json b/code/lib/cli-sb/package.json
index 5a6d260e0e01..eb660ccf8b08 100644
--- a/code/lib/cli-sb/package.json
+++ b/code/lib/cli-sb/package.json
@@ -1,6 +1,6 @@
{
"name": "sb",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook CLI",
"keywords": [
"storybook"
diff --git a/code/lib/cli-storybook/package.json b/code/lib/cli-storybook/package.json
index 4539ae8a93fd..8a9f87817b3d 100644
--- a/code/lib/cli-storybook/package.json
+++ b/code/lib/cli-storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/cli",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook CLI",
"keywords": [
"storybook"
diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts
new file mode 100644
index 000000000000..71110733d896
--- /dev/null
+++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.test.ts
@@ -0,0 +1,185 @@
+import { beforeEach, describe, expect, it, vi } from 'vitest';
+
+import { existsSync, readFileSync, writeFileSync } from 'fs';
+import path from 'path';
+import dedent from 'ts-dedent';
+
+import { getAddonNames } from '../helpers/mainConfigFile';
+import { addonA11yAddonTest, transformSetupFile } from './addon-a11y-addon-test';
+
+vi.mock('../helpers/mainConfigFile');
+
+// mock fs.existsSync
+vi.mock('fs', async (importOriginal) => {
+ const mod = (await importOriginal()) as any;
+ return {
+ ...mod,
+ existsSync: vi.fn(),
+ readFileSync: vi.fn(),
+ writeFileSync: vi.fn(),
+ };
+});
+
+describe('addonA11yAddonTest', () => {
+ const configDir = '/path/to/config';
+ const mainConfig = {} as any;
+
+ beforeEach(() => {
+ vi.clearAllMocks();
+ });
+
+ describe('check', () => {
+ it('should return null if a11y addon is not present', async () => {
+ vi.mocked(getAddonNames).mockReturnValue([]);
+ const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);
+ expect(result).toBeNull();
+ });
+
+ it('should return null if test addon is not present', async () => {
+ vi.mocked(getAddonNames).mockReturnValue(['@storybook/addon-a11y']);
+ const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);
+ expect(result).toBeNull();
+ });
+
+ it('should return null if configDir is not provided', async () => {
+ const result = await addonA11yAddonTest.check({ mainConfig, configDir: '' } as any);
+ expect(result).toBeNull();
+ });
+
+ it('should return setupFile and transformedSetupCode if vitest.setup file exists', async () => {
+ vi.mocked(getAddonNames).mockReturnValue([
+ '@storybook/addon-a11y',
+ '@storybook/experimental-addon-test',
+ ]);
+ vi.mocked(existsSync).mockReturnValue(true);
+ vi.mocked(readFileSync).mockReturnValue('const annotations = setProjectAnnotations([]);');
+
+ const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);
+ expect(result).toEqual({
+ setupFile: path.join(configDir, 'vitest.setup.js'),
+ transformedSetupCode: expect.any(String),
+ });
+ });
+
+ it('should return setupFile and null transformedSetupCode if transformation fails', async () => {
+ vi.mocked(getAddonNames).mockReturnValue([
+ '@storybook/addon-a11y',
+ '@storybook/experimental-addon-test',
+ ]);
+ vi.mocked(existsSync).mockReturnValue(true);
+ vi.mocked(readFileSync).mockImplementation(() => {
+ throw new Error('Test error');
+ });
+
+ const result = await addonA11yAddonTest.check({ mainConfig, configDir } as any);
+ expect(result).toEqual({
+ setupFile: path.join(configDir, 'vitest.setup.js'),
+ transformedSetupCode: null,
+ });
+ });
+ });
+
+ describe('prompt', () => {
+ it('should return manual prompt if setupFile is null', () => {
+ const result = addonA11yAddonTest.prompt({ setupFile: null, transformedSetupCode: null });
+ expect(result).toContain("We couldn't find or automatically update your");
+ });
+
+ it('should return auto prompt if setupFile and transformedSetupCode are present', () => {
+ const result = addonA11yAddonTest.prompt({
+ setupFile: '/path/to/vitest.setup.ts',
+ transformedSetupCode: 'transformed code',
+ });
+ expect(result).toContain('In order for these checks to be enabled we have to update your');
+ });
+ });
+
+ describe('run', () => {
+ it('should write transformed setup code to file', async () => {
+ const setupFile = '/path/to/vitest.setup.ts';
+ const transformedSetupCode = 'transformed code';
+
+ await addonA11yAddonTest.run?.({ result: { setupFile, transformedSetupCode } } as any);
+
+ expect(writeFileSync).toHaveBeenCalledWith(setupFile, transformedSetupCode, 'utf8');
+ });
+
+ it('should not write to file if setupFile or transformedSetupCode is null', async () => {
+ await addonA11yAddonTest.run?.({
+ result: { setupFile: null, transformedSetupCode: null },
+ } as any);
+
+ expect(writeFileSync).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('transformSetupFile', async () => {
+ it('should throw', async () => {
+ const setupFile = '/path/to/vitest.setup.ts';
+ const source = dedent`
+ import { beforeAll } from 'vitest';
+ import { setProjectAnnotations } from 'storybook';
+
+ beforeAll(project.beforeAll);
+ `;
+
+ vi.mocked(readFileSync).mockReturnValue(source);
+
+ expect(() => transformSetupFile(setupFile)).toThrow();
+ });
+
+ it('should transform setup file correctly - 1', () => {
+ const setupFile = '/path/to/vitest.setup.ts';
+ const source = dedent`
+ import { beforeAll } from 'vitest';
+ import { setProjectAnnotations } from 'storybook';
+ import * as projectAnnotations from './preview';
+
+ const project = setProjectAnnotations([projectAnnotations]);
+
+ beforeAll(project.beforeAll);
+ `;
+ vi.mocked(readFileSync).mockReturnValue(source);
+
+ const transformedCode = transformSetupFile(setupFile);
+ expect(transformedCode).toMatchInlineSnapshot(`
+ "import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
+ import { beforeAll } from 'vitest';
+ import { setProjectAnnotations } from 'storybook';
+ import * as projectAnnotations from './preview';
+
+ const project = setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
+
+ beforeAll(project.beforeAll);"
+ `);
+ });
+
+ it('should transform setup file correctly - 2 (different format)', () => {
+ const setupFile = '/path/to/vitest.setup.ts';
+ const source = dedent`
+ import { beforeAll } from 'vitest';
+ import { setProjectAnnotations } from 'storybook';
+ import * as projectAnnotations from './preview';
+
+ const project = setProjectAnnotations([
+ projectAnnotations
+ ]);
+
+ beforeAll(project.beforeAll);
+ `;
+ vi.mocked(readFileSync).mockReturnValue(source);
+
+ const transformedCode = transformSetupFile(setupFile);
+ expect(transformedCode).toMatchInlineSnapshot(`
+ "import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";
+ import { beforeAll } from 'vitest';
+ import { setProjectAnnotations } from 'storybook';
+ import * as projectAnnotations from './preview';
+
+ const project = setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);
+
+ beforeAll(project.beforeAll);"
+ `);
+ });
+ });
+});
diff --git a/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts
new file mode 100644
index 000000000000..ae848cf57689
--- /dev/null
+++ b/code/lib/cli-storybook/src/automigrate/fixes/addon-a11y-addon-test.ts
@@ -0,0 +1,160 @@
+import { existsSync, readFileSync, writeFileSync } from 'fs';
+import * as jscodeshift from 'jscodeshift';
+import path from 'path';
+import picocolors from 'picocolors';
+import { dedent } from 'ts-dedent';
+
+import { getAddonNames } from '../helpers/mainConfigFile';
+import type { Fix } from '../types';
+
+export const vitestFileExtensions = ['.js', '.ts', '.cts', '.mts', '.cjs', '.mjs'] as const;
+
+interface AddonA11yAddonTestOptions {
+ setupFile: string | null;
+ transformedSetupCode: string | null;
+}
+
+/**
+ * If addon-a11y and experimental-addon-test are already installed, we need to update
+ * `.storybook/vitest.setup.` to set up project annotations from addon-a11y. If we can't find
+ * `.storybook/vitest.setup.`, we need to set up a notification to the user to manually
+ * update the file.
+ */
+export const addonA11yAddonTest: Fix = {
+ id: 'addonA11yAddonTest',
+ // TODO: Change to the correct version after testing
+ versionRange: ['<8.5.0', '*'],
+
+ promptType(result) {
+ if (result.setupFile === null) {
+ return 'manual';
+ }
+
+ return 'auto';
+ },
+
+ async check({ mainConfig, configDir }) {
+ const addons = getAddonNames(mainConfig);
+
+ const hasA11yAddon = !!addons.find((addon) => addon.includes('@storybook/addon-a11y'));
+ const hasTestAddon = !!addons.find((addon) =>
+ addon.includes('@storybook/experimental-addon-test')
+ );
+
+ if (!hasA11yAddon || !hasTestAddon || !configDir) {
+ return null;
+ }
+
+ // get `${configDir}/vitest.setup.` absolute file path
+ const vitestSetupFile =
+ vitestFileExtensions
+ .map((ext) => path.join(configDir, `vitest.setup${ext}`))
+ .find((filePath) => existsSync(filePath)) ?? null;
+
+ try {
+ if (vitestSetupFile) {
+ const transformedSetupCode = transformSetupFile(vitestSetupFile);
+ return {
+ setupFile: vitestSetupFile,
+ transformedSetupCode,
+ };
+ } else {
+ return {
+ setupFile: null,
+ transformedSetupCode: null,
+ };
+ }
+ } catch (e) {
+ return {
+ setupFile: vitestSetupFile,
+ transformedSetupCode: null,
+ };
+ }
+ },
+
+ prompt({ setupFile, transformedSetupCode }) {
+ const introduction = dedent`
+ We have detected that you have ${picocolors.magenta(`@storybook/addon-a11y`)} and ${picocolors.magenta(`@storybook/experimental-addon-test`)} installed.
+
+ ${picocolors.magenta(`@storybook/addon-a11y`)} integrates now with ${picocolors.magenta(`@storybook/experimental-addon-test`)} to provide automatic accessibility checks for your stories, powered by Axe and Vitest.
+ `;
+
+ if (setupFile === null || transformedSetupCode === null) {
+ return dedent`
+ ${introduction}
+
+ We couldn't find or automatically update your ${picocolors.cyan(`.storybook/vitest.setup.`)} in your project to smoothly set up project annotations from ${picocolors.magenta(`@storybook/addon-a11y`)}.
+ Please manually update your ${picocolors.cyan(`vitest.setup.ts`)} file to include the following:
+
+ ${picocolors.gray('...')}
+ ${picocolors.green('+ import * as a11yAddonAnnotations from "@storybook/addon-a11y/preview";')}
+
+ ${picocolors.gray('const annotations = setProjectAnnotations([')}
+ ${picocolors.gray(' ...')}
+ ${picocolors.green('+ a11yAddonAnnotations,')}
+ ${picocolors.gray(']);')}
+
+ ${picocolors.gray('beforeAll(annotations.beforeAll);')}
+
+ For more information, please refer to the addon test documentation:
+ ${picocolors.cyan('https://storybook.js.org/docs/writing-tests/addon-test')}
+ `;
+ }
+
+ const fileExtension = path.extname(setupFile);
+
+ return dedent`
+ We have detected that you have ${picocolors.magenta(`@storybook/addon-a11y`)} and ${picocolors.magenta(`@storybook/experimental-addon-test`)} installed.
+
+ ${picocolors.magenta(`@storybook/addon-a11y`)} integrates now with ${picocolors.magenta(`@storybook/experimental-addon-test`)} to provide automatic accessibility checks for your stories, powered by Axe and Vitest.
+
+ In order for these checks to be enabled we have to update your ${picocolors.cyan(`.storybook/vitest.setup${fileExtension}`)} file.
+ `;
+ },
+
+ async run({ result }) {
+ const { setupFile, transformedSetupCode } = result;
+
+ if (!setupFile || !transformedSetupCode) {
+ return;
+ }
+
+ // Write the transformed code back to the file
+ writeFileSync(setupFile, transformedSetupCode, 'utf8');
+ },
+};
+
+export function transformSetupFile(setupFile: string) {
+ const source = readFileSync(setupFile, 'utf8');
+ const j = jscodeshift.withParser('ts');
+
+ const root = j(source);
+
+ // Import a11yAddonAnnotations
+ const importDeclaration = j.importDeclaration(
+ [j.importNamespaceSpecifier(j.identifier('a11yAddonAnnotations'))],
+ j.literal('@storybook/addon-a11y/preview')
+ );
+
+ // Find the setProjectAnnotations call
+ const setProjectAnnotationsCall = root.find(j.CallExpression, {
+ callee: {
+ type: 'Identifier',
+ name: 'setProjectAnnotations',
+ },
+ });
+
+ if (setProjectAnnotationsCall.length === 0) {
+ throw new Error('Could not find setProjectAnnotations call in vitest.setup file');
+ }
+
+ // Add a11yAddonAnnotations to the annotations array
+ setProjectAnnotationsCall.find(j.ArrayExpression).forEach((p) => {
+ p.value.elements.unshift(j.identifier('a11yAddonAnnotations'));
+ });
+
+ // Add the import declaration at the top
+ root.get().node.program.body.unshift(importDeclaration);
+
+ return root.toSource();
+}
diff --git a/code/lib/cli-storybook/src/automigrate/fixes/index.ts b/code/lib/cli-storybook/src/automigrate/fixes/index.ts
index 20d701bb16a8..dfd43100665c 100644
--- a/code/lib/cli-storybook/src/automigrate/fixes/index.ts
+++ b/code/lib/cli-storybook/src/automigrate/fixes/index.ts
@@ -1,4 +1,5 @@
import type { Fix } from '../types';
+import { addonA11yAddonTest } from './addon-a11y-addon-test';
import { addonPostCSS } from './addon-postcss';
import { addonsAPI } from './addons-api';
import { angularBuilders } from './angular-builders';
@@ -65,6 +66,7 @@ export const allFixes: Fix[] = [
vta,
autodocsTags,
initialGlobals,
+ addonA11yAddonTest,
];
export const initFixes: Fix[] = [eslintPlugin];
diff --git a/code/lib/cli/package.json b/code/lib/cli/package.json
index 985f6ce73c62..8c4627711f63 100644
--- a/code/lib/cli/package.json
+++ b/code/lib/cli/package.json
@@ -1,6 +1,6 @@
{
"name": "storybook",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook's CLI - install, dev, build, upgrade, and more",
"keywords": [
"cli",
diff --git a/code/lib/codemod/package.json b/code/lib/codemod/package.json
index b01b15c2ac07..606e5edba3e6 100644
--- a/code/lib/codemod/package.json
+++ b/code/lib/codemod/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/codemod",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "A collection of codemod scripts written with JSCodeshift",
"keywords": [
"storybook"
@@ -58,7 +58,7 @@
"@babel/preset-env": "^7.24.4",
"@babel/types": "^7.24.0",
"@storybook/core": "workspace:*",
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@types/cross-spawn": "^6.0.2",
"cross-spawn": "^7.0.3",
"es-toolkit": "^1.22.0",
diff --git a/code/lib/core-webpack/package.json b/code/lib/core-webpack/package.json
index f51817adb707..24f68690cfa3 100644
--- a/code/lib/core-webpack/package.json
+++ b/code/lib/core-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/core-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook framework-agnostic API",
"keywords": [
"storybook"
diff --git a/code/lib/create-storybook/package.json b/code/lib/create-storybook/package.json
index abf70ebc4d68..237aa9cee837 100644
--- a/code/lib/create-storybook/package.json
+++ b/code/lib/create-storybook/package.json
@@ -1,6 +1,6 @@
{
"name": "create-storybook",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Initialize Storybook into your project",
"homepage": "https://github.com/storybookjs/storybook/tree/next/code/lib/create-storybook",
"bugs": {
diff --git a/code/lib/create-storybook/rendererAssets/common/button.css b/code/lib/create-storybook/rendererAssets/common/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/lib/create-storybook/rendererAssets/common/button.css
+++ b/code/lib/create-storybook/rendererAssets/common/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/lib/create-storybook/rendererAssets/common/page.css b/code/lib/create-storybook/rendererAssets/common/page.css
index 87f7ecb17c4e..77c81d2d58f9 100644
--- a/code/lib/create-storybook/rendererAssets/common/page.css
+++ b/code/lib/create-storybook/rendererAssets/common/page.css
@@ -22,8 +22,7 @@
}
.storybook-page a {
- color: #1ea7fd;
- text-decoration: none;
+ color: inherit;
}
.storybook-page ul {
@@ -42,7 +41,7 @@
border-radius: 1em;
background: #e7fdd8;
padding: 4px 12px;
- color: #66bf3c;
+ color: #357a14;
font-weight: 700;
font-size: 11px;
line-height: 12px;
diff --git a/code/lib/csf-plugin/package.json b/code/lib/csf-plugin/package.json
index 2b8cd390b7ea..cfee2f12bbb7 100644
--- a/code/lib/csf-plugin/package.json
+++ b/code/lib/csf-plugin/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/csf-plugin",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Enrich CSF files via static analysis",
"keywords": [
"storybook"
diff --git a/code/lib/instrumenter/package.json b/code/lib/instrumenter/package.json
index a987140baea3..eef050e80786 100644
--- a/code/lib/instrumenter/package.json
+++ b/code/lib/instrumenter/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/instrumenter",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/lib/instrumenter/src/instrumenter.ts b/code/lib/instrumenter/src/instrumenter.ts
index 5e5a5c1cacab..524b7300222e 100644
--- a/code/lib/instrumenter/src/instrumenter.ts
+++ b/code/lib/instrumenter/src/instrumenter.ts
@@ -195,7 +195,7 @@ export class Instrumenter {
return {
playUntil: shadowCalls
.slice(0, firstRowIndex)
- .filter((call) => call.interceptable && !call.ancestors.length)
+ .filter((call) => call.interceptable && !call.ancestors?.length)
.slice(-1)[0]?.id,
};
});
@@ -205,7 +205,7 @@ export class Instrumenter {
};
const back = ({ storyId }: { storyId: string }) => {
- const log = this.getLog(storyId).filter((call) => !call.ancestors.length);
+ const log = this.getLog(storyId).filter((call) => !call.ancestors?.length);
const last = log.reduceRight((res, item, index) => {
if (res >= 0 || item.status === CallStates.WAITING) {
return res;
@@ -538,7 +538,7 @@ export class Instrumenter {
}));
// Exceptions inside callbacks should bubble up to the parent call.
- if (call.ancestors.length) {
+ if (call.ancestors?.length) {
if (!Object.prototype.hasOwnProperty.call(e, 'callId')) {
Object.defineProperty(e, 'callId', { value: call.id });
}
diff --git a/code/lib/react-dom-shim/package.json b/code/lib/react-dom-shim/package.json
index 5b007a076649..79ac3f3060c1 100644
--- a/code/lib/react-dom-shim/package.json
+++ b/code/lib/react-dom-shim/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/react-dom-shim",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
diff --git a/code/lib/source-loader/package.json b/code/lib/source-loader/package.json
index 14a48e23f5c4..f2fd5488f141 100644
--- a/code/lib/source-loader/package.json
+++ b/code/lib/source-loader/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/source-loader",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Source loader",
"keywords": [
"lib",
@@ -44,7 +44,7 @@
"prep": "jiti ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"es-toolkit": "^1.22.0",
"estraverse": "^5.2.0",
"prettier": "^3.1.1"
diff --git a/code/lib/test/package.json b/code/lib/test/package.json
index 6d044f1b8708..63247b810f01 100644
--- a/code/lib/test/package.json
+++ b/code/lib/test/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/test",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "",
"keywords": [
"storybook"
@@ -43,7 +43,7 @@
"prep": "jiti ../../../scripts/prepare/bundle.ts"
},
"dependencies": {
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/global": "^5.0.0",
"@storybook/instrumenter": "workspace:*",
"@testing-library/dom": "10.4.0",
diff --git a/code/lib/test/template/stories/before-each.stories.ts b/code/lib/test/template/stories/before-each.stories.ts
index 12aad1818afe..0d9a88cafa3c 100644
--- a/code/lib/test/template/stories/before-each.stories.ts
+++ b/code/lib/test/template/stories/before-each.stories.ts
@@ -1,48 +1,13 @@
/* eslint-disable @typescript-eslint/naming-convention,storybook/prefer-pascal-case */
-import { expect, getByRole, mocked, spyOn, userEvent } from '@storybook/test';
+import { expect } from '@storybook/test';
const meta = {
component: globalThis.Components.Button,
- loaders() {
- spyOn(console, 'log').mockName('console.log');
- console.log('1 - [from loaders]');
- },
- beforeEach() {
- console.log('2 - [from meta beforeEach]');
- },
+ args: { label: 'Button' },
};
export default meta;
-export const BeforeEachOrder = {
- parameters: { chromatic: { disable: true } },
- beforeEach() {
- console.log('3 - [from story beforeEach]');
- },
- decorators: (StoryFn: any) => {
- console.log('4 - [from decorator]');
- return StoryFn();
- },
- args: {
- label: 'Button',
- onClick: () => {
- console.log('5 - [from onClick]');
- },
- },
- async play({ canvasElement }: any) {
- await userEvent.click(getByRole(canvasElement, 'button'));
-
- const allLogs = mocked(console.log).mock.calls.filter(([message]) => /^\d+ - /.test(message));
- await expect(allLogs).toEqual([
- ['1 - [from loaders]'],
- ['2 - [from meta beforeEach]'],
- ['3 - [from story beforeEach]'],
- ['4 - [from decorator]'],
- ['5 - [from onClick]'],
- ]);
- },
-};
-
export const before_each_and_loaders_can_extend_context = {
parameters: { chromatic: { disable: true } },
loaders(context) {
diff --git a/code/lib/test/template/stories/mount-in-play.stories.ts b/code/lib/test/template/stories/mount-in-play.stories.ts
index 0c87263ba484..22c92497783d 100644
--- a/code/lib/test/template/stories/mount-in-play.stories.ts
+++ b/code/lib/test/template/stories/mount-in-play.stories.ts
@@ -1,50 +1,9 @@
-import { expect, fn, getByRole, mocked, spyOn, userEvent } from '@storybook/test';
+import { expect, fn } from '@storybook/test';
-const meta = {
- component: globalThis.Components.Button,
- loaders() {
- spyOn(console, 'log').mockName('console.log');
- console.log('1 - [from loaders]');
- },
- beforeEach() {
- console.log('2 - [from meta beforeEach]');
- },
-};
+const meta = { component: globalThis.Components.Button };
export default meta;
-export const MountInPlay = {
- beforeEach() {
- console.log('3 - [from story beforeEach]');
- },
- decorators: (storyFn) => {
- console.log('5 - [from decorator]');
- return storyFn();
- },
- args: {
- label: 'Button',
- onClick: () => {
- console.log('7 - [from onClick]');
- },
- },
- async play({ mount, canvasElement }) {
- console.log('4 - [before mount]');
- await mount();
- console.log('6 - [after mount]');
- await userEvent.click(getByRole(canvasElement, 'button'));
- const allLogs = mocked(console.log).mock.calls.filter(([message]) => /^\d+ - /.test(message));
- await expect(allLogs).toEqual([
- ['1 - [from loaders]'],
- ['2 - [from meta beforeEach]'],
- ['3 - [from story beforeEach]'],
- ['4 - [before mount]'],
- ['5 - [from decorator]'],
- ['6 - [after mount]'],
- ['7 - [from onClick]'],
- ]);
- },
-};
-
export const MountShouldBeDestructured = {
parameters: { chromatic: { disable: true } },
args: {
diff --git a/code/lib/test/template/stories/order-of-hooks.stories.ts b/code/lib/test/template/stories/order-of-hooks.stories.ts
new file mode 100644
index 000000000000..f3e965dee1b3
--- /dev/null
+++ b/code/lib/test/template/stories/order-of-hooks.stories.ts
@@ -0,0 +1,54 @@
+import { expect, fn, getByRole, mocked, spyOn, userEvent } from '@storybook/test';
+
+const meta = {
+ component: globalThis.Components.Button,
+ loaders() {
+ spyOn(console, 'log').mockName('console.log');
+ console.log('1 - [from loaders]');
+ },
+ beforeEach() {
+ console.log('2 - [from meta beforeEach]');
+ },
+ async experimental_afterEach() {
+ console.log('9 - [from meta afterEach]');
+
+ await expect(mocked(console.log).mock.calls).toEqual([
+ ['1 - [from loaders]'],
+ ['2 - [from meta beforeEach]'],
+ ['3 - [from story beforeEach]'],
+ ['4 - [before mount]'],
+ ['5 - [from decorator]'],
+ ['6 - [after mount]'],
+ ['7 - [from onClick]'],
+ ['8 - [from story afterEach]'],
+ ['9 - [from meta afterEach]'],
+ ]);
+ },
+};
+
+export default meta;
+
+export const OrderOfHooks = {
+ beforeEach() {
+ console.log('3 - [from story beforeEach]');
+ },
+ decorators: (storyFn) => {
+ console.log('5 - [from decorator]');
+ return storyFn();
+ },
+ args: {
+ label: 'Button',
+ onClick: () => {
+ console.log('7 - [from onClick]');
+ },
+ },
+ async play({ mount, canvasElement }) {
+ console.log('4 - [before mount]');
+ await mount();
+ console.log('6 - [after mount]');
+ await userEvent.click(getByRole(canvasElement, 'button'));
+ },
+ async experimental_afterEach() {
+ console.log('8 - [from story afterEach]');
+ },
+};
diff --git a/code/package.json b/code/package.json
index cad4c3bc025e..17e8e9c048d6 100644
--- a/code/package.json
+++ b/code/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/root",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"private": true,
"description": "Storybook root",
"homepage": "https://storybook.js.org/",
@@ -123,7 +123,7 @@
"@storybook/codemod": "workspace:*",
"@storybook/core": "workspace:*",
"@storybook/core-webpack": "workspace:*",
- "@storybook/csf": "0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/csf-plugin": "workspace:*",
"@storybook/ember": "workspace:*",
"@storybook/eslint-config-storybook": "^4.0.0",
diff --git a/code/presets/create-react-app/package.json b/code/presets/create-react-app/package.json
index 0abf32c7f106..e15f9f178ee6 100644
--- a/code/presets/create-react-app/package.json
+++ b/code/presets/create-react-app/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-create-react-app",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Create React App preset",
"keywords": [
"storybook"
diff --git a/code/presets/html-webpack/package.json b/code/presets/html-webpack/package.json
index 04259562e42f..2d80b196ffb0 100644
--- a/code/presets/html-webpack/package.json
+++ b/code/presets/html-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-html-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for HTML: View HTML snippets in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/presets/preact-webpack/package.json b/code/presets/preact-webpack/package.json
index 47a58f5fcc54..f483ee8dfce4 100644
--- a/code/presets/preact-webpack/package.json
+++ b/code/presets/preact-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-preact-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Preact: Develop Preact Component in isolation.",
"keywords": [
"storybook"
diff --git a/code/presets/react-webpack/package.json b/code/presets/react-webpack/package.json
index 439ac42128e6..4c347def5b69 100644
--- a/code/presets/react-webpack/package.json
+++ b/code/presets/react-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-react-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for React: Develop React Component in isolation with Hot Reloading",
"keywords": [
"storybook"
diff --git a/code/presets/server-webpack/package.json b/code/presets/server-webpack/package.json
index 1b8f29882f35..42d0b605a244 100644
--- a/code/presets/server-webpack/package.json
+++ b/code/presets/server-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-server-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Server: View HTML snippets from a server in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/presets/svelte-webpack/package.json b/code/presets/svelte-webpack/package.json
index 24182a57dce7..72c17dd4e8e8 100644
--- a/code/presets/svelte-webpack/package.json
+++ b/code/presets/svelte-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-svelte-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Svelte: Develop Svelte Component in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/presets/vue3-webpack/package.json b/code/presets/vue3-webpack/package.json
index 78d39c601e8f..b9a562aefc89 100644
--- a/code/presets/vue3-webpack/package.json
+++ b/code/presets/vue3-webpack/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preset-vue3-webpack",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook for Vue 3: Develop Vue 3 Components in isolation with Hot Reloading.",
"keywords": [
"storybook"
diff --git a/code/renderers/html/package.json b/code/renderers/html/package.json
index 05f5083e0ada..4e30884c2d84 100644
--- a/code/renderers/html/package.json
+++ b/code/renderers/html/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/html",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook HTML renderer",
"keywords": [
"storybook"
diff --git a/code/renderers/preact/package.json b/code/renderers/preact/package.json
index 4b9ac43bb3b4..67af51a9bbb4 100644
--- a/code/renderers/preact/package.json
+++ b/code/renderers/preact/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/preact",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Preact renderer",
"keywords": [
"storybook"
diff --git a/code/renderers/react/package.json b/code/renderers/react/package.json
index 28bffef0c467..77a70d1854d3 100644
--- a/code/renderers/react/package.json
+++ b/code/renderers/react/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/react",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook React renderer",
"keywords": [
"storybook"
diff --git a/code/renderers/react/src/__test__/button.css b/code/renderers/react/src/__test__/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/renderers/react/src/__test__/button.css
+++ b/code/renderers/react/src/__test__/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/renderers/server/package.json b/code/renderers/server/package.json
index cdd333669721..5aecd20df1d6 100644
--- a/code/renderers/server/package.json
+++ b/code/renderers/server/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/server",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Server renderer",
"keywords": [
"storybook"
@@ -46,7 +46,7 @@
},
"dependencies": {
"@storybook/components": "workspace:*",
- "@storybook/csf": "^0.1.11",
+ "@storybook/csf": "0.1.12",
"@storybook/global": "^5.0.0",
"@storybook/manager-api": "workspace:*",
"@storybook/preview-api": "workspace:*",
diff --git a/code/renderers/svelte/package.json b/code/renderers/svelte/package.json
index 369cebded2bf..bf328e615353 100644
--- a/code/renderers/svelte/package.json
+++ b/code/renderers/svelte/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/svelte",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Svelte renderer",
"keywords": [
"storybook"
diff --git a/code/renderers/svelte/template/components/button.css b/code/renderers/svelte/template/components/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/renderers/svelte/template/components/button.css
+++ b/code/renderers/svelte/template/components/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/renderers/vue3/package.json b/code/renderers/vue3/package.json
index dbf5c570fcd0..b5b1d437fcf3 100644
--- a/code/renderers/vue3/package.json
+++ b/code/renderers/vue3/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/vue3",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook Vue 3 renderer",
"keywords": [
"storybook"
diff --git a/code/renderers/vue3/src/__tests__/button.css b/code/renderers/vue3/src/__tests__/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/renderers/vue3/src/__tests__/button.css
+++ b/code/renderers/vue3/src/__tests__/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/renderers/vue3/template/components/button.css b/code/renderers/vue3/template/components/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/renderers/vue3/template/components/button.css
+++ b/code/renderers/vue3/template/components/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/renderers/web-components/package.json b/code/renderers/web-components/package.json
index 1e77bedb4997..324f56b82e7a 100644
--- a/code/renderers/web-components/package.json
+++ b/code/renderers/web-components/package.json
@@ -1,6 +1,6 @@
{
"name": "@storybook/web-components",
- "version": "8.5.0-alpha.18",
+ "version": "8.5.0-alpha.19",
"description": "Storybook web-components renderer",
"keywords": [
"lit",
diff --git a/code/renderers/web-components/template/components/button.css b/code/renderers/web-components/template/components/button.css
index 94d674b7614d..4e3620b0dcbf 100644
--- a/code/renderers/web-components/template/components/button.css
+++ b/code/renderers/web-components/template/components/button.css
@@ -8,7 +8,7 @@
font-family: 'Nunito Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.storybook-button--primary {
- background-color: #1ea7fd;
+ background-color: #555ab9;
color: white;
}
.storybook-button--secondary {
diff --git a/code/yarn.lock b/code/yarn.lock
index bbe92fd2608a..f0862ce5333e 100644
--- a/code/yarn.lock
+++ b/code/yarn.lock
@@ -378,6 +378,16 @@ __metadata:
languageName: node
linkType: hard
+"@babel/code-frame@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/code-frame@npm:7.24.7"
+ dependencies:
+ "@babel/highlight": "npm:^7.24.7"
+ picocolors: "npm:^1.0.0"
+ checksum: 10c0/ab0af539473a9f5aeaac7047e377cb4f4edd255a81d84a76058595f8540784cc3fbe8acf73f1e073981104562490aabfb23008cd66dc677a456a4ed5390fdde6
+ languageName: node
+ linkType: hard
+
"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.23.5, @babel/compat-data@npm:^7.24.4, @babel/compat-data@npm:^7.25.9":
version: 7.26.2
resolution: "@babel/compat-data@npm:7.26.2"
@@ -385,6 +395,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/compat-data@npm:^7.25.2":
+ version: 7.25.2
+ resolution: "@babel/compat-data@npm:7.25.2"
+ checksum: 10c0/5bf1f14d6e5f0d37c19543e99209ff4a94bb97915e1ce01e5334a144aa08cd56b6e62ece8135dac77e126723d63d4d4b96fc603a12c43b88c28f4b5e070270c5
+ languageName: node
+ linkType: hard
+
"@babel/core@npm:7.23.9":
version: 7.23.9
resolution: "@babel/core@npm:7.23.9"
@@ -431,7 +448,30 @@ __metadata:
languageName: node
linkType: hard
-"@babel/core@npm:^7.12.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.18.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.25.2, @babel/core@npm:^7.3.4, @babel/core@npm:^7.7.5":
+"@babel/core@npm:^7.12.0, @babel/core@npm:^7.12.3, @babel/core@npm:^7.13.16, @babel/core@npm:^7.18.9, @babel/core@npm:^7.23.0, @babel/core@npm:^7.23.2, @babel/core@npm:^7.23.9, @babel/core@npm:^7.24.4, @babel/core@npm:^7.3.4, @babel/core@npm:^7.7.5":
+ version: 7.25.2
+ resolution: "@babel/core@npm:7.25.2"
+ dependencies:
+ "@ampproject/remapping": "npm:^2.2.0"
+ "@babel/code-frame": "npm:^7.24.7"
+ "@babel/generator": "npm:^7.25.0"
+ "@babel/helper-compilation-targets": "npm:^7.25.2"
+ "@babel/helper-module-transforms": "npm:^7.25.2"
+ "@babel/helpers": "npm:^7.25.0"
+ "@babel/parser": "npm:^7.25.0"
+ "@babel/template": "npm:^7.25.0"
+ "@babel/traverse": "npm:^7.25.2"
+ "@babel/types": "npm:^7.25.2"
+ convert-source-map: "npm:^2.0.0"
+ debug: "npm:^4.1.0"
+ gensync: "npm:^1.0.0-beta.2"
+ json5: "npm:^2.2.3"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/a425fa40e73cb72b6464063a57c478bc2de9dbcc19c280f1b55a3d88b35d572e87e8594e7d7b4880331addb6faef641bbeb701b91b41b8806cd4deae5d74f401
+ languageName: node
+ linkType: hard
+
+"@babel/core@npm:^7.25.2":
version: 7.26.0
resolution: "@babel/core@npm:7.26.0"
dependencies:
@@ -490,6 +530,18 @@ __metadata:
languageName: node
linkType: hard
+"@babel/generator@npm:^7.25.0":
+ version: 7.25.0
+ resolution: "@babel/generator@npm:7.25.0"
+ dependencies:
+ "@babel/types": "npm:^7.25.0"
+ "@jridgewell/gen-mapping": "npm:^0.3.5"
+ "@jridgewell/trace-mapping": "npm:^0.3.25"
+ jsesc: "npm:^2.5.1"
+ checksum: 10c0/d0e2dfcdc8bdbb5dded34b705ceebf2e0bc1b06795a1530e64fb6a3ccf313c189db7f60c1616effae48114e1a25adc75855bc4496f3779a396b3377bae718ce7
+ languageName: node
+ linkType: hard
+
"@babel/helper-annotate-as-pure@npm:7.22.5":
version: 7.22.5
resolution: "@babel/helper-annotate-as-pure@npm:7.22.5"
@@ -531,6 +583,19 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-compilation-targets@npm:^7.25.2":
+ version: 7.25.2
+ resolution: "@babel/helper-compilation-targets@npm:7.25.2"
+ dependencies:
+ "@babel/compat-data": "npm:^7.25.2"
+ "@babel/helper-validator-option": "npm:^7.24.8"
+ browserslist: "npm:^4.23.1"
+ lru-cache: "npm:^5.1.1"
+ semver: "npm:^6.3.1"
+ checksum: 10c0/de10e986b5322c9f807350467dc845ec59df9e596a5926a3b5edbb4710d8e3b8009d4396690e70b88c3844fe8ec4042d61436dd4b92d1f5f75655cf43ab07e99
+ languageName: node
+ linkType: hard
+
"@babel/helper-create-class-features-plugin@npm:^7.18.6, @babel/helper-create-class-features-plugin@npm:^7.21.0, @babel/helper-create-class-features-plugin@npm:^7.24.0, @babel/helper-create-class-features-plugin@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-create-class-features-plugin@npm:7.24.7"
@@ -631,7 +696,17 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.24.3, @babel/helper-module-imports@npm:^7.24.7, @babel/helper-module-imports@npm:^7.25.9, @babel/helper-module-imports@npm:^7.8.3":
+"@babel/helper-module-imports@npm:^7.16.7, @babel/helper-module-imports@npm:^7.22.15, @babel/helper-module-imports@npm:^7.24.3, @babel/helper-module-imports@npm:^7.24.7, @babel/helper-module-imports@npm:^7.8.3":
+ version: 7.24.7
+ resolution: "@babel/helper-module-imports@npm:7.24.7"
+ dependencies:
+ "@babel/traverse": "npm:^7.24.7"
+ "@babel/types": "npm:^7.24.7"
+ checksum: 10c0/97c57db6c3eeaea31564286e328a9fb52b0313c5cfcc7eee4bc226aebcf0418ea5b6fe78673c0e4a774512ec6c86e309d0f326e99d2b37bfc16a25a032498af0
+ languageName: node
+ linkType: hard
+
+"@babel/helper-module-imports@npm:^7.25.9":
version: 7.25.9
resolution: "@babel/helper-module-imports@npm:7.25.9"
dependencies:
@@ -654,6 +729,20 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-module-transforms@npm:^7.25.2":
+ version: 7.25.2
+ resolution: "@babel/helper-module-transforms@npm:7.25.2"
+ dependencies:
+ "@babel/helper-module-imports": "npm:^7.24.7"
+ "@babel/helper-simple-access": "npm:^7.24.7"
+ "@babel/helper-validator-identifier": "npm:^7.24.7"
+ "@babel/traverse": "npm:^7.25.2"
+ peerDependencies:
+ "@babel/core": ^7.0.0
+ checksum: 10c0/adaa15970ace0aee5934b5a633789b5795b6229c6a9cf3e09a7e80aa33e478675eee807006a862aa9aa517935d81f88a6db8a9f5936e3a2a40ec75f8062bc329
+ languageName: node
+ linkType: hard
+
"@babel/helper-optimise-call-expression@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-optimise-call-expression@npm:7.24.7"
@@ -663,7 +752,14 @@ __metadata:
languageName: node
linkType: hard
-"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.25.9, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3":
+"@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.20.2, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0, @babel/helper-plugin-utils@npm:^7.8.3":
+ version: 7.24.7
+ resolution: "@babel/helper-plugin-utils@npm:7.24.7"
+ checksum: 10c0/c3d38cd9b3520757bb4a279255cc3f956fc0ac1c193964bd0816ebd5c86e30710be8e35252227e0c9d9e0f4f56d9b5f916537f2bc588084b0988b4787a967d31
+ languageName: node
+ linkType: hard
+
+"@babel/helper-plugin-utils@npm:^7.25.9":
version: 7.25.9
resolution: "@babel/helper-plugin-utils@npm:7.25.9"
checksum: 10c0/483066a1ba36ff16c0116cd24f93de05de746a603a777cd695ac7a1b034928a65a4ecb35f255761ca56626435d7abdb73219eba196f9aa83b6c3c3169325599d
@@ -734,6 +830,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-string-parser@npm:^7.24.8":
+ version: 7.24.8
+ resolution: "@babel/helper-string-parser@npm:7.24.8"
+ checksum: 10c0/6361f72076c17fabf305e252bf6d580106429014b3ab3c1f5c4eb3e6d465536ea6b670cc0e9a637a77a9ad40454d3e41361a2909e70e305116a23d68ce094c08
+ languageName: node
+ linkType: hard
+
"@babel/helper-string-parser@npm:^7.25.9":
version: 7.25.9
resolution: "@babel/helper-string-parser@npm:7.25.9"
@@ -755,6 +858,13 @@ __metadata:
languageName: node
linkType: hard
+"@babel/helper-validator-option@npm:^7.24.8":
+ version: 7.24.8
+ resolution: "@babel/helper-validator-option@npm:7.24.8"
+ checksum: 10c0/73db93a34ae89201351288bee7623eed81a54000779462a986105b54ffe82069e764afd15171a428b82e7c7a9b5fec10b5d5603b216317a414062edf5c67a21f
+ languageName: node
+ linkType: hard
+
"@babel/helper-wrap-function@npm:^7.24.7":
version: 7.24.7
resolution: "@babel/helper-wrap-function@npm:7.24.7"
@@ -777,7 +887,29 @@ __metadata:
languageName: node
linkType: hard
-"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.5, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.6, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.4, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6":
+"@babel/helpers@npm:^7.25.0":
+ version: 7.25.0
+ resolution: "@babel/helpers@npm:7.25.0"
+ dependencies:
+ "@babel/template": "npm:^7.25.0"
+ "@babel/types": "npm:^7.25.0"
+ checksum: 10c0/b7fe007fc4194268abf70aa3810365085e290e6528dcb9fbbf7a765d43c74b6369ce0f99c5ccd2d44c413853099daa449c9a0123f0b212ac8d18643f2e8174b8
+ languageName: node
+ linkType: hard
+
+"@babel/highlight@npm:^7.24.7":
+ version: 7.24.7
+ resolution: "@babel/highlight@npm:7.24.7"
+ dependencies:
+ "@babel/helper-validator-identifier": "npm:^7.24.7"
+ chalk: "npm:^2.4.2"
+ js-tokens: "npm:^4.0.0"
+ picocolors: "npm:^1.0.0"
+ checksum: 10c0/674334c571d2bb9d1c89bdd87566383f59231e16bcdcf5bb7835babdf03c9ae585ca0887a7b25bdf78f303984af028df52831c7989fecebb5101cc132da9393a
+ languageName: node
+ linkType: hard
+
+"@babel/parser@npm:^7.1.0, @babel/parser@npm:^7.11.5, @babel/parser@npm:^7.13.16, @babel/parser@npm:^7.14.7, @babel/parser@npm:^7.20.5, @babel/parser@npm:^7.20.7, @babel/parser@npm:^7.22.5, @babel/parser@npm:^7.23.0, @babel/parser@npm:^7.23.5, @babel/parser@npm:^7.23.6, @babel/parser@npm:^7.23.9, @babel/parser@npm:^7.24.0, @babel/parser@npm:^7.24.4, @babel/parser@npm:^7.24.7, @babel/parser@npm:^7.25.9, @babel/parser@npm:^7.26.0, @babel/parser@npm:^7.26.2, @babel/parser@npm:^7.4.5, @babel/parser@npm:^7.6.0, @babel/parser@npm:^7.9.6":
version: 7.26.2
resolution: "@babel/parser@npm:7.26.2"
dependencies:
@@ -788,6 +920,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.3":
+ version: 7.25.3
+ resolution: "@babel/parser@npm:7.25.3"
+ dependencies:
+ "@babel/types": "npm:^7.25.2"
+ bin:
+ parser: ./bin/babel-parser.js
+ checksum: 10c0/874b01349aedb805d6694f867a752fdc7469778fad76aca4548d2cc6ce96087c3ba5fb917a6f8d05d2d1a74aae309b5f50f1a4dba035f5a2c9fcfe6e106d2c4e
+ languageName: node
+ linkType: hard
+
"@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:^7.24.4":
version: 7.24.4
resolution: "@babel/plugin-bugfix-firefox-class-in-computed-class-key@npm:7.24.4"
@@ -2247,6 +2390,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/template@npm:^7.25.0":
+ version: 7.25.0
+ resolution: "@babel/template@npm:7.25.0"
+ dependencies:
+ "@babel/code-frame": "npm:^7.24.7"
+ "@babel/parser": "npm:^7.25.0"
+ "@babel/types": "npm:^7.25.0"
+ checksum: 10c0/4e31afd873215744c016e02b04f43b9fa23205d6d0766fb2e93eb4091c60c1b88897936adb895fb04e3c23de98dfdcbe31bc98daaa1a4e0133f78bb948e1209b
+ languageName: node
+ linkType: hard
+
"@babel/traverse@npm:7.23.2":
version: 7.23.2
resolution: "@babel/traverse@npm:7.23.2"
@@ -2280,6 +2434,21 @@ __metadata:
languageName: node
linkType: hard
+"@babel/traverse@npm:^7.25.2":
+ version: 7.25.3
+ resolution: "@babel/traverse@npm:7.25.3"
+ dependencies:
+ "@babel/code-frame": "npm:^7.24.7"
+ "@babel/generator": "npm:^7.25.0"
+ "@babel/parser": "npm:^7.25.3"
+ "@babel/template": "npm:^7.25.0"
+ "@babel/types": "npm:^7.25.2"
+ debug: "npm:^4.3.1"
+ globals: "npm:^11.1.0"
+ checksum: 10c0/4c8a1966fa90b53a783a4afd2fcdaa6ab1a912e6621dca9fcc6633e80ccb9491620e88caf73b537da4e16cefd537b548c87d7087868d5b0066414dea375c0e9b
+ languageName: node
+ linkType: hard
+
"@babel/types@npm:7.17.0":
version: 7.17.0
resolution: "@babel/types@npm:7.17.0"
@@ -2290,7 +2459,7 @@ __metadata:
languageName: node
linkType: hard
-"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.17.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.23.9, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.4, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.2, @babel/types@npm:^7.9.6":
+"@babel/types@npm:^7.0.0, @babel/types@npm:^7.11.5, @babel/types@npm:^7.17.0, @babel/types@npm:^7.18.9, @babel/types@npm:^7.2.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.22.5, @babel/types@npm:^7.23.0, @babel/types@npm:^7.23.4, @babel/types@npm:^7.23.6, @babel/types@npm:^7.23.9, @babel/types@npm:^7.24.0, @babel/types@npm:^7.24.7, @babel/types@npm:^7.25.9, @babel/types@npm:^7.26.0, @babel/types@npm:^7.4.4, @babel/types@npm:^7.6.1, @babel/types@npm:^7.7.2, @babel/types@npm:^7.9.6":
version: 7.26.0
resolution: "@babel/types@npm:7.26.0"
dependencies:
@@ -2300,6 +2469,17 @@ __metadata:
languageName: node
linkType: hard
+"@babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2":
+ version: 7.25.2
+ resolution: "@babel/types@npm:7.25.2"
+ dependencies:
+ "@babel/helper-string-parser": "npm:^7.24.8"
+ "@babel/helper-validator-identifier": "npm:^7.24.7"
+ to-fast-properties: "npm:^2.0.0"
+ checksum: 10c0/e489435856be239f8cc1120c90a197e4c2865385121908e5edb7223cfdff3768cba18f489adfe0c26955d9e7bbb1fb10625bc2517505908ceb0af848989bd864
+ languageName: node
+ linkType: hard
+
"@base2/pretty-print-object@npm:1.0.1":
version: 1.0.1
resolution: "@base2/pretty-print-object@npm:1.0.1"
@@ -2862,13 +3042,20 @@ __metadata:
languageName: node
linkType: hard
-"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1":
+"@eslint-community/regexpp@npm:^4.10.0":
version: 4.12.1
resolution: "@eslint-community/regexpp@npm:4.12.1"
checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6
languageName: node
linkType: hard
+"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1":
+ version: 4.10.0
+ resolution: "@eslint-community/regexpp@npm:4.10.0"
+ checksum: 10c0/c5f60ef1f1ea7649fa7af0e80a5a79f64b55a8a8fa5086de4727eb4c86c652aedee407a9c143b8995d2c0b2d75c1222bec9ba5d73dbfc1f314550554f0979ef4
+ languageName: node
+ linkType: hard
+
"@eslint/eslintrc@npm:^1.0.5":
version: 1.4.1
resolution: "@eslint/eslintrc@npm:1.4.1"
@@ -4629,13 +4816,20 @@ __metadata:
languageName: node
linkType: hard
-"@polka/url@npm:^1.0.0-next.21, @polka/url@npm:^1.0.0-next.24":
+"@polka/url@npm:^1.0.0-next.21":
version: 1.0.0-next.28
resolution: "@polka/url@npm:1.0.0-next.28"
checksum: 10c0/acc5ea62597e4da2fb42dbee02749d07f102ae7d6d2c966bf7e423c79cd65d1621da305af567e6e7c232f3b565e242d1ec932cbb3dcc0db1508d02e9a2cafa2e
languageName: node
linkType: hard
+"@polka/url@npm:^1.0.0-next.24":
+ version: 1.0.0-next.25
+ resolution: "@polka/url@npm:1.0.0-next.25"
+ checksum: 10c0/ef61f0a0fe94bb6e1143fc5b9d5a12e6ca9dbd2c57843ebf81db432c21b9f1005c09e8a1ef8b6d5ddfa42146ca65b640feb2d353bd0d3546da46ba59e48a5349
+ languageName: node
+ linkType: hard
+
"@popperjs/core@npm:^2.11.5, @popperjs/core@npm:^2.6.0":
version: 2.11.8
resolution: "@popperjs/core@npm:2.11.8"
@@ -5309,13 +5503,17 @@ __metadata:
"@storybook/addon-highlight": "workspace:*"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.12"
+ "@storybook/test": "workspace:*"
"@testing-library/react": "npm:^14.0.0"
axe-core: "npm:^4.2.0"
+ picocolors: "npm:^1.1.0"
+ pretty-format: "npm:^29.7.0"
react: "npm:^18.2.0"
react-dom: "npm:^18.2.0"
react-resize-detector: "npm:^7.1.2"
resize-observer-polyfill: "npm:^1.5.1"
typescript: "npm:^5.3.2"
+ vitest-axe: "npm:^0.1.0"
peerDependencies:
storybook: "workspace:^"
languageName: unknown
@@ -5495,7 +5693,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/addon-links@workspace:addons/links"
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
ts-dedent: "npm:^2.0.0"
typescript: "npm:^5.3.2"
@@ -5721,7 +5919,7 @@ __metadata:
resolution: "@storybook/blocks@workspace:lib/blocks"
dependencies:
"@storybook/addon-actions": "workspace:*"
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/icons": "npm:^1.2.12"
"@storybook/react": "workspace:*"
"@storybook/test": "workspace:*"
@@ -5893,7 +6091,7 @@ __metadata:
"@babel/preset-env": "npm:^7.24.4"
"@babel/types": "npm:^7.24.0"
"@storybook/core": "workspace:*"
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@types/cross-spawn": "npm:^6.0.2"
"@types/jscodeshift": "npm:^0.11.10"
ansi-regex: "npm:^6.0.1"
@@ -5989,7 +6187,7 @@ __metadata:
"@radix-ui/react-dialog": "npm:^1.0.5"
"@radix-ui/react-scroll-area": "npm:1.2.0-rc.7"
"@radix-ui/react-slot": "npm:^1.0.2"
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/docs-mdx": "npm:4.0.0-next.1"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.12"
@@ -6128,12 +6326,12 @@ __metadata:
languageName: unknown
linkType: soft
-"@storybook/csf@npm:0.1.11, @storybook/csf@npm:^0.1.11":
- version: 0.1.11
- resolution: "@storybook/csf@npm:0.1.11"
+"@storybook/csf@npm:0.1.12":
+ version: 0.1.12
+ resolution: "@storybook/csf@npm:0.1.12"
dependencies:
type-fest: "npm:^2.19.0"
- checksum: 10c0/c5329fc13e7d762049b5c91df1bc1c0e510a1a898c401b72b68f1ff64139a85ab64a92f8e681d2fcb226c0a4a55d0f23b569b2bdb517e0f067bd05ea46228356
+ checksum: 10c0/3d96a976ada67eb683279338d1eb6aa730b228107d4c4f6616ea7b94061899c1fdc11957a756e7bc0708d18cb39af0010c865d124efd84559cd82dcb2d8bc959
languageName: node
linkType: hard
@@ -6200,7 +6398,7 @@ __metadata:
resolution: "@storybook/experimental-addon-test@workspace:addons/test"
dependencies:
"@devtools-ds/object-inspector": "npm:^1.1.2"
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.12"
"@storybook/instrumenter": "workspace:*"
@@ -6328,7 +6526,7 @@ __metadata:
languageName: unknown
linkType: soft
-"@storybook/icons@npm:^1.2.12, @storybook/icons@npm:^1.2.5":
+"@storybook/icons@npm:^1.2.12":
version: 1.2.12
resolution: "@storybook/icons@npm:1.2.12"
peerDependencies:
@@ -6338,6 +6536,16 @@ __metadata:
languageName: node
linkType: hard
+"@storybook/icons@npm:^1.2.5":
+ version: 1.2.10
+ resolution: "@storybook/icons@npm:1.2.10"
+ peerDependencies:
+ react: ^16.8.0 || ^17.0.0 || ^18.0.0
+ react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0
+ checksum: 10c0/aadde2efd5c471b78096f29a6393db111ee95174cab94ade0d2859d476262f080aa8ffb414f82932afd81d5c57bed813193a04e92086962bde2224774dac9060
+ languageName: node
+ linkType: hard
+
"@storybook/instrumenter@workspace:*, @storybook/instrumenter@workspace:lib/instrumenter":
version: 0.0.0-use.local
resolution: "@storybook/instrumenter@workspace:lib/instrumenter"
@@ -6844,7 +7052,7 @@ __metadata:
"@storybook/codemod": "workspace:*"
"@storybook/core": "workspace:*"
"@storybook/core-webpack": "workspace:*"
- "@storybook/csf": "npm:0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/csf-plugin": "workspace:*"
"@storybook/ember": "workspace:*"
"@storybook/eslint-config-storybook": "npm:^4.0.0"
@@ -6991,7 +7199,7 @@ __metadata:
resolution: "@storybook/server@workspace:renderers/server"
dependencies:
"@storybook/components": "workspace:*"
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
"@storybook/manager-api": "workspace:*"
"@storybook/preview-api": "workspace:*"
@@ -7008,7 +7216,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/source-loader@workspace:lib/source-loader"
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
es-toolkit: "npm:^1.22.0"
estraverse: "npm:^5.2.0"
prettier: "npm:^3.1.1"
@@ -7122,7 +7330,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/test@workspace:lib/test"
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
"@storybook/instrumenter": "workspace:*"
"@testing-library/dom": "npm:10.4.0"
@@ -7329,7 +7537,7 @@ __metadata:
languageName: node
linkType: hard
-"@swc/helpers@npm:0.5.13, @swc/helpers@npm:~0.5.0":
+"@swc/helpers@npm:0.5.13":
version: 0.5.13
resolution: "@swc/helpers@npm:0.5.13"
dependencies:
@@ -7338,6 +7546,15 @@ __metadata:
languageName: node
linkType: hard
+"@swc/helpers@npm:~0.5.0":
+ version: 0.5.6
+ resolution: "@swc/helpers@npm:0.5.6"
+ dependencies:
+ tslib: "npm:^2.4.0"
+ checksum: 10c0/ae43e2130b0c47a8c5dc51148925604707ee7801fef90674f71d2266a98b272c8f16145931fc7d51daf6795c4f3a86ccecd472e94a7ea562e0db7c333447d9e6
+ languageName: node
+ linkType: hard
+
"@tanstack/react-virtual@npm:^3.3.0":
version: 3.3.0
resolution: "@tanstack/react-virtual@npm:3.3.0"
@@ -7965,13 +8182,20 @@ __metadata:
languageName: node
linkType: hard
-"@types/istanbul-lib-coverage@npm:*, @types/istanbul-lib-coverage@npm:^2.0.1":
+"@types/istanbul-lib-coverage@npm:*":
version: 2.0.6
resolution: "@types/istanbul-lib-coverage@npm:2.0.6"
checksum: 10c0/3948088654f3eeb45363f1db158354fb013b362dba2a5c2c18c559484d5eb9f6fd85b23d66c0a7c2fcfab7308d0a585b14dadaca6cc8bf89ebfdc7f8f5102fb7
languageName: node
linkType: hard
+"@types/istanbul-lib-coverage@npm:^2.0.1":
+ version: 2.0.4
+ resolution: "@types/istanbul-lib-coverage@npm:2.0.4"
+ checksum: 10c0/af5f6b64e788331ed3f7b2e2613cb6ca659c58b8500be94bbda8c995ad3da9216c006f1cfe6f66b321c39392b1bda18b16e63cef090a77d24a00b4bd5ba3b018
+ languageName: node
+ linkType: hard
+
"@types/istanbul-lib-report@npm:^3.0.3":
version: 3.0.3
resolution: "@types/istanbul-lib-report@npm:3.0.3"
@@ -8899,48 +9123,48 @@ __metadata:
linkType: hard
"@vitest/coverage-istanbul@npm:^2.1.3":
- version: 2.1.8
- resolution: "@vitest/coverage-istanbul@npm:2.1.8"
+ version: 2.1.3
+ resolution: "@vitest/coverage-istanbul@npm:2.1.3"
dependencies:
"@istanbuljs/schema": "npm:^0.1.3"
- debug: "npm:^4.3.7"
+ debug: "npm:^4.3.6"
istanbul-lib-coverage: "npm:^3.2.2"
istanbul-lib-instrument: "npm:^6.0.3"
istanbul-lib-report: "npm:^3.0.1"
istanbul-lib-source-maps: "npm:^5.0.6"
istanbul-reports: "npm:^3.1.7"
- magicast: "npm:^0.3.5"
+ magicast: "npm:^0.3.4"
test-exclude: "npm:^7.0.1"
tinyrainbow: "npm:^1.2.0"
peerDependencies:
- vitest: 2.1.8
- checksum: 10c0/809eeccebaa7fd0e349d89a8d374e449c65a1d626f46b03b080aa507ac93dfb340c90dd491fe9a08dca896d6832e0f3dcffd6fd7ba3d05c1dc95c7a32aabc50c
+ vitest: 2.1.3
+ checksum: 10c0/6b21eb219f45dc0f3bfb35049280658687b6b2f4ba5e17dc2c7e2c221f5d37e60c6962c5cfd77bd5f2848bb56debd26f82e5684b293f5775a8a416a0173f1803
languageName: node
linkType: hard
"@vitest/coverage-v8@npm:^2.1.3":
- version: 2.1.8
- resolution: "@vitest/coverage-v8@npm:2.1.8"
+ version: 2.1.3
+ resolution: "@vitest/coverage-v8@npm:2.1.3"
dependencies:
"@ampproject/remapping": "npm:^2.3.0"
"@bcoe/v8-coverage": "npm:^0.2.3"
- debug: "npm:^4.3.7"
+ debug: "npm:^4.3.6"
istanbul-lib-coverage: "npm:^3.2.2"
istanbul-lib-report: "npm:^3.0.1"
istanbul-lib-source-maps: "npm:^5.0.6"
istanbul-reports: "npm:^3.1.7"
- magic-string: "npm:^0.30.12"
- magicast: "npm:^0.3.5"
- std-env: "npm:^3.8.0"
+ magic-string: "npm:^0.30.11"
+ magicast: "npm:^0.3.4"
+ std-env: "npm:^3.7.0"
test-exclude: "npm:^7.0.1"
tinyrainbow: "npm:^1.2.0"
peerDependencies:
- "@vitest/browser": 2.1.8
- vitest: 2.1.8
+ "@vitest/browser": 2.1.3
+ vitest: 2.1.3
peerDependenciesMeta:
"@vitest/browser":
optional: true
- checksum: 10c0/b228a23bbaf0eae07ac939399f968b0def2df786091948a12d614919db3f5b6e46db7a1ab4f9d05d5d7f696afd53133a67abc25915f85480cd032442664ac725
+ checksum: 10c0/5fdff9e9dd8b8d2030c00a5273ba2b27441c0cb45d007b6671504745dac6d095c160a01433789e7ed1ca6cd234246f883c1d52c02cfb62f8ae81dda17dd56bc6
languageName: node
linkType: hard
@@ -10515,6 +10739,13 @@ __metadata:
languageName: node
linkType: hard
+"axe-core@npm:^4.4.2":
+ version: 4.10.2
+ resolution: "axe-core@npm:4.10.2"
+ checksum: 10c0/0e20169077de96946a547fce0df39d9aeebe0077f9d3eeff4896518b96fde857f80b98f0d4279274a7178791744dd5a54bb4f322de45b4f561ffa2586ff9a09d
+ languageName: node
+ linkType: hard
+
"axios@npm:^1.6.1, axios@npm:^1.7.4":
version: 1.7.9
resolution: "axios@npm:1.7.9"
@@ -11368,6 +11599,20 @@ __metadata:
languageName: node
linkType: hard
+"browserslist@npm:^4.23.1":
+ version: 4.23.3
+ resolution: "browserslist@npm:4.23.3"
+ dependencies:
+ caniuse-lite: "npm:^1.0.30001646"
+ electron-to-chromium: "npm:^1.5.4"
+ node-releases: "npm:^2.0.18"
+ update-browserslist-db: "npm:^1.1.0"
+ bin:
+ browserslist: cli.js
+ checksum: 10c0/3063bfdf812815346447f4796c8f04601bf5d62003374305fd323c2a463e42776475bcc5309264e39bcf9a8605851e53560695991a623be988138b3ff8c66642
+ languageName: node
+ linkType: hard
+
"buffer-crc32@npm:^0.2.5":
version: 0.2.13
resolution: "buffer-crc32@npm:0.2.13"
@@ -11628,6 +11873,13 @@ __metadata:
languageName: node
linkType: hard
+"caniuse-lite@npm:^1.0.30001646":
+ version: 1.0.30001650
+ resolution: "caniuse-lite@npm:1.0.30001650"
+ checksum: 10c0/81d271517f452321d4274d514dcbf4d57fc7ca6d2f82d4e273a850fc6d92d334d97bbec8359ce2237c7f2d128729037b82ca506c7213511dc8380b8ec24d9d45
+ languageName: node
+ linkType: hard
+
"case-sensitive-paths-webpack-plugin@npm:^2.4.0":
version: 2.4.0
resolution: "case-sensitive-paths-webpack-plugin@npm:2.4.0"
@@ -11655,14 +11907,14 @@ __metadata:
languageName: node
linkType: hard
-"chalk@npm:5.3.0, chalk@npm:^5.0.0, chalk@npm:^5.2.0, chalk@npm:^5.3.0":
+"chalk@npm:5.3.0, chalk@npm:^5.0.0, chalk@npm:^5.0.1, chalk@npm:^5.2.0, chalk@npm:^5.3.0":
version: 5.3.0
resolution: "chalk@npm:5.3.0"
checksum: 10c0/8297d436b2c0f95801103ff2ef67268d362021b8210daf8ddbe349695333eb3610a71122172ff3b0272f1ef2cf7cc2c41fdaa4715f52e49ffe04c56340feed09
languageName: node
linkType: hard
-"chalk@npm:^2.0.0, chalk@npm:^2.3.0":
+"chalk@npm:^2.0.0, chalk@npm:^2.3.0, chalk@npm:^2.4.2":
version: 2.4.2
resolution: "chalk@npm:2.4.2"
dependencies:
@@ -13419,7 +13671,7 @@ __metadata:
languageName: node
linkType: hard
-"dom-accessibility-api@npm:^0.5.9":
+"dom-accessibility-api@npm:^0.5.14, dom-accessibility-api@npm:^0.5.9":
version: 0.5.16
resolution: "dom-accessibility-api@npm:0.5.16"
checksum: 10c0/b2c2eda4fae568977cdac27a9f0c001edf4f95a6a6191dfa611e3721db2478d1badc01db5bb4fa8a848aeee13e442a6c2a4386d65ec65a1436f24715a2f8d053
@@ -13563,7 +13815,14 @@ __metadata:
languageName: node
linkType: hard
-"dotenv@npm:^16.0.0, dotenv@npm:^16.4.5, dotenv@npm:~16.4.5":
+"dotenv@npm:^16.0.0":
+ version: 16.3.1
+ resolution: "dotenv@npm:16.3.1"
+ checksum: 10c0/b95ff1bbe624ead85a3cd70dbd827e8e06d5f05f716f2d0cbc476532d54c7c9469c3bc4dd93ea519f6ad711cb522c00ac9a62b6eb340d5affae8008facc3fbd7
+ languageName: node
+ linkType: hard
+
+"dotenv@npm:^16.4.5, dotenv@npm:~16.4.5":
version: 16.4.7
resolution: "dotenv@npm:16.4.7"
checksum: 10c0/be9f597e36a8daf834452daa1f4cc30e5375a5968f98f46d89b16b983c567398a330580c88395069a77473943c06b877d1ca25b4afafcdd6d4adb549e8293462
@@ -13675,6 +13934,13 @@ __metadata:
languageName: node
linkType: hard
+"electron-to-chromium@npm:^1.5.4":
+ version: 1.5.5
+ resolution: "electron-to-chromium@npm:1.5.5"
+ checksum: 10c0/6e5e12f729a74a78d9a7386ea32039262cb8a2f4611ab346da1f162c270d0569194c72169042080a1017220835ed30ee2d77ca5ba13c1acaa5fa0d373fbc0ad5
+ languageName: node
+ linkType: hard
+
"electron-to-chromium@npm:^1.5.41":
version: 1.5.50
resolution: "electron-to-chromium@npm:1.5.50"
@@ -14349,6 +14615,13 @@ __metadata:
languageName: node
linkType: hard
+"escalade@npm:^3.1.2":
+ version: 3.1.2
+ resolution: "escalade@npm:3.1.2"
+ checksum: 10c0/6b4adafecd0682f3aa1cd1106b8fff30e492c7015b178bc81b2d2f75106dabea6c6d6e8508fc491bd58e597c74abb0e8e2368f943ecb9393d4162e3c2f3cf287
+ languageName: node
+ linkType: hard
+
"escape-html@npm:~1.0.3":
version: 1.0.3
resolution: "escape-html@npm:1.0.3"
@@ -19624,7 +19897,16 @@ __metadata:
languageName: node
linkType: hard
-"magic-string@npm:^0.30.0, magic-string@npm:^0.30.11, magic-string@npm:^0.30.12, magic-string@npm:^0.30.5":
+"magic-string@npm:^0.30.0, magic-string@npm:^0.30.11, magic-string@npm:^0.30.5":
+ version: 0.30.11
+ resolution: "magic-string@npm:0.30.11"
+ dependencies:
+ "@jridgewell/sourcemap-codec": "npm:^1.5.0"
+ checksum: 10c0/b9eb370773d0bd90ca11a848753409d8e5309b1ad56d2a1aa49d6649da710a6d2fe7237ad1a643c5a5d3800de2b9946ed9690acdfc00e6cc1aeafff3ab1752c4
+ languageName: node
+ linkType: hard
+
+"magic-string@npm:^0.30.12":
version: 0.30.12
resolution: "magic-string@npm:0.30.12"
dependencies:
@@ -19633,14 +19915,14 @@ __metadata:
languageName: node
linkType: hard
-"magicast@npm:^0.3.5":
- version: 0.3.5
- resolution: "magicast@npm:0.3.5"
+"magicast@npm:^0.3.4":
+ version: 0.3.4
+ resolution: "magicast@npm:0.3.4"
dependencies:
- "@babel/parser": "npm:^7.25.4"
- "@babel/types": "npm:^7.25.4"
+ "@babel/parser": "npm:^7.24.4"
+ "@babel/types": "npm:^7.24.0"
source-map-js: "npm:^1.2.0"
- checksum: 10c0/a6cacc0a848af84f03e3f5bda7b0de75e4d0aa9ddce5517fd23ed0f31b5ddd51b2d0ff0b7e09b51f7de0f4053c7a1107117edda6b0732dca3e9e39e6c5a68c64
+ checksum: 10c0/7ebaaac397b13c31ca05e6d9649296751d76749b945d10a0800107872119fbdf267acdb604571d25e38ec6fd7ab3568a951b6e76eaef1caba9eaa11778fd9783
languageName: node
linkType: hard
@@ -26438,7 +26720,7 @@ __metadata:
languageName: node
linkType: hard
-"std-env@npm:^3.7.0, std-env@npm:^3.8.0":
+"std-env@npm:^3.7.0":
version: 3.8.0
resolution: "std-env@npm:3.8.0"
checksum: 10c0/f560a2902fd0fa3d648d7d0acecbd19d664006f7372c1fba197ed4c216b4c9e48db6e2769b5fe1616d42a9333c9f066c5011935035e85c59f45dc4f796272040
@@ -26967,7 +27249,7 @@ __metadata:
languageName: node
linkType: hard
-"svelte@npm:^5.0.0, svelte@npm:^5.0.0-next.268, svelte@npm:^5.0.5":
+"svelte@npm:^5.0.0, svelte@npm:^5.0.5":
version: 5.0.5
resolution: "svelte@npm:5.0.5"
dependencies:
@@ -26988,6 +27270,27 @@ __metadata:
languageName: node
linkType: hard
+"svelte@npm:^5.0.0-next.268":
+ version: 5.0.0-next.268
+ resolution: "svelte@npm:5.0.0-next.268"
+ dependencies:
+ "@ampproject/remapping": "npm:^2.3.0"
+ "@jridgewell/sourcemap-codec": "npm:^1.5.0"
+ "@types/estree": "npm:^1.0.5"
+ acorn: "npm:^8.12.1"
+ acorn-typescript: "npm:^1.4.13"
+ aria-query: "npm:^5.3.1"
+ axobject-query: "npm:^4.1.0"
+ esm-env: "npm:^1.0.0"
+ esrap: "npm:^1.2.2"
+ is-reference: "npm:^3.0.2"
+ locate-character: "npm:^3.0.0"
+ magic-string: "npm:^0.30.11"
+ zimmerframe: "npm:^1.1.2"
+ checksum: 10c0/74a954cffe2a70259a1d1d2a834e9615d3f393429ac8cc1e15bfdc66b8bbe5dc449a8289370631b29023bca51aa451d1906f570b3761de4c235ea731913ee1b2
+ languageName: node
+ linkType: hard
+
"sveltedoc-parser@npm:^4.2.1":
version: 4.3.1
resolution: "sveltedoc-parser@npm:4.3.1"
@@ -28308,6 +28611,20 @@ __metadata:
languageName: node
linkType: hard
+"update-browserslist-db@npm:^1.1.0":
+ version: 1.1.0
+ resolution: "update-browserslist-db@npm:1.1.0"
+ dependencies:
+ escalade: "npm:^3.1.2"
+ picocolors: "npm:^1.0.1"
+ peerDependencies:
+ browserslist: ">= 4.21.0"
+ bin:
+ update-browserslist-db: cli.js
+ checksum: 10c0/a7452de47785842736fb71547651c5bbe5b4dc1e3722ccf48a704b7b34e4dcf633991eaa8e4a6a517ffb738b3252eede3773bef673ef9021baa26b056d63a5b9
+ languageName: node
+ linkType: hard
+
"update-browserslist-db@npm:^1.1.1":
version: 1.1.1
resolution: "update-browserslist-db@npm:1.1.1"
@@ -28829,6 +29146,22 @@ __metadata:
languageName: node
linkType: hard
+"vitest-axe@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "vitest-axe@npm:0.1.0"
+ dependencies:
+ aria-query: "npm:^5.0.0"
+ axe-core: "npm:^4.4.2"
+ chalk: "npm:^5.0.1"
+ dom-accessibility-api: "npm:^0.5.14"
+ lodash-es: "npm:^4.17.21"
+ redent: "npm:^3.0.0"
+ peerDependencies:
+ vitest: ">=0.16.0"
+ checksum: 10c0/ad523ad3115f66b1605c3c0ea6a9932867c4273f8ad73b717afc5fe496159b5e11d50a8babf05ce4990c612558ee24579cf14258304ce6b32a77d15be9e98aa6
+ languageName: node
+ linkType: hard
+
"vitest@npm:^2.1.3":
version: 2.1.3
resolution: "vitest@npm:2.1.3"
diff --git a/docs/_snippets/storybook-addon-a11y-component-config.md b/docs/_snippets/storybook-addon-a11y-component-config.md
index d0b5ab9fee65..5d84203b21c8 100644
--- a/docs/_snippets/storybook-addon-a11y-component-config.md
+++ b/docs/_snippets/storybook-addon-a11y-component-config.md
@@ -24,6 +24,10 @@ const meta: Meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -58,7 +62,11 @@ export default meta;
},
],
},
- options: {},
+ options: {}
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -90,6 +98,10 @@ export default {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -120,6 +132,10 @@ export default {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -153,6 +169,10 @@ export default {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -186,6 +206,10 @@ const meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -221,6 +245,10 @@ const meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -256,6 +284,10 @@ export default meta;
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -289,6 +321,10 @@ const meta: Meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -324,6 +360,10 @@ const meta: Meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -354,6 +394,10 @@ export default {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
@@ -384,6 +428,10 @@ const meta: Meta = {
],
},
options: {},
+ },
+ },
+ globals: {
+ a11y: {
manual: true,
},
},
diff --git a/docs/_snippets/storybook-addon-a11y-disable.md b/docs/_snippets/storybook-addon-a11y-disable.md
index 083c3d108cbb..998a1f91c0c2 100644
--- a/docs/_snippets/storybook-addon-a11y-disable.md
+++ b/docs/_snippets/storybook-addon-a11y-disable.md
@@ -11,10 +11,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disabled: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -28,10 +28,10 @@ export default {
};
export const NonA11yStory = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -50,10 +50,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -72,10 +72,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -94,10 +94,10 @@ export const NonA11yStory: Story = {
@@ -111,10 +111,10 @@ export default {
};
export const NonA11yStory = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -133,10 +133,10 @@ export const NonA11yStory = {
@@ -155,10 +155,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -177,10 +177,10 @@ export const NonA11yStory: Story = {
@@ -199,10 +199,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -216,10 +216,10 @@ export default {
};
export const NonA11yStory = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -238,10 +238,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -260,10 +260,10 @@ export default meta;
type Story = StoryObj;
export const NonA11yStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -275,10 +275,10 @@ export default {
};
export const ExampleStory = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
@@ -295,10 +295,10 @@ export default meta;
type Story = StoryObj;
export const ExampleStory: Story = {
- parameters: {
+ globals: {
a11y: {
- // This option disables all a11y checks on this story
- disable: true,
+ // This option disables all automatic a11y checks on this story
+ manual: true,
},
},
};
diff --git a/docs/_snippets/storybook-addon-a11y-test-override-warning-levels.md b/docs/_snippets/storybook-addon-a11y-test-override-warning-levels.md
new file mode 100644
index 000000000000..120a5ad6de8b
--- /dev/null
+++ b/docs/_snippets/storybook-addon-a11y-test-override-warning-levels.md
@@ -0,0 +1,32 @@
+```js filename=".storybook/preview.js" renderer="common" language="js"
+export default {
+ parameters: {
+ a11y: {
+ /*
+ * Configure the warning levels for a11y checks
+ * The available options are 'minor', 'moderate', 'serious', and 'critical'
+ */
+ warnings: ['minor', 'moderate'],
+ },
+ },
+};
+```
+
+```ts filename=".storybook/preview.ts" renderer="common" language="ts"
+// Replace your-framework with the framework you are using (e.g., react, vue3)
+import { Preview } from '@storybook/your-framework';
+
+const preview: Preview = {
+ parameters: {
+ a11y: {
+ /*
+ * Configure the warning levels for a11y checks
+ * The available options are 'minor', 'moderate', 'serious', and 'critical'
+ */
+ warnings: ['minor', 'moderate'],
+ },
+ },
+};
+
+export default preview;
+```
diff --git a/docs/_snippets/storybook-addon-a11y-test-setup.md b/docs/_snippets/storybook-addon-a11y-test-setup.md
new file mode 100644
index 000000000000..6419c6bf70aa
--- /dev/null
+++ b/docs/_snippets/storybook-addon-a11y-test-setup.md
@@ -0,0 +1,121 @@
+```ts filename=".storybook/vitest.setup.ts" renderer="react" language="ts"
+import { beforeAll } from 'vitest';
+
+import { setProjectAnnotations } from '@storybook/react';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
+
+```js filename=".storybook/vitest.setup.js" renderer="react" language="js"
+import { beforeAll } from 'vitest';
+
+import { setProjectAnnotations } from '@storybook/react';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
+
+```ts filename=".storybook/vitest.setup.ts" renderer="svelte" language="ts"
+import { beforeAll } from 'vitest';
+
+// Replace @storybook/svelte with @storybook/sveltekit if you are using SvelteKit
+import { setProjectAnnotations } from '@storybook/svelte';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
+
+```js filename=".storybook/vitest.setup.js" renderer="svelte" language="js"
+import { beforeAll } from 'vitest';
+
+// Replace @storybook/svelte with @storybook/sveltekit if you are using SvelteKit
+import { setProjectAnnotations } from '@storybook/svelte';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
+
+```ts filename=".storybook/vitest.setup.ts" renderer="vue" language="ts"
+import { beforeAll } from 'vitest';
+
+import { setProjectAnnotations } from '@storybook/vue3';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
+
+```js filename=".storybook/vitest.setup.js" renderer="vue" language="js"
+import { beforeAll } from 'vitest';
+
+import { setProjectAnnotations } from '@storybook/vue3';
+
+// Import the a11y addon annotations
+import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
+
+// Optionally import your own annotations
+import * as projectAnnotations from './preview';
+
+const project = setProjectAnnotations([
+ // Add the a11y addon annotations
+ a11yAddonAnnotations,
+ projectAnnotations,
+]);
+
+beforeAll(project.beforeAll);
+```
diff --git a/docs/_snippets/storybook-test-addon-disable-tests.md b/docs/_snippets/storybook-test-addon-disable-tests.md
new file mode 100644
index 000000000000..6f004039dc60
--- /dev/null
+++ b/docs/_snippets/storybook-test-addon-disable-tests.md
@@ -0,0 +1,392 @@
+```ts filename="Button.stories.ts|tsx" renderer="react" language="ts"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta: Meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```js filename="Button.stories.js|jsx" renderer="react" language="js"
+import { Button } from './Button';
+
+export default {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export const Accessible = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```ts filename="Button.stories.ts|tsx" renderer="react" language="ts-4-9"
+import type { Meta, StoryObj } from '@storybook/react';
+
+import { Button } from './Button';
+
+const meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="js" tabTitle="Svelte CSF"
+
+
+
+
+
+
+```
+
+```js filename="Button.stories.js" renderer="svelte" language="js" tabTitle="CSF"
+import Button from './Button.svelte';
+
+export default {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export const Accessible = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="ts-4-9" tabTitle="Svelte CSF"
+
+
+
+
+
+
+```
+
+```ts filename="Button.stories.ts" renderer="svelte" language="ts-4-9" tabTitle="CSF"
+import type { Meta, StoryObj } from '@storybook/svelte';
+
+import Button from './Button.svelte';
+
+const meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```svelte filename="Button.stories.svelte" renderer="svelte" language="ts" tabTitle="Svelte CSF"
+
+
+
+
+
+
+```
+
+```ts filename="Button.stories.ts" renderer="svelte" language="ts" tabTitle="CSF"
+import type { Meta, StoryObj } from '@storybook/svelte';
+
+import Button from './Button.svelte';
+
+const meta: Meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```js filename="Button.stories.js" renderer="vue" language="js"
+import Button from './Button.vue';
+
+export default {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export const Accessible = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```ts filename="Button.stories.ts" renderer="vue" language="ts-4-9"
+import type { Meta, StoryObj } from '@storybook/vue3';
+
+import Button from './Button.vue';
+
+const meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+} satisfies Meta;
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
+
+```ts filename="Button.stories.ts" renderer="vue" language="ts"
+import type { Meta, StoryObj } from '@storybook/vue3';
+
+import Button from './Button.vue';
+
+const meta: Meta = {
+ component: Button,
+ /*
+ * Enable accessibility checks for all stories in this component
+ * This is only necessary if you have set the `!a11ytest` tag in your preview file, otherwise `a11ytest` is enabled by default
+ */
+ tags: ['a11ytest'],
+};
+
+export default meta;
+type Story = StoryObj;
+
+export const Accessible: Story = {
+ args: {
+ primary: false,
+ label: 'Button',
+ },
+};
+
+export const Inaccessible: Story = {
+ // Turn off accessibility tests for this story using the tag's configuration option
+ tags: ['!a11ytest'],
+ args: {
+ ...Accessible.args,
+ backgroundColor: 'red',
+ },
+};
+```
diff --git a/docs/versions/next.json b/docs/versions/next.json
index 0fee1f4e6446..b8768a58da49 100644
--- a/docs/versions/next.json
+++ b/docs/versions/next.json
@@ -1 +1 @@
-{"version":"8.5.0-alpha.18","info":{"plain":"- Addon Test: Clarify message when `vitest` detects missing deps - [#29763](https://github.com/storybookjs/storybook/pull/29763), thanks @ndelangen!\n- Addon Test: Refactor test addon to include stories automatically - [#29367](https://github.com/storybookjs/storybook/pull/29367), thanks @yannbf!\n- Addon Test: Replace `glob` with `tinyglobby` - [#29817](https://github.com/storybookjs/storybook/pull/29817), thanks @ghengeveld!\n- Addon Test: Support Storybook environment variables in Vitest - [#29792](https://github.com/storybookjs/storybook/pull/29792), thanks @ghengeveld!\n- Composition: Hide contextMenu on composed storybooks - [#29803](https://github.com/storybookjs/storybook/pull/29803), thanks @ndelangen!\n- Vue: Properly resolve Vite plugin - [#29795](https://github.com/storybookjs/storybook/pull/29795), thanks @tobiasdiez!"}}
+{"version":"8.5.0-alpha.19","info":{"plain":"- Addon A11y: Create a11y test provider and revamp a11y addon - [#29643](https://github.com/storybookjs/storybook/pull/29643), thanks @valentinpalkovic!\n- Addon Test: Fix indexing behavior - [#29836](https://github.com/storybookjs/storybook/pull/29836), thanks @yannbf!\n- Addon Test: Fix run request while booting or restarting Vitest - [#29829](https://github.com/storybookjs/storybook/pull/29829), thanks @ghengeveld!\n- Addon Test: Serve `staticDirs` with Vitest - [#29811](https://github.com/storybookjs/storybook/pull/29811), thanks @ghengeveld!\n- RNW-Vite: Add tsconfig path aliases support - [#29953](https://github.com/storybookjs/storybook/pull/29953), thanks @shilman!\n- RNW-Vite: Fix flow plugin including too many things - [#29952](https://github.com/storybookjs/storybook/pull/29952), thanks @dannyhw!"}}
diff --git a/docs/writing-tests/accessibility-testing.mdx b/docs/writing-tests/accessibility-testing.mdx
index 9d04907b17b5..7072edb154ad 100644
--- a/docs/writing-tests/accessibility-testing.mdx
+++ b/docs/writing-tests/accessibility-testing.mdx
@@ -75,7 +75,7 @@ If you need to dismiss an accessibility rule or modify its settings across all s
- You can also customize your own set of rules for all stories of a component. Update your story's default export and add a parameter with the required configuration:
+ You can also customize your own set of rules for all stories of a component. Update your story's default export and add parameters and globals with the required configuration:
@@ -95,17 +95,17 @@ Customize the a11y ruleset at the story level by updating your story to include
{/* prettier-ignore-end */}
-#### How to disable a11y tests
+#### Turn off automated a11y tests
- If you are using Svelte CSF, you can turn off accessibility testing for stories or components by adding a parameter to your story or adjusting the defineMeta function with the required configuration. With a regular CSF story, you can add the following to your story's export or component's default export:
+ If you are using Svelte CSF, you can turn off automated accessibility testing for stories or components by adding globals to your story or adjusting the defineMeta function with the required configuration. With a regular CSF story, you can add the following to your story's export or component's default export:
- Disable accessibility testing for stories or components by adding the following parameter to your story’s export or component’s default export respectively:
+ Disable automated accessibility testing for stories or components by adding the following globals to your story’s export or component’s default export respectively:
@@ -116,6 +116,50 @@ Customize the a11y ruleset at the story level by updating your story to include
{/* prettier-ignore-end */}
+
+
+## Test addon integration
+
+The accessibility addon provides seamless integration with Storybook's [test addon](./test-addon.mdx), enabling you to run automated accessibility checks for all your tests in the background while you run component tests. If there are any violations, the test will fail, and you will see the results in the sidebar without any additional setup.
+
+{/* TODO: add asset of the changed UI here */}
+
+### Manual upgrade
+
+If you enabled the addon and you're manually upgrading to Storybook 8.5 or later, you'll need to adjust your existing configuration (i.e., `.storybook/vitest.config.ts`) to enable the integration as follows:
+
+
+
+### Override accessibility violation levels
+
+By default, when the accessibility addon runs with the test addon enabled, it interprets all violations as errors. This means that if a story has a minor accessibility violation, the test will fail. However, you can override this behavior by setting the `warnings` parameter in the `a11y` configuration object to define an array of impact levels that should be considered warnings.
+
+{/* prettier-ignore-start */}
+
+
+
+{/* prettier-ignore-end */}
+
+In the example above, we configured all the `minor` or `moderate` accessibility violations to be considered warnings. All other levels (i.e., `serious` or `critical`) will continue to be considered errors, fail the test, and report the results accordingly in the Storybook UI or Vitest.
+
+### Configure accessibility tests with the test addon
+
+If you want to run accessibility tests only for a subset of your stories, you can use the [tags](../writing-stories/tags.mdx) mechanism to filter the tests you want to run with the test addon. For example, to turn off accessibility tests for a specific story, add the `!a11ytest` tag to the story's meta or directly to the story's `tags` configuration option. For example:
+
+{/* prettier-ignore-start */}
+
+
+
+{/* prettier-ignore-end */}
+
+
+
+ Tags can be applied at the project, component (meta), or story levels. Read our [documentation](../writing-stories/tags.mdx) for more information on configuring tags.
+
+
+
+
+
## Automate accessibility tests with test runner
The most accurate way to check accessibility is manually on real devices. However, you can use automated tools to catch common accessibility issues. For example, [Axe](https://www.deque.com/axe/), on average, catches upwards to [57% of WCAG issues](https://www.deque.com/blog/automated-testing-study-identifies-57-percent-of-digital-accessibility-issues/) automatically.
@@ -164,7 +208,7 @@ The test runner provides [helper methods](./test-runner.mdx#helpers), allowing a
### Disable a11y tests with the test runner
-Additionally, if you have already [disabled accessibility](#how-to-disable-a11y-tests) tests for any particular story, you can also configure the test runner to avoid testing it as well. For example:
+Additionally, if you have already [disabled accessibility](#turn-off-automated-a11y-tests) tests for any particular story, you can also configure the test runner to avoid testing it as well. For example:
{/* prettier-ignore-start */}
@@ -178,6 +222,16 @@ Additionally, if you have already [disabled accessibility](#how-to-disable-a11y-
Browser-based accessibility tests, like those found in Storybook, evaluate the rendered DOM because that gives you the highest accuracy. Auditing code that hasn't been compiled yet is one step removed from the real thing, so you won't catch everything the user might experience.
+
+
+## Troubleshooting
+
+### Why are my tests failing in different environments?
+
+If you enabled the experimental test addon (i.e.,`@storybook/experimental-addon-test`), your tests run in Vitest using your project's configuration with Playwright's Chromium browser. This can lead to inconsistent test results reported in the Storybook UI or CLI. The inconsistency can be due to `axe-core` reporting different results in different environments, such as browser versions or configurations. If you encounter this issue, we recommend reaching out using the default communication channels (e.g., [GitHub discussions](https://github.com/storybookjs/storybook/discussions/new?category=help), [Github issues](https://github.com/storybookjs/storybook/issues/new?template=bug_report.yml)).
+
+
+
**Learn about other UI tests**
* [Component tests](./component-testing.mdx) for user behavior simulation
diff --git a/scripts/tasks/sandbox-parts.ts b/scripts/tasks/sandbox-parts.ts
index 920b31857a8b..ea99a566dbef 100644
--- a/scripts/tasks/sandbox-parts.ts
+++ b/scripts/tasks/sandbox-parts.ts
@@ -439,6 +439,7 @@ export async function setupVitest(details: TemplateDetails, options: PassedOptio
dedent`import { beforeAll } from 'vitest'
import { setProjectAnnotations } from '${storybookPackage}'
import * as rendererDocsAnnotations from '${template.expected.renderer}/dist/entry-preview-docs.mjs'
+ import * as addonA11yAnnotations from '@storybook/addon-a11y/preview'
import * as addonActionsAnnotations from '@storybook/addon-actions/preview'
import * as addonTestAnnotations from '@storybook/experimental-addon-test/preview'
import '../src/stories/components'
@@ -448,13 +449,14 @@ export async function setupVitest(details: TemplateDetails, options: PassedOptio
${isVue ? 'import * as vueAnnotations from "../src/stories/renderers/vue3/preview.js"' : ''}
const annotations = setProjectAnnotations([
+ ${isVue ? 'vueAnnotations,' : ''}
rendererDocsAnnotations,
- projectAnnotations,
coreAnnotations,
toolbarAnnotations,
addonActionsAnnotations,
addonTestAnnotations,
- ${isVue ? 'vueAnnotations,' : ''}
+ addonA11yAnnotations,
+ projectAnnotations,
])
beforeAll(annotations.beforeAll)`
@@ -808,6 +810,11 @@ export const extendPreview: Task['run'] = async ({ template, sandboxDir }) => {
if (template.expected.builder.includes('vite')) {
previewConfig.setFieldValue(['tags'], ['vitest']);
+ // TODO: Remove this once the starter components + test stories have proper accessibility
+ previewConfig.setFieldValue(
+ ['parameters', 'a11y', 'warnings'],
+ ['minor', 'moderate', 'serious', 'critical']
+ );
}
await writeConfig(previewConfig);
diff --git a/scripts/tasks/sandbox.ts b/scripts/tasks/sandbox.ts
index a6064b2d58e7..80b0a2bf1045 100644
--- a/scripts/tasks/sandbox.ts
+++ b/scripts/tasks/sandbox.ts
@@ -74,7 +74,11 @@ export const sandbox: Task = {
// extraDeps.push('@testing-library/angular', '@analogjs/vitest-angular');
// }
- options.addon = [...options.addon, '@storybook/experimental-addon-test'];
+ options.addon = [
+ ...options.addon,
+ '@storybook/experimental-addon-test',
+ '@storybook/addon-a11y',
+ ];
}
let startTime = now();
diff --git a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/main.ts b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/main.ts
index 9a2664c6e951..198deee16402 100644
--- a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/main.ts
+++ b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/main.ts
@@ -5,6 +5,7 @@ const config: StorybookConfig = {
addons: [
"@storybook/addon-controls",
"@storybook/experimental-addon-test",
+ //"@storybook/addon-a11y",
],
framework: {
name: "@storybook/react-vite",
diff --git a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/vitest.setup.ts b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/vitest.setup.ts
index e384ed2a5b36..d89d36e9a642 100644
--- a/test-storybooks/portable-stories-kitchen-sink/react/.storybook/vitest.setup.ts
+++ b/test-storybooks/portable-stories-kitchen-sink/react/.storybook/vitest.setup.ts
@@ -1,8 +1,10 @@
import { beforeAll } from 'vitest'
import { setProjectAnnotations } from '@storybook/react'
+import * as addonA11yAnnotations from '@storybook/addon-a11y/preview'
import * as projectAnnotations from './preview'
const annotations = setProjectAnnotations([
+ addonA11yAnnotations,
projectAnnotations,
])
diff --git a/test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/component-testing.spec.ts b/test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/component-testing.spec.ts
index 68276fdb1a22..6b0879fca5f9 100644
--- a/test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/component-testing.spec.ts
+++ b/test-storybooks/portable-stories-kitchen-sink/react/e2e-tests/component-testing.spec.ts
@@ -73,7 +73,7 @@ test.describe("component testing", () => {
await expect(testingModuleDescription).toContainText('Not run');
- const runTestsButton = await page.getByLabel('Start component tests')
+ const runTestsButton = await page.getByLabel('Start Component tests')
await runTestsButton.click();
await expect(testingModuleDescription).toContainText('Testing', { timeout: 60000 });
@@ -120,7 +120,7 @@ test.describe("component testing", () => {
const sbPage = new SbPage(page, expect);
await sbPage.navigateToStory("addons/test", "Expected Failure");
- const expandButton = await page.getByLabel('Expand testing module')
+ const expandButton = page.getByLabel('Expand testing module')
await expandButton.click();
// For whatever reason, sometimes it takes longer for the story to load
@@ -135,7 +135,7 @@ test.describe("component testing", () => {
await expect(testingModuleDescription).toContainText('Not run');
- const runTestsButton = await page.getByLabel('Start component tests')
+ const runTestsButton = await page.getByLabel('Start Component Tests')
const watchModeButton = await page.getByLabel('Enable watch mode for Component tests')
await expect(runTestsButton).toBeEnabled();
await expect(watchModeButton).toBeEnabled();
diff --git a/test-storybooks/portable-stories-kitchen-sink/react/package.json b/test-storybooks/portable-stories-kitchen-sink/react/package.json
index 5af90b56b2e3..8f392f7f1add 100644
--- a/test-storybooks/portable-stories-kitchen-sink/react/package.json
+++ b/test-storybooks/portable-stories-kitchen-sink/react/package.json
@@ -90,6 +90,7 @@
"devDependencies": {
"@playwright/experimental-ct-react": "1.48.1",
"@playwright/test": "1.48.1",
+ "@storybook/addon-a11y": "^8.0.0",
"@storybook/addon-actions": "^8.0.0",
"@storybook/addon-controls": "^8.0.0",
"@storybook/addon-essentials": "^8.0.0",
diff --git a/test-storybooks/portable-stories-kitchen-sink/react/yarn.lock b/test-storybooks/portable-stories-kitchen-sink/react/yarn.lock
index 2041ffe4ec1a..b6be56469636 100644
--- a/test-storybooks/portable-stories-kitchen-sink/react/yarn.lock
+++ b/test-storybooks/portable-stories-kitchen-sink/react/yarn.lock
@@ -1239,21 +1239,19 @@ __metadata:
languageName: node
linkType: hard
-"@joshwooding/vite-plugin-react-docgen-typescript@npm:0.3.0":
- version: 0.3.0
- resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.3.0"
+"@joshwooding/vite-plugin-react-docgen-typescript@npm:0.4.2":
+ version: 0.4.2
+ resolution: "@joshwooding/vite-plugin-react-docgen-typescript@npm:0.4.2"
dependencies:
- glob: "npm:^7.2.0"
- glob-promise: "npm:^4.2.0"
magic-string: "npm:^0.27.0"
react-docgen-typescript: "npm:^2.2.2"
peerDependencies:
typescript: ">= 4.3.x"
- vite: ^3.0.0 || ^4.0.0 || ^5.0.0
+ vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0
peerDependenciesMeta:
typescript:
optional: true
- checksum: 10/9237499394b1f5f1320c9a489dbf5db2ba4b1d68081bf767a08895b70d0d0830adb9f0f1e2c5c94202e5bee63fe031ea2b91870a6bc806ed5e370be6b06df2e8
+ checksum: 10/0878171c598ee85997a2b9ea452715ea3df4c0faa3c646ffc0be62a772c3f4919986a9045864fe7cf2208b3f577bbe1e029f8ea3f3bf83f509be8d7a064f0396
languageName: node
linkType: hard
@@ -1599,6 +1597,19 @@ __metadata:
languageName: node
linkType: hard
+"@storybook/addon-a11y@portal:../../../code/addons/a11y::locator=portable-stories-react%40workspace%3A.":
+ version: 0.0.0-use.local
+ resolution: "@storybook/addon-a11y@portal:../../../code/addons/a11y::locator=portable-stories-react%40workspace%3A."
+ dependencies:
+ "@storybook/addon-highlight": "workspace:*"
+ "@storybook/test": "workspace:*"
+ axe-core: "npm:^4.2.0"
+ vitest-axe: "npm:^0.1.0"
+ peerDependencies:
+ storybook: "workspace:^"
+ languageName: node
+ linkType: soft
+
"@storybook/addon-actions@portal:../../../code/addons/actions::locator=portable-stories-react%40workspace%3A.":
version: 0.0.0-use.local
resolution: "@storybook/addon-actions@portal:../../../code/addons/actions::locator=portable-stories-react%40workspace%3A."
@@ -1740,7 +1751,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/blocks@portal:../../../code/lib/blocks::locator=portable-stories-react%40workspace%3A."
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/icons": "npm:^1.2.12"
ts-dedent: "npm:^2.0.0"
peerDependencies:
@@ -1764,16 +1775,16 @@ __metadata:
ts-dedent: "npm:^2.0.0"
peerDependencies:
storybook: "workspace:^"
- vite: ^4.0.0 || ^5.0.0
+ vite: ^4.0.0 || ^5.0.0 || ^6.0.0
languageName: node
linkType: soft
"@storybook/components@file:../../../code/deprecated/components::locator=portable-stories-react%40workspace%3A.":
- version: 8.5.0-alpha.4
- resolution: "@storybook/components@file:../../../code/deprecated/components#../../../code/deprecated/components::hash=60237a&locator=portable-stories-react%40workspace%3A."
+ version: 8.5.0-alpha.18
+ resolution: "@storybook/components@file:../../../code/deprecated/components#../../../code/deprecated/components::hash=aad2fe&locator=portable-stories-react%40workspace%3A."
peerDependencies:
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
- checksum: 10/0366ac53c8eed65b69aaa174337d27ec2283c446b328811f92ffc9de0a219860afd2e3bdc5f11c30485c43c21d246ff036bca74429ba307dc557917d14a9beba
+ checksum: 10/44d4a8a54fd32d94b03dc9f29e2d68ca3c37156b56055b94493f5f626786a02349c195859c48b4f8fa25e209ce12f385305d601135f7e63bdc4541fa0645cae5
languageName: node
linkType: hard
@@ -1781,7 +1792,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/core@portal:../../../code/core::locator=portable-stories-react%40workspace%3A."
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
better-opn: "npm:^3.0.2"
browser-assert: "npm:^1.2.1"
esbuild: "npm:^0.18.0 || ^0.19.0 || ^0.20.0 || ^0.21.0 || ^0.22.0 || ^0.23.0 || ^0.24.0"
@@ -1810,6 +1821,15 @@ __metadata:
languageName: node
linkType: soft
+"@storybook/csf@npm:0.1.12":
+ version: 0.1.12
+ resolution: "@storybook/csf@npm:0.1.12"
+ dependencies:
+ type-fest: "npm:^2.19.0"
+ checksum: 10/f661709de5bd68bfd4ced67df31ef26341168d6679bc13564cb024cfdbc8fdfa94d384267c20b3c858a3058b1ee8dbd71cea169245fcf7b28298890d6c3e1da4
+ languageName: node
+ linkType: hard
+
"@storybook/csf@npm:^0.0.1":
version: 0.0.1
resolution: "@storybook/csf@npm:0.0.1"
@@ -1819,20 +1839,11 @@ __metadata:
languageName: node
linkType: hard
-"@storybook/csf@npm:^0.1.11":
- version: 0.1.11
- resolution: "@storybook/csf@npm:0.1.11"
- dependencies:
- type-fest: "npm:^2.19.0"
- checksum: 10/f6eeefe3b92ab206676587da9e22a775da026c055999681580d2ca23c98185736f965adc79039a0ae97ea625f0fbc7915cd4559e5db24229a4805784d0b78584
- languageName: node
- linkType: hard
-
"@storybook/experimental-addon-test@file:../../../code/addons/test::locator=portable-stories-react%40workspace%3A.":
- version: 8.5.0-alpha.4
- resolution: "@storybook/experimental-addon-test@file:../../../code/addons/test#../../../code/addons/test::hash=6bed1d&locator=portable-stories-react%40workspace%3A."
+ version: 8.5.0-alpha.18
+ resolution: "@storybook/experimental-addon-test@file:../../../code/addons/test#../../../code/addons/test::hash=f1c849&locator=portable-stories-react%40workspace%3A."
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
"@storybook/icons": "npm:^1.2.12"
"@storybook/instrumenter": "workspace:*"
@@ -1853,7 +1864,7 @@ __metadata:
optional: true
vitest:
optional: true
- checksum: 10/9d842f824d9891bd19e508d654ce7f9f7cf8c73090588b84f29b2649e68338d13d7cd85a6d4bd92fe6beef276eb12783445bed4a4249563a5986f6f537ccc6d8
+ checksum: 10/29f2db97577ff0a3a79ae37a8b0eaebd86d7eca43c3ad364abbb5f4a63e5f9d12dab2927723802752a2c2e2d36561ac89db32a7fd770e31c5b6e573e265bdd27
languageName: node
linkType: hard
@@ -1886,20 +1897,20 @@ __metadata:
linkType: soft
"@storybook/manager-api@file:../../../code/deprecated/manager-api::locator=portable-stories-react%40workspace%3A.":
- version: 8.5.0-alpha.4
- resolution: "@storybook/manager-api@file:../../../code/deprecated/manager-api#../../../code/deprecated/manager-api::hash=8c9581&locator=portable-stories-react%40workspace%3A."
+ version: 8.5.0-alpha.18
+ resolution: "@storybook/manager-api@file:../../../code/deprecated/manager-api#../../../code/deprecated/manager-api::hash=c1892e&locator=portable-stories-react%40workspace%3A."
peerDependencies:
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
- checksum: 10/20f439e660e49c2bba2ce4fc73ddb9306c04cea9e6eaa0ddc23fc2047e135b7df4cc0b742dc662cee71013051b0d7e9e9e7a4f28323c1734fc6ad024ac47b9db
+ checksum: 10/405745f48728bfa4d8340fe2403bca0d60f803ed346c12d20a63ab9472ba1d8d1021aa12ee0fd36a6b41aec42d8c2a657acffeb9c8663aa32edcda490882e7f5
languageName: node
linkType: hard
"@storybook/preview-api@file:../../../code/deprecated/preview-api::locator=portable-stories-react%40workspace%3A.":
- version: 8.5.0-alpha.4
- resolution: "@storybook/preview-api@file:../../../code/deprecated/preview-api#../../../code/deprecated/preview-api::hash=a7858a&locator=portable-stories-react%40workspace%3A."
+ version: 8.5.0-alpha.18
+ resolution: "@storybook/preview-api@file:../../../code/deprecated/preview-api#../../../code/deprecated/preview-api::hash=0085a8&locator=portable-stories-react%40workspace%3A."
peerDependencies:
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
- checksum: 10/29559a5fd2698758e0bcf5442421fb583da5d95344f9740dcdc3615b3bec3dfb105f134fba08423a1fd1a68fbfa2615c91408271c4ef8926d43c0b5c6f8d0bb8
+ checksum: 10/29c5f7134b4300bac03c42f57c3138e24315516b23515893cfb4a144786327fb6e0a90d5470d951eb22e055466769fc9ad4577658afc7da43b60870c0d06e767
languageName: node
linkType: hard
@@ -1917,7 +1928,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/react-vite@portal:../../../code/frameworks/react-vite::locator=portable-stories-react%40workspace%3A."
dependencies:
- "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.3.0"
+ "@joshwooding/vite-plugin-react-docgen-typescript": "npm:0.4.2"
"@rollup/pluginutils": "npm:^5.0.2"
"@storybook/builder-vite": "workspace:*"
"@storybook/react": "workspace:*"
@@ -1927,10 +1938,14 @@ __metadata:
resolve: "npm:^1.22.8"
tsconfig-paths: "npm:^4.2.0"
peerDependencies:
+ "@storybook/test": "workspace:*"
react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0-beta
storybook: "workspace:^"
- vite: ^4.0.0 || ^5.0.0
+ vite: ^4.0.0 || ^5.0.0 || ^6.0.0
+ peerDependenciesMeta:
+ "@storybook/test":
+ optional: true
languageName: node
linkType: soft
@@ -1962,7 +1977,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@storybook/test@portal:../../../code/lib/test::locator=portable-stories-react%40workspace%3A."
dependencies:
- "@storybook/csf": "npm:^0.1.11"
+ "@storybook/csf": "npm:0.1.12"
"@storybook/global": "npm:^5.0.0"
"@storybook/instrumenter": "workspace:*"
"@testing-library/dom": "npm:10.4.0"
@@ -1976,11 +1991,11 @@ __metadata:
linkType: soft
"@storybook/theming@file:../../../code/deprecated/theming::locator=portable-stories-react%40workspace%3A.":
- version: 8.5.0-alpha.4
- resolution: "@storybook/theming@file:../../../code/deprecated/theming#../../../code/deprecated/theming::hash=74a1c8&locator=portable-stories-react%40workspace%3A."
+ version: 8.5.0-alpha.18
+ resolution: "@storybook/theming@file:../../../code/deprecated/theming#../../../code/deprecated/theming::hash=dd5360&locator=portable-stories-react%40workspace%3A."
peerDependencies:
storybook: ^8.2.0 || ^8.3.0-0 || ^8.4.0-0 || ^8.5.0-0 || ^8.6.0-0
- checksum: 10/387dd03f4a10a4a1f6381a9e150a3c4a96a5ce3f6aec4557a954fa3c629630e667a5e60003fed6a5ed31a7844dcd3507bcf996614e1ddb0cda8ad74b6922f3b4
+ checksum: 10/8f8ecbd709ff4a8e0bafa19642497aad0d6ee40f2e613793a4248cb3825765783dd40eb57d180cb6cc4ad1f8acbd4e4a1a1b3448245b89e28581e25289c88c86
languageName: node
linkType: hard
@@ -2275,16 +2290,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/glob@npm:^7.1.3":
- version: 7.2.0
- resolution: "@types/glob@npm:7.2.0"
- dependencies:
- "@types/minimatch": "npm:*"
- "@types/node": "npm:*"
- checksum: 10/6ae717fedfdfdad25f3d5a568323926c64f52ef35897bcac8aca8e19bc50c0bd84630bbd063e5d52078b2137d8e7d3c26eabebd1a2f03ff350fff8a91e79fc19
- languageName: node
- linkType: hard
-
"@types/graceful-fs@npm:^4.1.3":
version: 4.1.9
resolution: "@types/graceful-fs@npm:4.1.9"
@@ -2351,13 +2356,6 @@ __metadata:
languageName: node
linkType: hard
-"@types/minimatch@npm:*":
- version: 5.1.2
- resolution: "@types/minimatch@npm:5.1.2"
- checksum: 10/94db5060d20df2b80d77b74dd384df3115f01889b5b6c40fa2dfa27cfc03a68fb0ff7c1f2a0366070263eb2e9d6bfd8c87111d4bc3ae93c3f291297c1bf56c85
- languageName: node
- linkType: hard
-
"@types/mute-stream@npm:^0.0.4":
version: 0.0.4
resolution: "@types/mute-stream@npm:0.0.4"
@@ -3161,6 +3159,13 @@ __metadata:
languageName: node
linkType: hard
+"axe-core@npm:^4.2.0, axe-core@npm:^4.4.2":
+ version: 4.10.2
+ resolution: "axe-core@npm:4.10.2"
+ checksum: 10/a69423b2ff16c15922c4ea7cf9cc5112728a2817bbe0f2cc212248d648885ffd1ba554e3a341dfc289cd9e67fc0d06f333b5c6837c5c38ca6652507381216fc1
+ languageName: node
+ linkType: hard
+
"babel-jest@npm:^29.7.0":
version: 29.7.0
resolution: "babel-jest@npm:29.7.0"
@@ -3494,6 +3499,13 @@ __metadata:
languageName: node
linkType: hard
+"chalk@npm:^5.0.1":
+ version: 5.3.0
+ resolution: "chalk@npm:5.3.0"
+ checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea
+ languageName: node
+ linkType: hard
+
"char-regex@npm:^1.0.2":
version: 1.0.2
resolution: "char-regex@npm:1.0.2"
@@ -4003,7 +4015,7 @@ __metadata:
languageName: node
linkType: hard
-"dom-accessibility-api@npm:^0.5.9":
+"dom-accessibility-api@npm:^0.5.14, dom-accessibility-api@npm:^0.5.9":
version: 0.5.16
resolution: "dom-accessibility-api@npm:0.5.16"
checksum: 10/377b4a7f9eae0a5d72e1068c369c99e0e4ca17fdfd5219f3abd32a73a590749a267475a59d7b03a891f9b673c27429133a818c44b2e47e32fec024b34274e2ca
@@ -5018,17 +5030,6 @@ __metadata:
languageName: node
linkType: hard
-"glob-promise@npm:^4.2.0":
- version: 4.2.2
- resolution: "glob-promise@npm:4.2.2"
- dependencies:
- "@types/glob": "npm:^7.1.3"
- peerDependencies:
- glob: ^7.1.6
- checksum: 10/c1a3d95f7c8393e4151d4899ec4e42bb2e8237160f840ad1eccbe9247407da8b6c13e28f463022e011708bc40862db87b9b77236d35afa3feb8aa86d518f2dfe
- languageName: node
- linkType: hard
-
"glob@npm:^10.2.2, glob@npm:^10.3.10":
version: 10.4.5
resolution: "glob@npm:10.4.5"
@@ -5045,7 +5046,7 @@ __metadata:
languageName: node
linkType: hard
-"glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.2.0":
+"glob@npm:^7.1.3, glob@npm:^7.1.4":
version: 7.2.3
resolution: "glob@npm:7.2.3"
dependencies:
@@ -6531,6 +6532,13 @@ __metadata:
languageName: node
linkType: hard
+"lodash-es@npm:^4.17.21":
+ version: 4.17.21
+ resolution: "lodash-es@npm:4.17.21"
+ checksum: 10/03f39878ea1e42b3199bd3f478150ab723f93cc8730ad86fec1f2804f4a07c6e30deaac73cad53a88e9c3db33348bb8ceeb274552390e7a75d7849021c02df43
+ languageName: node
+ linkType: hard
+
"lodash.merge@npm:^4.6.2":
version: 4.6.2
resolution: "lodash.merge@npm:4.6.2"
@@ -7352,6 +7360,7 @@ __metadata:
dependencies:
"@playwright/experimental-ct-react": "npm:1.48.1"
"@playwright/test": "npm:1.48.1"
+ "@storybook/addon-a11y": "npm:^8.0.0"
"@storybook/addon-actions": "npm:^8.0.0"
"@storybook/addon-controls": "npm:^8.0.0"
"@storybook/addon-essentials": "npm:^8.0.0"
@@ -8807,6 +8816,22 @@ __metadata:
languageName: node
linkType: hard
+"vitest-axe@npm:^0.1.0":
+ version: 0.1.0
+ resolution: "vitest-axe@npm:0.1.0"
+ dependencies:
+ aria-query: "npm:^5.0.0"
+ axe-core: "npm:^4.4.2"
+ chalk: "npm:^5.0.1"
+ dom-accessibility-api: "npm:^0.5.14"
+ lodash-es: "npm:^4.17.21"
+ redent: "npm:^3.0.0"
+ peerDependencies:
+ vitest: ">=0.16.0"
+ checksum: 10/2304b352ce001b86f57ca23e2e47e708a36a41783ebf130a84c86b2d75fe7161888ae78fa9de69ced3eb0865bfe0ce076e2c86b2161f7ffc1afaa76fcd11942e
+ languageName: node
+ linkType: hard
+
"vitest@npm:^2.1.3":
version: 2.1.3
resolution: "vitest@npm:2.1.3"