storybookjs / storybook

Storybook is the industry standard workshop for building, documenting, and testing UI components in isolation
https://storybook.js.org
MIT License
84.7k stars 9.33k forks source link

[Bug]: Type for beforeAll is possibly undefined when used in portable stories #28513

Closed valentinpalkovic closed 4 months ago

valentinpalkovic commented 4 months ago

Describe the bug

Applying the following example code in a setupTests.ts file to setup project annotations for vitest:

import { beforeAll } from "vitest";
import { setProjectAnnotations } from "@storybook/react";
import { render as testingLibraryRender } from "@testing-library/react";
import * as storybookAnnotations from "./.storybook/preview";

const annotations = setProjectAnnotations([
  storybookAnnotations,
  { testingLibraryRender },
]);

// ERROR
beforeAll(annotations.beforeAll);

annotations.beforeAll is potentially undefined, although it is always a function, even if the user doesn’t define beforeAll.

We should fix the type returned by setProjectAnnotations to always set beforeAll as required.

image

greptile-apps[bot] commented 4 months ago

To address the issue of annotations.beforeAll being potentially undefined, update the type definition in the setProjectAnnotations function to ensure beforeAll is always defined.

  1. Update Type Definition:
    • Modify the return type of setProjectAnnotations in /code/renderers/react/src/portable-stories.tsx and /code/renderers/vue3/src/portable-stories.ts to ensure beforeAll is always defined.
export function setProjectAnnotations(
  projectAnnotations: NamedOrDefaultProjectAnnotations<ReactRenderer> | NamedOrDefaultProjectAnnotations<ReactRenderer>[]
): ProjectAnnotations<ReactRenderer> & { beforeAll: NonNullable<ProjectAnnotations<ReactRenderer>['beforeAll']> } {
  return originalSetProjectAnnotations<ReactRenderer>(projectAnnotations) as ProjectAnnotations<ReactRenderer> & { beforeAll: NonNullable<ProjectAnnotations<ReactRenderer>['beforeAll']> };
}
  1. Update Tests:
    • Ensure tests in /code/core/src/preview-api/modules/store/csf/portable-stories.test.ts reflect the new type definition.
it('should return composed beforeAll as part of project annotations', async () => {
  const after = vi.fn();
  const before = vi.fn((n) => () => after(n));
  const finalAnnotations = setProjectAnnotations([
    { beforeAll: () => before(1) },
    { beforeAll: () => before(2) },
    { beforeAll: () => before(3) },
  ]);

  const cleanup = await finalAnnotations.beforeAll?.();
  expect(before.mock.calls).toEqual([[1], [2], [3]]);

  await cleanup?.();
  expect(after.mock.calls).toEqual([[3], [2], [1]]);
});

References

/code/renderers/react/src/portable-stories.tsx /code/renderers/vue3/src/portable-stories.ts /code/core/src/preview-api/modules/store/csf/portable-stories.test.ts /code/core/src/preview-api/modules/store/csf /code/core/src/preview-api/modules/store/StoryStore.test.ts

#### About Greptile This response provides a starting point for your research, not a precise solution. Help us improve! Please leave a 👍 if this is helpful and 👎 if it is irrelevant. [Ask Greptile](https://app.greptile.com/chat/github/storybookjs/storybook/next) · [Edit Issue Bot Settings](https://app.greptile.com/apps/github)