-
-
Notifications
You must be signed in to change notification settings - Fork 9.7k
Open
Description
Describe the bug
When a user attempted to migrate from CSF to CSF Next by following the documentation, and attempting to export the fn
function from storybook/test
to use it in various stories, they will run cryptic errors in the Storybook UI that do not provide much context about the root cause of the issue, nor how to resolve it. This is a pattern that users may want to use to avoid duplicating the same action definitions across multiple stories/tests and instead have a single source of truth for them to use throughout their projects.
This can be observed in the following screenshot:

Steps to Reproduce
Reproduction link
N/A
Reproduction steps
- Create a small Storybook project using the latest Storybook stable version (e.g., 9.1.6)
- Create a component with the following code:
// src/components/Task.tsx
import type { TaskData } from "../types";
type TaskProps = {
/** Composition of the task */
task: TaskData;
/** Event to change the task to archived */
onArchiveTask: (id: string) => void;
/** Event to change the task to pinned */
onPinTask: (id: string) => void;
};
export default function Task({
task: { id, title, state },
onArchiveTask,
onPinTask,
}: TaskProps) {
return (
<div className={`list-item ${state}`}>
<label
htmlFor={`archiveTask-${id}`}
aria-label={`archiveTask-${id}`}
className="checkbox"
>
<input
type="checkbox"
disabled={true}
name="checked"
id={`custom-archiveTask-${id}`}
aria-label={`custom-archiveTask-${id}`}
checked={state === "TASK_ARCHIVED"}
/>
<span
className="checkbox-custom"
onClick={() => onArchiveTask(id)}
aria-label={`custom-archiveTask-checkbox-${id}`}
/>
</label>
<label htmlFor={`title-${id}`} aria-label={title} className="title">
<input
type="text"
value={title}
readOnly={true}
name="title"
id={`title-${id}`}
placeholder="Input title"
/>
</label>
{state !== "TASK_ARCHIVED" && (
<button
className="pin-button"
onClick={() => onPinTask(id)}
id={`pinTask-${id}`}
aria-label={`pinTask-${id}`}
key={`pinTask-${id}`}
>
<span className={`icon-star`} />
</button>
)}
</div>
);
}
- Create the following story that exports the
fn
function fromstorybook/test
:
// src/components/Task.stories.tsx
import type { Meta, StoryObj } from "@storybook/react-vite";
import { fn } from "storybook/test";
import Task from "./Task";
export const ActionsData = {
onArchiveTask: fn(),
onPinTask: fn(),
};
const meta = {
component: Task,
title: "Task",
tags: ["autodocs"],
//👇 Our exports that end in "Data" are not stories.
excludeStories: /.*Data$/,
args: {
...ActionsData,
},
} satisfies Meta<typeof Task>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {
args: {
task: {
id: "1",
title: "Test Task",
state: "TASK_INBOX",
},
},
};
export const Pinned: Story = {
args: {
task: {
...Default.args.task,
state: "TASK_PINNED",
},
},
};
export const Archived: Story = {
args: {
task: {
...Default.args.task,
state: "TASK_ARCHIVED",
},
},
};
- Upgrade to the latest beta (i.e., 10.0.0-beta.8)
- Follow the migration steps from CSF to CSF Next as outlined in the documentation and migrate the story to CSF Next using the command:
npx storybook automigrate csf-factories
to convert the story to CSF Next format using subpath imports that yield the following code:
// src/components/Task.stories.tsx
import preview from "#.storybook/preview";
import { fn, expect } from "storybook/test";
import Task from "./Task";
export const ActionsData = {
onArchiveTask: fn(),
onPinTask: fn(),
};
const meta = preview.meta({
component: Task,
title: "Task",
tags: ["autodocs"],
//👇 Our exports that end in "Data" are not stories.
excludeStories: /.*Data$/,
args: {
...ActionsData,
},
});
export const Default = meta.story({
args: {
task: {
id: "1",
title: "Test Task",
state: "TASK_INBOX",
},
},
});
export const Pinned = meta.story({
args: {
task: {
...Default.input.args.task,
state: "TASK_PINNED",
},
},
});
export const Archived = meta.story({
args: {
task: {
...Default.input.args.task,
state: "TASK_ARCHIVED",
},
},
});
System
Storybook Environment Info:
System:
OS: macOS 15.0.1
CPU: (8) arm64 Apple M3
Shell: 5.9 - /bin/zsh
Binaries:
Node: 20.19.2 - ~/.nvm/versions/node/v20.19.2/bin/node
Yarn: 4.9.2 - /usr/local/bin/yarn <----- active
npm: 10.8.2 - ~/.nvm/versions/node/v20.19.2/bin/npm
Browsers:
Chrome: 140.0.7339.214
Edge: 140.0.3485.94
Safari: 18.0.1
npmPackages:
@storybook/addon-docs: ^10.0.0-beta.8 => 10.0.0-beta.8
@storybook/addon-vitest: ^10.0.0-beta.8 => 10.0.0-beta.8
@storybook/react-vite: ^10.0.0-beta.8 => 10.0.0-beta.8
eslint-plugin-storybook: ^10.0.0-beta.8 => 10.0.0-beta.8
msw-storybook-addon: ^2.0.5 => 2.0.5
storybook: ^10.0.0-beta.8 => 10.0.0-beta.8
Additional context
No response
dosubot
Metadata
Metadata
Assignees
Type
Projects
Status
No status