Skip to content
Closed
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
26 changes: 25 additions & 1 deletion code/core/src/csf/csf-factories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@
import type {
Args,
ComponentAnnotations,
ComposedStoryFn,
NormalizedComponentAnnotations,
NormalizedProjectAnnotations,
NormalizedStoryAnnotations,
PlayFunction,
ProjectAnnotations,
Renderer,
StoryAnnotations,
StoryContext,
} from '@storybook/core/types';

import { composeConfigs, normalizeProjectAnnotations } from '@storybook/core/preview-api';
import {
composeConfigs,
composeStory,
normalizeProjectAnnotations,
} from '@storybook/core/preview-api';

export interface Preview<TRenderer extends Renderer = Renderer> {
readonly _tag: 'Preview';
Expand Down Expand Up @@ -82,19 +89,36 @@ export interface Story<TRenderer extends Renderer, TArgs extends Args = Args> {
input: StoryAnnotations<TRenderer, TArgs>;
composed: NormalizedStoryAnnotations<TRenderer>;
meta: Meta<TRenderer, TArgs>;
play: PlayFunction<TRenderer, TArgs>;
run: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;
}

function defineStory<TRenderer extends Renderer>(
input: ComponentAnnotations<TRenderer>,
meta: Meta<TRenderer>
): Story<TRenderer> {
let composed: ComposedStoryFn<TRenderer>;

const compose = () => {
if (!composed) {
composed = composeStory(input, meta.input, meta.preview.composed);
}
return composed;
};

return {
_tag: 'Story',
input,
meta,
get composed(): never {
throw new Error('Not implemented');
},
get play() {
return input.play ?? meta.input?.play ?? (async () => {});
},
get run() {
return compose().run || (async () => {});
},
};
}

Expand Down
50 changes: 50 additions & 0 deletions code/renderers/react/src/csf-factories.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -277,3 +277,53 @@ it('Infer mock function given to args in meta.', () => {
},
});
});

describe('Composed getters', () => {
const TestButton = () => <></>;

const meta = preview.meta({
component: TestButton,
args: { label: 'label', onClick: fn(), onRender: () => <>some jsx</> },
});

it('Composes the play function', async () => {
const spy = fn();
const Basic = meta.story({
play: async ({ args }) => {
spy(args);
},
});

await Basic.play(meta.input as any);

expect(spy).toHaveBeenCalledWith({
label: 'label',
onClick: expect.any(Function),
onRender: expect.any(Function),
});
});

it('Composes the run function', async () => {
const playSpy = fn();
const renderSpy = fn();
const Basic = meta.story({
play: async ({ args }) => {
playSpy(args);
},
render: () => {
renderSpy();
return <></>;
},
});

await Basic.run();

expect(playSpy).toHaveBeenCalledWith({
label: 'label',
onClick: expect.any(Function),
onRender: expect.any(Function),
});

expect(renderSpy).toHaveBeenCalled();
});
});