Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
b23ccf1
Docs: Adds commands to the documentation
jonniebigodes Jan 12, 2024
6376e9d
Merge branch 'next' into docs_adds_doctor
jonniebigodes Jan 13, 2024
8e1ec5a
Merge branch 'next' into docs_adds_doctor
jonniebigodes Jan 15, 2024
20f1a91
Merge branch 'next' into docs_adds_doctor
jonniebigodes Jan 16, 2024
1cc0ba0
Fixes link for storybook new
jonniebigodes Jan 16, 2024
fbf50c6
Address feedback
jonniebigodes Jan 17, 2024
19ff85d
Merge branch 'docs_adds_doctor' of https://github.com/storybookjs/sto…
jonniebigodes Jan 17, 2024
cb22ad2
Removes added notes
jonniebigodes Jan 18, 2024
470bd58
Refactor integration tests for PreviewWeb module
valentinpalkovic Jan 18, 2024
68c80ba
Merge branch 'next' into valentin/fix-flaky-unit-test
valentinpalkovic Jan 19, 2024
6eceaaf
Set retry option for flaky PreviewAPI test
valentinpalkovic Jan 19, 2024
e8dc7ca
change ordering of commands
jonniebigodes Jan 19, 2024
9fcfeb2
minor tweaks
jonniebigodes Jan 19, 2024
c6a3eda
Docs: Updates shortcuts
jonniebigodes Jan 21, 2024
7087993
Merge branch 'next' into valentin/fix-flaky-unit-test
valentinpalkovic Jan 22, 2024
00977ce
Merge branch 'next' into docs_adds_doctor
jonniebigodes Jan 22, 2024
51035f1
Merge branch 'next' into docs_update_shortcuts
jonniebigodes Jan 22, 2024
dd22e0e
Merge pull request #25681 from storybookjs/docs_update_shortcuts
jonniebigodes Jan 22, 2024
0aad12e
Merge branch 'next' into docs_adds_doctor
jonniebigodes Jan 22, 2024
4833849
Merge pull request #25589 from storybookjs/docs_adds_doctor
jonniebigodes Jan 22, 2024
9e43755
Merge pull request #25654 from storybookjs/valentin/fix-flaky-unit-test
valentinpalkovic Jan 22, 2024
b7ffcdb
Write changelog for 8.0.0-alpha.13 [skip ci]
storybook-bot Jan 22, 2024
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
4 changes: 4 additions & 0 deletions CHANGELOG.prerelease.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 8.0.0-alpha.13

- Next.js: Fix SWC mode activation - [#25670](https://github.com/storybookjs/storybook/pull/25670), thanks [@valentinpalkovic](https://github.com/valentinpalkovic)!

## 8.0.0-alpha.12

- Blocks: Fix Controls block not having controls - [#25663](https://github.com/storybookjs/storybook/pull/25663), thanks [@JReinhold](https://github.com/JReinhold)!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,98 +72,122 @@ beforeEach(() => {
vi.mocked(WebView.prototype).prepareForStory.mockReturnValue('story-element' as any);
});

