Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions docs/_snippets/main-config-features-experimental-test-syntax.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
```ts filename=".storybook/main.js|ts (CSF Next 🧪)" renderer="react" language="ts"
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, nextjs-vite)
import { defineMain } from '@storybook/your-framework/node';

export default defineMain({
framework: '@storybook/your-framework',
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
features: {
experimentalTestSyntax: true,
},
});
```
21 changes: 21 additions & 0 deletions docs/api/csf/csf-next.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,27 @@ export const PrimaryDisabled = Primary.extend({
});
```

#### `<Story>.test`

(⚠️ **Experimental**)

A more ergonomic way to define [tests for your stories](../../writing-tests/index.mdx). While this API is still experimental, it is [documented in the RFC to gather feedback](https://github.com/storybookjs/storybook/discussions/30119) and must be enabled via the [`experimentalTestSyntax` feature flag](../main-config/main-config-features.mdx#experimentaltestsyntax).

```ts title="Button.stories.js|ts"
// ...from above
export const PrimaryDisabled = Primary.extend({ args: { disabled: true } });

// 👇 .test method: Attach tests to a story
// The test function can run the same code as the play function
PrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {
const button = await canvas.findByRole('button');
await userEvent(button).click();

await expect(button).toBeDisabled();
await expect(args.onClick).not.toHaveBeenCalled();
});
Comment on lines +237 to +245
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Fix userEvent usage in <Story>.test example

Inside test/play functions Storybook passes userEvent as the preconfigured Testing Library instance, so you call its methods directly (await userEvent.click(button);). Calling it as a function (userEvent(button).click()) will throw because userEvent isn’t callable. Please update the snippet accordingly.

-PrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {
+PrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {
   const button = await canvas.findByRole('button');
-  await userEvent(button).click();
+  await userEvent.click(button);
 
   await expect(button).toBeDisabled();
   await expect(args.onClick).not.toHaveBeenCalled();
 });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
// 👇 .test method: Attach tests to a story
// The test function can run the same code as the play function
PrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {
const button = await canvas.findByRole('button');
await userEvent(button).click();
await expect(button).toBeDisabled();
await expect(args.onClick).not.toHaveBeenCalled();
});
// 👇 .test method: Attach tests to a story
// The test function can run the same code as the play function
PrimaryDisabled.test('should be disabled', async ({ canvas, userEvent, args }) => {
const button = await canvas.findByRole('button');
await userEvent.click(button);
await expect(button).toBeDisabled();
await expect(args.onClick).not.toHaveBeenCalled();
});
🤖 Prompt for AI Agents
In docs/api/csf/csf-next.mdx around lines 237 to 245, the example uses userEvent
as a callable (userEvent(button).click()) which is incorrect because Storybook
passes a preconfigured Testing Library userEvent instance; change the call to
use its method directly (await userEvent.click(button)) so the test invokes
userEvent.click with the target element.

```

## Upgrade to CSF Next

You can upgrade your stories to CSF Next either automatically (from CSF 3) or manually (from CSF 1, 2, or 3). CSF Next is designed to be usable incrementally; you do not have to upgrade all of your story files at once. However, you cannot mix story formats within the same file.
Expand Down
67 changes: 67 additions & 0 deletions docs/api/main-config/main-config-features.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@ Parent: [main.js|ts configuration](./main-config.mdx)

Type:

<If renderer="react">

```ts
{
actions?: boolean;
argTypeTargetsV7?: boolean;
backgrounds?: boolean;
controls?: boolean;
developmentModeForBuild?: boolean;
experimentalTestSyntax?: boolean;
highlight?: boolean;
interactions?: boolean;
legacyDecoratorFileOrder?: boolean;
measure?: boolean;
outline?: boolean;
toolbars?: boolean;
viewport?: boolean;
}
```
</If>

<If renderer="angular">

```ts
{
actions?: boolean;
Expand All @@ -26,6 +49,28 @@ Type:
viewport?: boolean;
}
```
</If>

<If notRenderer={['react','angular']}>

```ts
{
actions?: boolean;
argTypeTargetsV7?: boolean;
backgrounds?: boolean;
controls?: boolean;
developmentModeForBuild?: boolean;
highlight?: boolean;
interactions?: boolean;
legacyDecoratorFileOrder?: boolean;
measure?: boolean;
outline?: boolean;
toolbars?: boolean;
viewport?: boolean;
}
```
</If>


Enables Storybook's additional features.

Expand All @@ -35,12 +80,16 @@ Type: `boolean`

Enable the [Actions](../../essentials/actions.mdx) feature.

<If renderer="angular">

## `angularFilterNonInputControls`

Type: `boolean`

Filter non-input controls in Angular.

</If>

## `argTypeTargetsV7`

(⚠️ **Experimental**)
Expand Down Expand Up @@ -79,6 +128,24 @@ Set `NODE_ENV` to `'development'` in built Storybooks for better testing and deb

{/* prettier-ignore-end */}

<If renderer="react">

## `experimentalTestSyntax`

(⚠️ **Experimental**)

Type: `boolean`

Enable the [experimental `.test` method with the CSF Next format](../csf/csf-next#storytest).

{/* prettier-ignore-start */}

<CodeSnippets path="main-config-features-experimental-test-syntax.md" />

{/* prettier-ignore-end */}

</If>

## `highlight`

Type: `boolean`
Expand Down