Skip to content

Commit

Permalink
Merge pull request #28764 from storybookjs/kasper/introduce-run
Browse files Browse the repository at this point in the history
Core: Introduce run over play in portable stories, and revert back play changes of 8.2
(cherry picked from commit 3b65e72)
  • Loading branch information
kasperpeulen committed Aug 1, 2024
1 parent e821802 commit 9a36be4
Show file tree
Hide file tree
Showing 35 changed files with 347 additions and 335 deletions.
55 changes: 23 additions & 32 deletions code/core/src/preview-api/modules/store/csf/portable-stories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,25 +89,8 @@ export function composeStory<TRenderer extends Renderer = Renderer, TArgs extend
normalizedComponentAnnotations
);

// TODO: Remove this in 9.0
// We can only use the renderToCanvas definition of the default config when testingLibraryRender is set
// This makes sure, that when the user doesn't do this, and doesn't provide its own renderToCanvas definition,
// we fall back to the < 8.1 behavior of the play function.

const fallback =
defaultConfig &&
!globalProjectAnnotations?.testingLibraryRender &&
!projectAnnotations?.testingLibraryRender;

const normalizedProjectAnnotations = normalizeProjectAnnotations<TRenderer>(
composeConfigs([
{
...defaultConfig,
renderToCanvas: fallback ? undefined : defaultConfig?.renderToCanvas,
},
globalProjectAnnotations,
projectAnnotations ?? {},
])
composeConfigs([defaultConfig ?? {}, globalProjectAnnotations, projectAnnotations ?? {}])
);