describe('PreviewWeb', () => {
describe('initial render', () => {
it('renders story mode through the stack', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

projectAnnotations.renderToCanvas.mockImplementationOnce(({ storyFn }: RenderContext<any>) =>
storyFn()
);
document.location.search = '?id=component-one--a';
await new PreviewWeb(importFn, getProjectAnnotations).ready();

await waitForRender();

expect(projectAnnotations.decorators[0]).toHaveBeenCalled();
expect(projectAnnotations.render).toHaveBeenCalled();
});

it('renders docs mode through docs page', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--docs&viewMode=docs';
const preview = new PreviewWeb(importFn, getProjectAnnotations);

const docsRoot = document.createElement('div');
vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);
componentOneExports.default.parameters.docs.container.mockImplementationOnce(() =>
React.createElement('div', {}, 'INSIDE')
);

await preview.ready();
await waitForRender();

expect(docsRoot.outerHTML).toMatchInlineSnapshot('"<div><div>INSIDE</div></div>"');
// Extended timeout to try and avoid
// Error: Event was not emitted in time: storyRendered,docsRendered,storyThrewException,storyErrored,storyMissing
}, 10_000);

it('sends docs rendering exceptions to showException', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--docs&viewMode=docs';
const preview = new PreviewWeb(importFn, getProjectAnnotations);

const docsRoot = document.createElement('div');
vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);
componentOneExports.default.parameters.docs.container.mockImplementation(() => {
throw new Error('Docs rendering error');
describe(
'PreviewWeb',
() => {
describe('initial render', () => {
it('renders story mode through the stack', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

projectAnnotations.renderToCanvas.mockImplementationOnce(
({ storyFn }: RenderContext<any>) => storyFn()
);
document.location.search = '?id=component-one--a';
await new PreviewWeb(importFn, getProjectAnnotations).ready();

await waitForRender();

await vi.waitFor(() => {
expect(projectAnnotations.decorators[0]).toHaveBeenCalled();
expect(projectAnnotations.render).toHaveBeenCalled();
});
});

vi.mocked(preview.view.showErrorDisplay).mockClear();

await preview.ready();
await waitForRender();

expect(preview.view.showErrorDisplay).toHaveBeenCalled();
it('renders docs mode through docs page', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--docs&viewMode=docs';
const preview = new PreviewWeb(importFn, getProjectAnnotations);

const docsRoot = document.createElement('div');
vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);
componentOneExports.default.parameters.docs.container.mockImplementationOnce(() =>
React.createElement('div', {}, 'INSIDE')
);

await preview.ready();

await vi.waitFor(
() => {
if (docsRoot.outerHTML !== '<div><div>INSIDE</div></div>') {
throw new Error('DocsRoot not ready yet');
}
},
{
timeout: 2000,
}
);

expect(docsRoot.outerHTML).toMatchInlineSnapshot('"<div><div>INSIDE</div></div>"');

// Extended timeout to try and avoid
// Error: Event was not emitted in time: storyRendered,docsRendered,storyThrewException,storyErrored,storyMissing
}, 10_000);

it('sends docs rendering exceptions to showException', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--docs&viewMode=docs';
const preview = new PreviewWeb(importFn, getProjectAnnotations);

const docsRoot = document.createElement('div');
vi.mocked(preview.view.prepareForDocs).mockReturnValue(docsRoot as any);
componentOneExports.default.parameters.docs.container.mockImplementation(() => {
throw new Error('Docs rendering error');
});

vi.mocked(preview.view.showErrorDisplay).mockClear();

await preview.ready();

await vi.waitFor(
() => {
expect(preview.view.showErrorDisplay).toHaveBeenCalled();
},
{
timeout: 2000,
}
);
});
});
});

describe('onGetGlobalMeta changed (HMR)', () => {
const newGlobalDecorator = vi.fn((s) => s());
const newGetProjectAnnotations = () => {
return {
...projectAnnotations,
args: { a: 'second' },
globals: { a: 'second' },
decorators: [newGlobalDecorator],

describe('onGetGlobalMeta changed (HMR)', () => {
const newGlobalDecorator = vi.fn((s) => s());
const newGetProjectAnnotations = () => {
return {
...projectAnnotations,
args: { a: 'second' },
globals: { a: 'second' },
decorators: [newGlobalDecorator],
};
};
};

it('renders story mode through the updated stack', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--a';
const preview = new PreviewWeb(importFn, getProjectAnnotations);
await preview.ready();
await waitForRender();

projectAnnotations.renderToCanvas.mockImplementationOnce(({ storyFn }: RenderContext<any>) =>
storyFn()
);
projectAnnotations.decorators[0].mockClear();
mockChannel.emit.mockClear();
preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });
await waitForRender();

expect(projectAnnotations.decorators[0]).not.toHaveBeenCalled();
expect(newGlobalDecorator).toHaveBeenCalled();
expect(projectAnnotations.render).toHaveBeenCalled();

it('renders story mode through the updated stack', async () => {
const { DocsRenderer } = await import('@storybook/addon-docs');
projectAnnotations.parameters.docs.renderer = () => new DocsRenderer() as any;

document.location.search = '?id=component-one--a';
const preview = new PreviewWeb(importFn, getProjectAnnotations);
await preview.ready();
await waitForRender();

projectAnnotations.renderToCanvas.mockImplementationOnce(
({ storyFn }: RenderContext<any>) => storyFn()
);
projectAnnotations.decorators[0].mockClear();
mockChannel.emit.mockClear();
preview.onGetProjectAnnotationsChanged({ getProjectAnnotations: newGetProjectAnnotations });

await vi.waitFor(() => {
expect(projectAnnotations.decorators[0]).not.toHaveBeenCalled();
expect(newGlobalDecorator).toHaveBeenCalled();
expect(projectAnnotations.render).toHaveBeenCalled();
});
});
});
});
});
},
{ retry: 3 }
);
3 changes: 2 additions & 1 deletion code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -292,5 +292,6 @@
"Dependency Upgrades"
]
]
}
},
"deferredNextVersion": "8.0.0-alpha.13"
}
82 changes: 25 additions & 57 deletions docs/addons/install-addons.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,111 +2,79 @@
title: 'Install addons'
---

