Skip to content

Commit

Permalink
Merge pull request #26110 from storybookjs/jeppe/24751-bug-stories-do…
Browse files Browse the repository at this point in the history
…cblock-duplicating-stories-on-custom-mdx-files

Blocks: Fix `Stories` block rendering duplicate stories when globals are changed
  • Loading branch information
JReinhold authored Feb 27, 2024
2 parents 7589b50 + 68c5350 commit 01f25d7
Show file tree
Hide file tree
Showing 7 changed files with 129 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { global as globalThis } from '@storybook/global';

export default {
title: 'Multiple CSF Files Same Title',
component: globalThis.Components.Html,
tags: ['autodocs'],
args: {
content: '<p>paragraph</p>',
},
parameters: {
chromatic: { disable: true },
},
};

export const DefaultA = {};

export const SpanContent = {
args: { content: '<span>span</span>' },
};

export const CodeContent = {
args: { content: '<code>code</code>' },
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { global as globalThis } from '@storybook/global';

export default {
title: 'Multiple CSF Files Same Title',
component: globalThis.Components.Html,
tags: ['autodocs'],
args: {
content: '<p>paragraph</p>',
},
parameters: {
chromatic: { disable: true },
},
};

export const DefaultB = {};

export const H1Content = {
args: { content: '<h1>heading 1</h1>' },
};

export const H2Content = {
args: { content: '<h2>heading 2</h2>' },
};
15 changes: 15 additions & 0 deletions code/e2e-tests/addon-docs.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -210,4 +210,19 @@ test.describe('addon-docs', () => {
await expect(componentReactVersion).toHaveText(expectedReactVersion);
await expect(componentReactDomVersion).toHaveText(expectedReactVersion);
});

test('should have stories from multiple CSF files in autodocs', async ({ page }) => {
const sbPage = new SbPage(page);
await sbPage.navigateToStory('/addons/docs/multiple-csf-files-same-title', 'docs');
const root = sbPage.previewRoot();

const storyHeadings = root.locator('.sb-anchor > h3');
await expect(await storyHeadings.count()).toBe(6);
await expect(storyHeadings.nth(0)).toHaveText('Default A');
await expect(storyHeadings.nth(1)).toHaveText('Span Content');
await expect(storyHeadings.nth(2)).toHaveText('Code Content');
await expect(storyHeadings.nth(3)).toHaveText('Default B');
await expect(storyHeadings.nth(4)).toHaveText('H 1 Content');
await expect(storyHeadings.nth(5)).toHaveText('H 2 Content');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,52 @@ describe('referenceCSFFile', () => {
});
});

describe('attachCSFFile', () => {
const firstCsfParts = csfFileParts('first-meta--first-story', 'first-meta');
const secondCsfParts = csfFileParts('second-meta--second-story', 'second-meta');
const store = {
componentStoriesFromCSFFile: ({ csfFile }: { csfFile: CSFFile }) =>
csfFile === firstCsfParts.csfFile ? [firstCsfParts.story] : [secondCsfParts.story],
} as unknown as StoryStore<Renderer>;

it('attaches multiple CSF files', () => {
// Arrange - create a context with both CSF files
const context = new DocsContext(channel, store, renderStoryToElement, [
firstCsfParts.csfFile,
secondCsfParts.csfFile,
]);

// Act - attach the first CSF file
context.attachCSFFile(firstCsfParts.csfFile);

// Assert - the first story is now the primary story and the only component story
expect(context.storyById()).toEqual(firstCsfParts.story);
expect(context.componentStories()).toEqual([firstCsfParts.story]);

// Assert - stories from both CSF files are available
expect(context.componentStoriesFromCSFFile(firstCsfParts.csfFile)).toEqual([
firstCsfParts.story,
]);
expect(context.componentStoriesFromCSFFile(secondCsfParts.csfFile)).toEqual([
secondCsfParts.story,
]);

// Act - attach the second CSF file
context.attachCSFFile(secondCsfParts.csfFile);

// Assert - the first story is still the primary story but both stories are available
expect(context.storyById()).toEqual(firstCsfParts.story);
expect(context.componentStories()).toEqual([firstCsfParts.story, secondCsfParts.story]);

// Act - attach the second CSF file again
context.attachCSFFile(secondCsfParts.csfFile);

// Assert - still only two stories are available
expect(context.storyById()).toEqual(firstCsfParts.story);
expect(context.componentStories()).toEqual([firstCsfParts.story, secondCsfParts.story]);
});
});

describe('resolveOf', () => {
const { story, csfFile, storyExport, metaExport, moduleExports, component } = csfFileParts();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ export class DocsContext<TRenderer extends Renderer> implements DocsContextProps

private nameToStoryId: Map<StoryName, StoryId>;

private attachedCSFFile?: CSFFile<TRenderer>;
private attachedCSFFiles: Set<CSFFile<TRenderer>>;

private primaryStory?: PreparedStory<TRenderer>;

Expand All @@ -38,11 +38,12 @@ export class DocsContext<TRenderer extends Renderer> implements DocsContextProps
/** The CSF files known (via the index) to be refererenced by this docs file */
csfFiles: CSFFile<TRenderer>[]
) {
this.componentStoriesValue = [];
this.storyIdToCSFFile = new Map();
this.exportToStory = new Map();
this.exportsToCSFFile = new Map();
this.nameToStoryId = new Map();
this.componentStoriesValue = [];
this.attachedCSFFiles = new Set();

csfFiles.forEach((csfFile, index) => {
this.referenceCSFFile(csfFile);
Expand Down Expand Up @@ -71,10 +72,15 @@ export class DocsContext<TRenderer extends Renderer> implements DocsContextProps
if (!this.exportsToCSFFile.has(csfFile.moduleExports)) {
throw new Error('Cannot attach a CSF file that has not been referenced');
}
if (this.attachedCSFFiles.has(csfFile)) {
// this CSF file is already attached, don't do anything
return;
}

this.attachedCSFFile = csfFile;
this.attachedCSFFiles.add(csfFile);

const stories = this.store.componentStoriesFromCSFFile({ csfFile });

stories.forEach((story) => {
this.nameToStoryId.set(story.name, story.id);
this.componentStoriesValue.push(story);
Expand Down Expand Up @@ -115,15 +121,18 @@ export class DocsContext<TRenderer extends Renderer> implements DocsContextProps
return { type: 'story', story: this.primaryStory } as TResolvedExport;
}

if (!this.attachedCSFFile)
if (this.attachedCSFFiles.size === 0)
throw new Error(
`No CSF file attached to this docs file, did you forget to use <Meta of={} />?`
);

if (moduleExportType === 'meta')
return { type: 'meta', csfFile: this.attachedCSFFile } as TResolvedExport;
const firstAttachedCSFFile = Array.from(this.attachedCSFFiles)[0];

if (moduleExportType === 'meta') {
return { type: 'meta', csfFile: firstAttachedCSFFile } as TResolvedExport;
}

const { component } = this.attachedCSFFile.meta;
const { component } = firstAttachedCSFFile.meta;
if (!component)
throw new Error(
`Attached CSF file does not defined a component, did you forget to export one?`
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import type { CSFFile, PreparedStory } from '@storybook/types';

export function csfFileParts() {
export function csfFileParts(storyId = 'meta--story', metaId = 'meta') {
// These compose the raw exports of the CSF file
const component = {};
const metaExport = { component };
Expand All @@ -9,13 +9,13 @@ export function csfFileParts() {

// This is the prepared story + CSF file after SB has processed them
const storyAnnotations = {
id: 'meta--story',
id: storyId,
moduleExport: storyExport,
} as CSFFile['stories'][string];
const story = { id: 'meta--story', moduleExport: storyExport } as PreparedStory;
const meta = { id: 'meta', title: 'Meta', component, moduleExports } as CSFFile['meta'];
const story = { id: storyId, moduleExport: storyExport } as PreparedStory;
const meta = { id: metaId, title: 'Meta', component, moduleExports } as CSFFile['meta'];
const csfFile = {
stories: { 'meta--story': storyAnnotations },
stories: { [storyId]: storyAnnotations },
meta,
moduleExports,
} as CSFFile;
Expand Down
2 changes: 1 addition & 1 deletion code/renderers/svelte/template/components/Html.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@
export let content = '';
</script>

<div>{@html content}></div>
<div>{@html content}</div>

0 comments on commit 01f25d7

Please sign in to comment.