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
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ export function instructions(projectInfo: ProjectInfo): string {
const tsx = ext(language, true);
const ts = ext(language, false);
const docsUrl = (path: string) => getDocsMarkdownUrl(path, projectInfo);
const mswInstall = packageManager.getInstallCommand(
['msw', 'msw-storybook-addon', 'mockdate'],
true
);
const mswInstall = packageManager.getInstallCommand(['msw', 'mockdate'], true);

const ctx: SetupInstructionsContext = {
configDir,
Expand Down
5 changes: 1 addition & 4 deletions code/core/src/cli/ai/setup-prompts/monorepo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,10 +40,7 @@ export function instructions(projectInfo: ProjectInfo): string {
const tsx = ext(language, true);
const ts = ext(language, false);
const docsUrl = (path: string) => getDocsMarkdownUrl(path, projectInfo);
const mswInstall = packageManager.getInstallCommand(
['msw', 'msw-storybook-addon', 'mockdate'],
true
);
const mswInstall = packageManager.getInstallCommand(['msw', 'mockdate'], true);

const ctx: SetupInstructionsContext = {
configDir,
Expand Down
5 changes: 1 addition & 4 deletions code/core/src/cli/ai/setup-prompts/optimized-tests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ export function instructions(projectInfo: ProjectInfo): string {
const tsx = ext(language, true);
const ts = ext(language, false);
const docsUrl = (path: string) => getDocsMarkdownUrl(path, projectInfo);
const mswInstall = packageManager.getInstallCommand(
['msw', 'msw-storybook-addon', 'mockdate'],
true
);
const mswInstall = packageManager.getInstallCommand(['msw', 'mockdate'], true);

const ctx: SetupInstructionsContext = {
configDir,
Expand Down
52 changes: 39 additions & 13 deletions code/core/src/cli/ai/setup-prompts/partials/examples.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,49 @@ import type { ProjectInfo } from '../../types.ts';
import { ext } from '../../utils/ext.ts';

export function getPreviewExample(projectInfo: ProjectInfo): string {
const { configDir, language, framework, rendererPackage } = projectInfo;
const { configDir, language, framework, rendererPackage, hasCsfFactoryPreview } = projectInfo;
const tsx = ext(language, true);
const typeImport = framework || rendererPackage || '@storybook/react-vite';

if (language === 'js') {
if (hasCsfFactoryPreview) {
return dedent`
\`\`\`${tsx}
// ${configDir}/preview.${tsx}
import { definePreview } from '${typeImport}';
import '../src/index.css';
import MockDate from 'mockdate';
import { initialize, mswLoader } from 'msw-storybook-addon';
import addonMsw from 'msw-storybook-addon';
import { SessionProvider } from '../src/contexts/SessionContext';
import { mswHandlers } from './msw-handlers';

initialize({ onUnhandledRequest: 'bypass' });
export default definePreview({
addons: [addonMsw()],
decorators: [
(Story) => (
<SessionProvider>
<Story />
</SessionProvider>
),
],
async beforeEach({ msw }) {
msw.use(...mswHandlers);
localStorage.setItem('theme', 'dark');
MockDate.set('2024-04-01T12:00:00Z');
},
});
\`\`\`
`;
}

if (language === 'js') {
return dedent`
\`\`\`${tsx}
// ${configDir}/preview.${tsx}
import '../src/index.css';
import MockDate from 'mockdate';
import { mswLoader } from 'msw-storybook-addon/csf3';
import { SessionProvider } from '../src/contexts/SessionContext';
import { mswHandlers } from './msw-handlers';

const preview = {
decorators: [
Expand All @@ -27,9 +55,9 @@ export function getPreviewExample(projectInfo: ProjectInfo): string {
</SessionProvider>
),
],
loaders: [mswLoader],
parameters: { msw: { handlers: mswHandlers } },
async beforeEach() {
loaders: [mswLoader()],
async beforeEach({ msw }) {
msw.use(...mswHandlers);
localStorage.setItem('theme', 'dark');
MockDate.set('2024-04-01T12:00:00Z');
},
Expand All @@ -46,12 +74,10 @@ export function getPreviewExample(projectInfo: ProjectInfo): string {
import type { Preview } from '${typeImport}';
import '../src/index.css';
import MockDate from 'mockdate';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { mswLoader } from 'msw-storybook-addon/csf3';
import { SessionProvider } from '../src/contexts/SessionContext';
import { mswHandlers } from './msw-handlers';

initialize({ onUnhandledRequest: 'bypass' });

const preview: Preview = {
decorators: [
(Story) => (
Expand All @@ -60,9 +86,9 @@ export function getPreviewExample(projectInfo: ProjectInfo): string {
</SessionProvider>
),
],
loaders: [mswLoader],
parameters: { msw: { handlers: mswHandlers } },
async beforeEach() {
loaders: [mswLoader()],
async beforeEach({ msw }) {
msw.use(...mswHandlers);
localStorage.setItem('theme', 'dark');
MockDate.set('2024-04-01T12:00:00Z');
},
Expand Down
28 changes: 19 additions & 9 deletions code/core/src/cli/ai/setup-prompts/partials/steps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,16 +183,28 @@ export function mswStep(
{ configDir, mswInstall, packageManager, ts }: InstructionsContext
): { title: string; body: string } {
const mswInit = getMswInitCommand(packageManager);
const mswAddonAdd = packageManager.getPackageCommand([
'storybook',
'add',
'msw-storybook-addon@3',
]);
const csfNextNote = projectInfo.hasCsfFactoryPreview
? `

If \`storybook add\` injects \`import * as mswStorybookAddon from 'msw-storybook-addon/preview'\` and a \`mswStorybookAddon\` entry into your \`definePreview\` \`addons\`, remove both — that form breaks TypeScript inference for the entire preview. Register the addon with \`addonMsw()\` as shown below instead.
`
: '';

return {
title: 'MSW handlers (only what stories will hit)',
body: `Use \`msw-storybook-addon\`. Install with:
body: `Use \`msw-storybook-addon\`. Register it with \`storybook add\` (which also adds it to the \`addons\` field of \`${configDir}/main.${ts}\`), then install its peer dependencies and generate the worker script:

\`\`\`bash
${mswAddonAdd}
${mswInstall}
${mswInit}
\`\`\`

${csfNextNote}
Make sure \`${configDir}/main.${ts}\` serves \`./public\`:

${getMainConfigExample(projectInfo)}
Expand All @@ -203,13 +215,11 @@ export function mswStep(
// ${configDir}/msw-handlers.${ts}
import { http, HttpResponse } from 'msw';

export const mswHandlers = {
products: [
http.get('https://api.example.com/products', () =>
HttpResponse.json({ items: [{ id: 'p1', name: 'Example', price: 42 }] })
),
],
};
export const mswHandlers = [
http.get('https://api.example.com/products', () =>
HttpResponse.json({ items: [{ id: 'p1', name: 'Example', price: 42 }] })
),
];
\`\`\`
`,
};
Expand Down
71 changes: 33 additions & 38 deletions code/core/src/cli/ai/setup-prompts/pattern-copy-play.ts
Original file line number Diff line number Diff line change
Expand Up @@ -143,19 +143,13 @@ function getMswPreviewExample(projectInfo: ProjectInfo): string {
\`\`\`tsx
// ${configDir}/preview.tsx
import { definePreview } from 'storybook/preview';
import { initialize, mswLoader } from 'msw-storybook-addon';
import addonMsw from 'msw-storybook-addon';
import { mswHandlers } from './msw-handlers';
Comment thread
yannbf marked this conversation as resolved.

initialize({
onUnhandledRequest: 'bypass',
});

export default definePreview({
loaders: [mswLoader],
parameters: {
msw: {
handlers: mswHandlers,
},
addons: [addonMsw()],
async beforeEach({ msw }) {
msw.use(...mswHandlers);
},
});
\`\`\`
Expand All @@ -166,19 +160,13 @@ function getMswPreviewExample(projectInfo: ProjectInfo): string {
\`\`\`tsx
// ${configDir}/preview.tsx
import type { Preview } from '${typeImport}';
import { initialize, mswLoader } from 'msw-storybook-addon';
import { mswLoader } from 'msw-storybook-addon/csf3';
import { mswHandlers } from './msw-handlers';

initialize({
onUnhandledRequest: 'bypass',
});

const preview: Preview = {
loaders: [mswLoader],
parameters: {
msw: {
handlers: mswHandlers,
},
loaders: [mswLoader()],
async beforeEach({ msw }) {
msw.use(...mswHandlers);
},
};

Expand Down Expand Up @@ -453,6 +441,11 @@ export function instructions(projectInfo: ProjectInfo): string {
const configDir = projectInfo.configDir;
const typeImport = getTypeImportSource(projectInfo);
const mswInit = getMswInitCommand(projectInfo.packageManager);
const mswAddonAdd = projectInfo.packageManager.getPackageCommand([
'storybook',
'add',
'msw-storybook-addon@3',
]);
const vitestRunFile = getVitestStorybookRunCommand(
projectInfo.packageManager,
'<path-to-story-file>'
Expand Down Expand Up @@ -609,7 +602,11 @@ export function instructions(projectInfo: ProjectInfo): string {
All network/data queries should be handled by the default Storybook environment.

- Always use \`msw-storybook-addon\` for query mocking.
- If you introduce MSW, run \`${mswInit}\` to create the worker file.
- If you introduce MSW, register the addon with \`${mswAddonAdd}\` (which also adds it to the main config) and run \`${mswInit}\` to create the worker file.${
projectInfo.hasCsfFactoryPreview
? " If `storybook add` injects `import * as mswStorybookAddon from 'msw-storybook-addon/preview'` and a `mswStorybookAddon` entry into `definePreview` `addons`, remove both — that form breaks TypeScript inference for the entire preview; use `addonMsw()` instead."
: ''
}
- Make sure Storybook serves \`./public\` as a static dir so \`mockServiceWorker.js\` is available.
- Do not mock \`fetch\` directly.
- Network/data queries should return deterministic mock data.
Expand All @@ -633,23 +630,21 @@ export function instructions(projectInfo: ProjectInfo): string {
// ${configDir}/msw-handlers.ts
import { http, HttpResponse } from "msw";

export const mswHandlers = {
products: [
http.get("https://api.example.com/products", () =>
HttpResponse.json({
items: [
{
id: "product-1",
name: "Example product",
description: "Mock product description",
imageUrl: "https://images.example.com/product.jpg",
price: 42,
},
],
}),
),
],
};
export const mswHandlers = [
http.get("https://api.example.com/products", () =>
HttpResponse.json({
items: [
{
id: "product-1",
name: "Example product",
description: "Mock product description",
imageUrl: "https://images.example.com/product.jpg",
price: 42,
},
],
}),
),
];
\`\`\`

${getMswPreviewExample(projectInfo)}
Expand Down
5 changes: 1 addition & 4 deletions code/core/src/cli/ai/setup-prompts/relaxed-limits.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,7 @@ export function instructions(projectInfo: ProjectInfo): string {
const tsx = ext(language, true);
const ts = ext(language, false);
const docsUrl = (path: string) => getDocsMarkdownUrl(path, projectInfo);
const mswInstall = packageManager.getInstallCommand(
['msw', 'msw-storybook-addon', 'mockdate'],
true
);
const mswInstall = packageManager.getInstallCommand(['msw', 'mockdate'], true);

const ctx: SetupInstructionsContext = {
configDir,
Expand Down
Loading