const story = prepareStory<TRenderer>(
Expand All @@ -130,7 +113,7 @@ export function composeStory<TRenderer extends Renderer = Renderer, TArgs extend
loaded: {},
abortSignal: new AbortController().signal,
step: (label, play) => story.runStep(label, play, context),
canvasElement: globalThis?.document?.body,
canvasElement: null!,
canvas: {} as Canvas,
...story,
context: null!,
Expand All @@ -149,6 +132,7 @@ export function composeStory<TRenderer extends Renderer = Renderer, TArgs extend
id: story.id,
name: story.name,
tags: story.tags,
showMain: () => {},
showError: (error) => {},
showException: (error) => {},
forceRemount: true,
Expand All @@ -171,28 +155,23 @@ export function composeStory<TRenderer extends Renderer = Renderer, TArgs extend

let loadedContext: StoryContext<TRenderer> | undefined;

// TODO: Remove in 9.0
const backwardsCompatiblePlay = async (
extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>
) => {
const play = async (extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => {
const context = initializeContext();
context.canvasElement ??= globalThis?.document?.body;
if (loadedContext) {
context.loaded = loadedContext.loaded;
}
Object.assign(context, extraContext);
return story.playFunction!(context);
};
const newPlay = (extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => {

const run = (extraContext?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => {
const context = initializeContext();
Object.assign(context, extraContext);
return playStory(story, context);
return runStory(story, context);
};
const playFunction =
!story.renderToCanvas && story.playFunction
? backwardsCompatiblePlay
: !story.renderToCanvas && !story.playFunction
? undefined
: newPlay;

const playFunction = story.playFunction ? play : undefined;

const composedStory: ComposedStoryFn<TRenderer, Partial<TArgs>> = Object.assign(
function storyFn(extraArgs?: Partial<TArgs>) {
Expand Down Expand Up @@ -226,6 +205,7 @@ export function composeStory<TRenderer extends Renderer = Renderer, TArgs extend
parameters: story.parameters as Parameters,
argTypes: story.argTypes as StrictArgTypes<TArgs>,
play: playFunction!,
run,
tags: story.tags,
}
);
Expand Down Expand Up @@ -325,13 +305,24 @@ export function createPlaywrightTest<TFixture extends { extend: any }>(

// TODO At some point this function should live in prepareStory and become the core of StoryRender.render as well.
// Will make a follow up PR for that
async function playStory<TRenderer extends Renderer>(
async function runStory<TRenderer extends Renderer>(
story: PreparedStory<TRenderer>,
context: StoryContext<TRenderer>
) {
for (const callback of [...cleanups].reverse()) await callback();
cleanups.length = 0;

if (!context.canvasElement) {
const container = document.createElement('div');
globalThis?.document?.body?.appendChild(container);
context.canvasElement = container;
cleanups.push(() => {
if (globalThis?.document?.body?.contains(container)) {
globalThis?.document?.body?.removeChild(container);
}
});
}

context.loaded = await story.applyLoaders(context);
if (context.abortSignal.aborted) return;

Expand Down
3 changes: 2 additions & 1 deletion code/core/src/types/modules/composedStory.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@ export type ComposedStoryFn<
> = PartialArgsStoryFn<TRenderer, TArgs> & {
args: TArgs;
id: StoryId;
play: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;
play?: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;
run: (context?: Partial<StoryContext<TRenderer, Partial<TArgs>>>) => Promise<void>;
load: () => Promise<void>;
storyName: string;
parameters: Parameters;
Expand Down
10 changes: 5 additions & 5 deletions code/renderers/react/src/__test__/portable-stories.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ describe('renders', () => {
});

it('should render component mounted in play function', async () => {
await MountInPlayFunction.play();
await MountInPlayFunction.run();

expect(screen.getByTestId('spy-data').textContent).toEqual('mockFn return value');
expect(screen.getByTestId('loaded-data').textContent).toEqual('loaded data');
Expand All @@ -65,7 +65,7 @@ describe('renders', () => {
expect(getByTestId('spy-data').textContent).toEqual('mockFn return value');
expect(getByTestId('loaded-data').textContent).toEqual('loaded data');
// spy assertions happen in the play function and should work
await LoaderStory.play!();
await LoaderStory.run!();
});
});

Expand Down Expand Up @@ -125,7 +125,7 @@ describe('CSF3', () => {

it('renders with play function without canvas element', async () => {
const CSF3InputFieldFilled = composeStory(stories.CSF3InputFieldFilled, stories.default);
await CSF3InputFieldFilled.play();
await CSF3InputFieldFilled.run();

const input = screen.getByTestId('input') as HTMLInputElement;
expect(input.value).toEqual('Hello world!');
Expand All @@ -138,7 +138,7 @@ describe('CSF3', () => {
console.log(div.tagName);
document.body.appendChild(div);

await CSF3InputFieldFilled.play({ canvasElement: div });
await CSF3InputFieldFilled.run({ canvasElement: div });

const input = screen.getByTestId('input') as HTMLInputElement;
expect(input.value).toEqual('Hello world!');
Expand Down Expand Up @@ -185,6 +185,6 @@ const testCases = Object.values(composeStories(stories)).map(
);
it.each(testCases)('Renders %s story', async (_storyName, Story) => {
if (_storyName === 'CSF2StoryWithLocale') return;
await Story.play();
await Story.run();
expect(document.body).toMatchSnapshot();
});
15 changes: 10 additions & 5 deletions code/renderers/react/src/portable-stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ export function setProjectAnnotations(
// This will not be necessary once we have auto preset loading
export const INTERNAL_DEFAULT_PROJECT_ANNOTATIONS: ProjectAnnotations<ReactRenderer> = {
...reactProjectAnnotations,
renderToCanvas: ({
storyContext: { context, unboundStoryFn: Story, testingLibraryRender: render, canvasElement },
}) => {
if (render == null) throw new TestingLibraryMustBeConfiguredError();
const { unmount } = render(<Story {...context} />, { baseElement: context.canvasElement });
renderToCanvas: (renderContext, canvasElement) => {
if (renderContext.storyContext.testingLibraryRender == null) {
throw new TestingLibraryMustBeConfiguredError();
// Enable for 8.3
// return reactProjectAnnotations.renderToCanvas(renderContext, canvasElement);
}
const {
storyContext: { context, unboundStoryFn: Story, testingLibraryRender: render },
} = renderContext;
const { unmount } = render(<Story {...context} />, { container: context.canvasElement });
return unmount;
},
};
Expand Down
Loading

0 comments on commit 9a36be4

Please sign in to comment.