diff --git a/lib/core/src/client/preview/loadCsf.test.ts b/lib/core/src/client/preview/loadCsf.test.ts index c51b589b011f..39a5c003ea80 100644 --- a/lib/core/src/client/preview/loadCsf.test.ts +++ b/lib/core/src/client/preview/loadCsf.test.ts @@ -1,8 +1,13 @@ import { ConfigApi, ClientApi, StoryStore } from '@storybook/client-api'; +import { logger } from '@storybook/client-logger'; import { RequireContext } from './types'; import { loadCsf } from './loadCsf'; +jest.mock('@storybook/client-logger', () => ({ + logger: { warn: jest.fn() }, +})); + let cbs: ((data: any) => void)[]; let mod: NodeModule; beforeEach(() => { @@ -365,4 +370,34 @@ describe('core.preview.loadCsf', () => { expect(storyStore.incrementRevision).toHaveBeenCalled(); expect(mockedStoriesOf).toHaveBeenCalledWith('a', true); }); + + it('gives a warning if there are no exported stories', () => { + const { configure } = makeMocks(); + + const input = { + a: { + default: { + title: 'MissingExportsComponent', + }, + // no named exports, will not present a story + }, + }; + configure(makeRequireContext(input), mod, 'react'); + expect(logger.warn).toHaveBeenCalled(); + }); + + it('does not give a warning if there are exported stories', () => { + const { configure } = makeMocks(); + + const input = { + a: { + default: { + title: 'MissingExportsComponent', + }, + x: () => 0, + }, + }; + configure(makeRequireContext(input), mod, 'react'); + expect(logger.warn).not.toHaveBeenCalled(); + }); }); diff --git a/lib/core/src/client/preview/loadCsf.ts b/lib/core/src/client/preview/loadCsf.ts index cb8873da1a73..357a7569d79f 100644 --- a/lib/core/src/client/preview/loadCsf.ts +++ b/lib/core/src/client/preview/loadCsf.ts @@ -1,6 +1,7 @@ import { ConfigApi, ClientApi, StoryStore } from '@storybook/client-api'; import { isExportStory, storyNameFromExport, toId } from '@storybook/csf'; import { logger } from '@storybook/client-logger'; +import dedent from 'ts-dedent'; import { Loadable, LoaderFunction, RequireContext } from './types'; @@ -113,7 +114,16 @@ const loadStories = ( kind.addDecorator(decorator); }); - Object.keys(exports).forEach((key) => { + const storyExports = Object.keys(exports); + if (storyExports.length === 0) { + logger.warn( + dedent`Found a story file for "${kindName}" but no exported stories. + Check the docs for reference: https://storybook.js.org/docs/formats/component-story-format/` + ); + return; + } + + storyExports.forEach((key) => { if (isExportStory(key, meta)) { const storyFn = exports[key]; const { name, parameters, decorators, args, argTypes } = storyFn.story || {};