Storybook has [hundreds of reusable addons](https://storybook.js.org/addons) that are packaged as NPM modules. Let's walk through how to extend Storybook by installing and registering addons.
Storybook has [hundreds of reusable addons](https://storybook.js.org/integrations) packaged as NPM modules. Let's walk through how to extend Storybook by installing and registering addons.

### Using addons
## Automatic installation

With the exception of preset addons, all addons have the same installation process: install and register.
Storybook includes a [`storybook add`](../api/cli-options.md#add) command to automate the setup of addons. Several community-led addons can be added using this command, except for preset addons. We encourage you to read the addon's documentation to learn more about its installation process.

For example, to include accessibility testing in Storybook, run the following command to install the necessary addon:
Run the `storybook add` command using your chosen package manager, and the CLI will update your Storybook configuration to include the addon and install any necessary dependencies.

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'common/storybook-a11y-install.yarn.js.mdx',
'common/storybook-a11y-install.npm.js.mdx',
'common/storybook-a11y-install.pnpm.js.mdx',
'common/storybook-add-command.yarn.js.mdx',
'common/storybook-add-command.npm.js.mdx',
'common/storybook-add-command.pnpm.js.mdx',
]}
/>

<!-- prettier-ignore-end -->

Next, update [`.storybook/main.js|ts`](../configure/index.md#configure-story-rendering) to the following:
<Callout variant="warning">

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'common/storybook-a11y-register.js.mdx',
'common/storybook-a11y-register.ts.mdx',
]}
/>

<!-- prettier-ignore-end -->

<Callout variant="info">

Addons may also require addon-specific configuration. Read their respective READMEs.
If you're attempting to install multiple addons at once, it will only install the first addon that was specified. This is a known limitation of the current implementation and will be addressed in a future release.

</Callout>

Now when you run Storybook the accessibility testing addon will be enabled.

![Storybook addon installed and registered](./storybook-addon-installed-registered.png)

### Using preset addons
### Manual installation

Storybook preset addons are grouped collections of specific `babel`, `webpack` and `addons` configurations for distinct use cases. Each one with its own set of instructions. Preset addons have a three-step installation process: install, register and optionally configuration.
Storybook addons are always added through the [`addons`](../api/main-config-addons.md) configuration array in [`.storybook/main.js|ts`](../configure/index.md). The following example shows how to manually add the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) to Storybook.

For example, to use SCSS styling, run the following command to install the addon and the required dependencies:
Run the following command with your package manager of choice to install the addon.

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'common/storybook-preset-scss.webpack-4.js.mdx',
'common/storybook-preset-scss.webpack-5.js.mdx',
'common/storybook-a11y-install.yarn.js.mdx',
'common/storybook-a11y-install.npm.js.mdx',
'common/storybook-a11y-install.pnpm.js.mdx',
]}
/>

<!-- prettier-ignore-end -->

<Callout variant="info" icon="💡" title="Tip:">

Use the Webpack 5 snippet only if your framework already includes support for this version. Otherwise, use the Webpack 4 snippet.

</Callout>

Next, update [`.storybook/main.js|ts`](../configure/index.md#configure-story-rendering) to the following:
Next, update `.storybook/main.js|ts` to the following:

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'common/storybook-main-preset-config.js.mdx',
'common/storybook-main-preset-config.ts.mdx',
'common/storybook-a11y-register.js.mdx',
'common/storybook-a11y-register.ts.mdx',
]}
/>

<!-- prettier-ignore-end -->

Now when you run Storybook it will configure itself to use SCSS styling. No further configuration is needed.

#### Optional configuration
When you run Storybook, the accessibility testing addon will be enabled.

Most preset addons can also take additional parameters. The most common use cases are:
![Storybook addon installed and registered](./storybook-addon-installed-registered.png)

- Addon configuration
- Webpack loader configuration
### Removing addons

Consider the following example:
To remove an addon from Storybook, you can choose to manually uninstall it and remove it from the configuration file (i.e., [`.storybook/main.js|ts`](../configure/index.md)) or opt-in to do it automatically via the CLI with the [`remove`](../api/cli-options.md#remove) command. For example, to remove the [Accessibility addon](https://storybook.js.org/addons/@storybook/addon-a11y) from Storybook with the CLI, run the following command:

<!-- prettier-ignore-start -->

<CodeSnippets
paths={[
'common/storybook-preset-configuration.js.mdx',
'common/storybook-preset-configuration.ts.mdx',
'common/storybook-remove-command.yarn.js.mdx',
'common/storybook-remove-command.npm.js.mdx',
'common/storybook-remove-command.pnpm.js.mdx',
]}
/>

<!-- prettier-ignore-end -->

<Callout variant="info">

Preset addons may also have addon-specific configurations. Read their respective READMEs.

</Callout>

Now, when Storybook starts up, it will update webpack's CSS loader to use modules and adjust how styling is defined.
Loading