Update store/preview to take project annotations on init.

This way they can be set on `window` at boot time.
This commit is contained in:
Tom Coleman 2021-09-13 17:03:21 +10:00
parent a1e1ec6245
commit dcdf150b88
10 changed files with 264 additions and 250 deletions

View File

@ -22,14 +22,14 @@ const fetchStoryIndex = async () => {
const channel = createChannel({ page: 'preview' });
addons.setChannel(channel);
const preview = new PreviewWeb({ importFn, getProjectAnnotations, fetchStoryIndex });
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
window.__STORYBOOK_PREVIEW__ = preview;
window.__STORYBOOK_STORY_STORE__ = preview.storyStore;
window.__STORYBOOK_ADDONS_CHANNEL__ = channel;
window.__STORYBOOK_CLIENT_API__ = new ClientApi({ storyStore: preview.storyStore });
preview.initialize();
preview.initialize({ getProjectAnnotations });
if (module.hot) {
module.hot.accept('./{{storiesFilename}}', () => {

View File

@ -7,7 +7,6 @@ import createChannel from '@storybook/channel-postmessage';
import { importFn } from './{{storiesFilename}}';
const getProjectAnnotations = () =>
composeConfigs([
{{#each configs}}
@ -23,14 +22,14 @@ const fetchStoryIndex = async () => {
const channel = createChannel({ page: 'preview' });
addons.setChannel(channel);
const preview = new PreviewWeb({ importFn, getProjectAnnotations, fetchStoryIndex });
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
window.__STORYBOOK_PREVIEW__ = preview;
window.__STORYBOOK_STORY_STORE__ = preview.storyStore;
window.__STORYBOOK_ADDONS_CHANNEL__ = channel;
window.__STORYBOOK_CLIENT_API__ = new ClientApi({ storyStore: preview.storyStore });
preview.initialize();
preview.initialize({ getProjectAnnotations });
if (module.hot) {
module.hot.accept('./{{storiesFilename}}', () => {

View File

@ -25,12 +25,22 @@ export function start<TFramework extends AnyFramework>(
const channel = createChannel({ page: 'preview' });
addons.setChannel(channel);
let preview: PreviewWeb<TFramework>;
const clientApi = new ClientApi<TFramework>();
const preview = new PreviewWeb<TFramework>({
importFn: (path: Path) => clientApi.importFn(path),
fetchStoryIndex: () => clientApi.fetchStoryIndex(),
});
// These two bits are a bit ugly, but due to dependencies, `ClientApi` cannot have
// direct reference to `PreviewWeb`, so we need to patch in bits
clientApi.onImportFnChanged = preview.onImportFnChanged.bind(preview);
clientApi.storyStore = preview.storyStore;
if (globalWindow) {
globalWindow.__STORYBOOK_CLIENT_API__ = clientApi;
globalWindow.__STORYBOOK_ADDONS_CHANNEL__ = channel;
// eslint-disable-next-line no-underscore-dangle
globalWindow.__STORYBOOK_PREVIEW__ = preview;
globalWindow.__STORYBOOK_STORY_STORE__ = preview.storyStore;
}
return {
@ -66,23 +76,7 @@ export function start<TFramework extends AnyFramework>(
};
if (!preview) {
preview = new PreviewWeb({
importFn: (path: Path) => clientApi.importFn(path),
getProjectAnnotations,
fetchStoryIndex: () => clientApi.fetchStoryIndex(),
});
if (globalWindow) {
// eslint-disable-next-line no-underscore-dangle
globalWindow.__STORYBOOK_PREVIEW__ = preview;
globalWindow.__STORYBOOK_STORY_STORE__ = preview.storyStore;
}
// These two bits are a bit ugly, but due to dependencies, `ClientApi` cannot have
// direct reference to `PreviewWeb`, so we need to patch in bits
clientApi.onImportFnChanged = preview.onImportFnChanged.bind(preview);
clientApi.storyStore = preview.storyStore;
preview.initialize({ cacheAllCSFFiles: true, sync: true });
preview.initialize({ getProjectAnnotations, cacheAllCSFFiles: true, sync: true });
} else {
getProjectAnnotations();
preview.onImportFnChanged({ importFn: (path: Path) => clientApi.importFn(path) });

View File

@ -61,7 +61,7 @@ describe('PreviewWeb', () => {
storyFn()
);
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -71,7 +71,7 @@ describe('PreviewWeb', () => {
it('renders docs mode through docs page', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
const docsRoot = window.document.createElement('div');
// @ts-ignore
@ -80,7 +80,7 @@ describe('PreviewWeb', () => {
React.createElement('div', {}, 'INSIDE')
);
await preview.initialize();
await preview.initialize({ getProjectAnnotations });
await waitForRender();
expect(docsRoot.outerHTML).toMatchInlineSnapshot(`
@ -106,8 +106,8 @@ describe('PreviewWeb', () => {
it('renders story mode through the updated stack', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
projectAnnotations.renderToDOM.mockImplementationOnce(({ storyFn }: RenderContext<any>) =>

View File

@ -71,11 +71,13 @@ describe('PreviewWeb', () => {
it('shows an error if getProjectAnnotations throws', async () => {
const err = new Error('meta error');
const preview = new PreviewWeb({
importFn,
fetchStoryIndex,
});
preview.initialize({
getProjectAnnotations: () => {
throw err;
},
importFn,
fetchStoryIndex,
});
expect(preview.view.showErrorDisplay).toHaveBeenCalled();
@ -87,14 +89,14 @@ describe('PreviewWeb', () => {
it('sets globals from the URL', async () => {
document.location.search = '?id=*&globals=a:c';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.storyStore.globals.get()).toEqual({ a: 'c' });
});
it('emits the SET_GLOBALS event', async () => {
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {
globals: { a: 'b' },
@ -104,10 +106,9 @@ describe('PreviewWeb', () => {
it('SET_GLOBALS sets globals and types even when undefined', async () => {
await new PreviewWeb({
getProjectAnnotations: () => ({}),
importFn,
fetchStoryIndex,
}).initialize();
}).initialize({ getProjectAnnotations: () => ({}) });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {
globals: {},
@ -118,7 +119,7 @@ describe('PreviewWeb', () => {
it('emits the SET_GLOBALS event from the URL', async () => {
document.location.search = '?id=*&globals=a:c';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {
globals: { a: 'c' },
@ -129,8 +130,8 @@ describe('PreviewWeb', () => {
it('sets args from the URL', async () => {
document.location.search = '?id=component-one--a&args=foo:url';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.storyStore.args.get('component-one--a')).toEqual({
foo: 'url',
@ -142,8 +143,8 @@ describe('PreviewWeb', () => {
it('selects the story specified in the URL', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.urlStore.selection).toEqual({
storyId: 'component-one--a',
@ -159,7 +160,7 @@ describe('PreviewWeb', () => {
it('emits the STORY_SPECIFIED event', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_SPECIFIED, {
storyId: 'component-one--a',
@ -170,7 +171,7 @@ describe('PreviewWeb', () => {
it('emits the CURRENT_STORY_WAS_SET event', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, {
storyId: 'component-one--a',
@ -182,8 +183,8 @@ describe('PreviewWeb', () => {
it('renders missing', async () => {
document.location.search = '?id=random';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.showNoPreview).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'random');
@ -193,8 +194,8 @@ describe('PreviewWeb', () => {
it.skip('tries again with a specifier if CSF file changes', async () => {
document.location.search = '?id=component-one--d';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.showNoPreview).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d');
@ -220,8 +221,8 @@ describe('PreviewWeb', () => {
it.skip('DOES NOT try again if CSF file changes if selection changed', async () => {
document.location.search = '?id=component-one--d';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.showNoPreview).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d');
@ -250,8 +251,8 @@ describe('PreviewWeb', () => {
it.skip('tries again with a specifier if stories list changes', async () => {
document.location.search = '?id=component-three--d';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.showNoPreview).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-three--d');
@ -265,8 +266,8 @@ describe('PreviewWeb', () => {
});
it('renders missing if no selection', async () => {
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.showNoPreview).toHaveBeenCalled();
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, undefined);
@ -276,8 +277,8 @@ describe('PreviewWeb', () => {
it('calls view.prepareForStory', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.prepareForStory).toHaveBeenCalledWith(
expect.objectContaining({
@ -288,7 +289,7 @@ describe('PreviewWeb', () => {
it('emits STORY_PREPARED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {
id: 'component-one--a',
@ -301,7 +302,7 @@ describe('PreviewWeb', () => {
it('applies loaders with story context', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -318,7 +319,7 @@ describe('PreviewWeb', () => {
it('passes loaded context to renderToDOM', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -346,8 +347,8 @@ describe('PreviewWeb', () => {
});
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
@ -362,8 +363,8 @@ describe('PreviewWeb', () => {
});
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
@ -378,8 +379,8 @@ describe('PreviewWeb', () => {
});
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
@ -394,8 +395,8 @@ describe('PreviewWeb', () => {
);
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
@ -413,8 +414,8 @@ describe('PreviewWeb', () => {
);
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
@ -424,7 +425,7 @@ describe('PreviewWeb', () => {
it('executes runPlayFunction', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -433,7 +434,7 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -445,8 +446,8 @@ describe('PreviewWeb', () => {
it('calls view.prepareForDocs', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
expect(preview.view.prepareForDocs).toHaveBeenCalled();
});
@ -454,7 +455,7 @@ describe('PreviewWeb', () => {
it('render the docs container with the correct context', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -477,7 +478,7 @@ describe('PreviewWeb', () => {
it('emits DOCS_RENDERED', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -489,7 +490,7 @@ describe('PreviewWeb', () => {
describe('onUpdateGlobals', () => {
it('emits GLOBALS_UPDATED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });
@ -501,8 +502,8 @@ describe('PreviewWeb', () => {
it('sets new globals on the store', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });
@ -511,8 +512,8 @@ describe('PreviewWeb', () => {
it('passes new globals in context to renderToDOM', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -533,7 +534,7 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -547,7 +548,7 @@ describe('PreviewWeb', () => {
describe('onUpdateArgs', () => {
it('emits STORY_ARGS_UPDATED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -562,8 +563,8 @@ describe('PreviewWeb', () => {
it('sets new args on the store', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -578,8 +579,8 @@ describe('PreviewWeb', () => {
it('passes new args in context to renderToDOM', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -604,7 +605,7 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -623,7 +624,7 @@ describe('PreviewWeb', () => {
document.location.search = '?id=component-one--a';
componentOneExports.default.loaders[0].mockImplementationOnce(async () => gate);
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -653,7 +654,7 @@ describe('PreviewWeb', () => {
document.location.search = '?id=component-one--a';
projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate);
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -695,7 +696,7 @@ describe('PreviewWeb', () => {
updatedArgs: { new: 'arg' },
});
});
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
@ -733,7 +734,7 @@ describe('PreviewWeb', () => {
});
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await renderToDOMCalled;
// Story gets rendered with original args
@ -777,7 +778,7 @@ describe('PreviewWeb', () => {
describe('onResetArgs', () => {
it('emits STORY_ARGS_UPDATED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
mockChannel.emit.mockClear();
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -805,7 +806,7 @@ describe('PreviewWeb', () => {
it('resets a single arg', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
mockChannel.emit.mockClear();
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
@ -839,7 +840,7 @@ describe('PreviewWeb', () => {
it('resets all args', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.UPDATE_STORY_ARGS, {
storyId: 'component-one--a',
updatedArgs: { foo: 'new', new: 'value' },
@ -872,8 +873,8 @@ describe('PreviewWeb', () => {
describe('on FORCE_RE_RENDER', () => {
it('rerenders the story with the same args', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -891,7 +892,7 @@ describe('PreviewWeb', () => {
describe('onSetCurrentStory', () => {
it('updates URL', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--b',
@ -907,7 +908,7 @@ describe('PreviewWeb', () => {
it('emits CURRENT_STORY_WAS_SET', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--b',
@ -922,8 +923,8 @@ describe('PreviewWeb', () => {
it('renders missing if the story specified does not exist', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'random',
@ -938,8 +939,8 @@ describe('PreviewWeb', () => {
describe('if the selection is unchanged', () => {
it('emits STORY_UNCHANGED', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--a',
@ -952,8 +953,8 @@ describe('PreviewWeb', () => {
it('does NOT call renderToDOM', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
projectAnnotations.renderToDOM.mockClear();
@ -971,7 +972,7 @@ describe('PreviewWeb', () => {
describe('when changing story in story viewMode', () => {
it('updates URL', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--b',
@ -987,7 +988,7 @@ describe('PreviewWeb', () => {
it('emits STORY_CHANGED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1002,7 +1003,7 @@ describe('PreviewWeb', () => {
it('emits STORY_PREPARED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1023,7 +1024,7 @@ describe('PreviewWeb', () => {
it('applies loaders with story context', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1046,7 +1047,7 @@ describe('PreviewWeb', () => {
it('passes loaded context to renderToDOM', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1075,8 +1076,8 @@ describe('PreviewWeb', () => {
it('renders exception if renderToDOM throws', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = new Error('error');
@ -1097,8 +1098,8 @@ describe('PreviewWeb', () => {
it('renders error if the story calls showError', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = { title: 'title', description: 'description' };
@ -1122,8 +1123,8 @@ describe('PreviewWeb', () => {
it('renders exception if the story calls showException', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = new Error('error');
@ -1144,7 +1145,7 @@ describe('PreviewWeb', () => {
it('executes runPlayFunction', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1159,7 +1160,7 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1174,8 +1175,8 @@ describe('PreviewWeb', () => {
it('retains any arg changes', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1215,7 +1216,7 @@ describe('PreviewWeb', () => {
componentOneExports.default.loaders[0].mockImplementationOnce(async () => gate);
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--b',
@ -1246,7 +1247,7 @@ describe('PreviewWeb', () => {
document.location.search = '?id=component-one--a';
projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate);
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--b',
@ -1279,7 +1280,7 @@ describe('PreviewWeb', () => {
});
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await renderToDOMCalled;
// Story gets rendered with original args
@ -1328,7 +1329,7 @@ describe('PreviewWeb', () => {
describe('when changing from story viewMode to docs', () => {
it('updates URL', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--a',
@ -1344,7 +1345,7 @@ describe('PreviewWeb', () => {
it('emits STORY_CHANGED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1359,8 +1360,8 @@ describe('PreviewWeb', () => {
it('calls view.prepareForDocs', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1375,7 +1376,7 @@ describe('PreviewWeb', () => {
it('render the docs container with the correct context', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1403,7 +1404,7 @@ describe('PreviewWeb', () => {
it('emits DOCS_RENDERED', async () => {
document.location.search = '?id=component-one--a';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1420,7 +1421,7 @@ describe('PreviewWeb', () => {
describe('when changing from docs viewMode to story', () => {
it('updates URL', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
emitter.emit(Events.SET_CURRENT_STORY, {
storyId: 'component-one--a',
@ -1436,7 +1437,7 @@ describe('PreviewWeb', () => {
it('unmounts docs', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1452,7 +1453,7 @@ describe('PreviewWeb', () => {
// NOTE: I am not sure this entirely makes sense but this is the behaviour from 6.3
it('emits STORY_CHANGED', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1467,8 +1468,8 @@ describe('PreviewWeb', () => {
it('calls view.prepareForStory', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1487,7 +1488,7 @@ describe('PreviewWeb', () => {
it('emits STORY_PREPARED', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1508,7 +1509,7 @@ describe('PreviewWeb', () => {
it('applies loaders with story context', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1531,7 +1532,7 @@ describe('PreviewWeb', () => {
it('passes loaded context to renderToDOM', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1560,8 +1561,8 @@ describe('PreviewWeb', () => {
it('renders exception if renderToDOM throws', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = new Error('error');
@ -1587,8 +1588,8 @@ describe('PreviewWeb', () => {
);
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1612,8 +1613,8 @@ describe('PreviewWeb', () => {
);
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1629,7 +1630,7 @@ describe('PreviewWeb', () => {
it('executes runPlayFunction', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1644,7 +1645,7 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
await new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex }).initialize();
await new PreviewWeb({ importFn, fetchStoryIndex }).initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1672,8 +1673,8 @@ describe('PreviewWeb', () => {
it('does not emit STORY_UNCHANGED', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1688,8 +1689,8 @@ describe('PreviewWeb', () => {
it('does not emit STORY_CHANGED', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1701,8 +1702,8 @@ describe('PreviewWeb', () => {
it('emits STORY_PREPARED with new annotations', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1720,8 +1721,8 @@ describe('PreviewWeb', () => {
it('applies loaders with story context', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1742,8 +1743,8 @@ describe('PreviewWeb', () => {
it('passes loaded context to renderToDOM', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1770,8 +1771,8 @@ describe('PreviewWeb', () => {
it('retains the same delta to the args', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
emitter.emit(Events.UPDATE_STORY_ARGS, {
@ -1799,8 +1800,8 @@ describe('PreviewWeb', () => {
it('renders exception if renderToDOM throws', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = new Error('error');
@ -1818,8 +1819,8 @@ describe('PreviewWeb', () => {
it('renders error if the story calls showError', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = { title: 'title', description: 'description' };
@ -1840,8 +1841,8 @@ describe('PreviewWeb', () => {
it('renders exception if the story calls showException', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
const error = new Error('error');
@ -1859,8 +1860,8 @@ describe('PreviewWeb', () => {
it('executes runPlayFunction', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1873,8 +1874,8 @@ describe('PreviewWeb', () => {
it('emits STORY_RENDERED', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1895,8 +1896,8 @@ describe('PreviewWeb', () => {
it('emits STORY_UNCHANGED', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1909,8 +1910,8 @@ describe('PreviewWeb', () => {
it('does not re-render the story', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1936,8 +1937,8 @@ describe('PreviewWeb', () => {
it('renders story missing', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1950,8 +1951,8 @@ describe('PreviewWeb', () => {
it('does not re-render the story', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1971,8 +1972,8 @@ describe('PreviewWeb', () => {
describe('onGetProjectAnnotationsChanged', () => {
it('shows an error the new value throws', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -1999,8 +2000,8 @@ describe('PreviewWeb', () => {
it('updates globals to their new values', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -2012,8 +2013,8 @@ describe('PreviewWeb', () => {
it('updates args to their new values', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
mockChannel.emit.mockClear();
@ -2029,8 +2030,8 @@ describe('PreviewWeb', () => {
it('rerenders the current story with new global meta-generated context', async () => {
document.location.search = '?id=component-one--a';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
await waitForRender();
projectAnnotations.renderToDOM.mockClear();
@ -2053,8 +2054,8 @@ describe('PreviewWeb', () => {
describe('onKeydown', () => {
it('emits PREVIEW_KEYDOWN for regular elements', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
preview.onKeydown({
target: { tagName: 'div', getAttribute: jest.fn().mockReturnValue(null) },
@ -2068,8 +2069,8 @@ describe('PreviewWeb', () => {
it('does not emit PREVIEW_KEYDOWN for input elements', async () => {
document.location.search = '?id=component-one--a&viewMode=docs';
const preview = new PreviewWeb({ getProjectAnnotations, importFn, fetchStoryIndex });
await preview.initialize();
const preview = new PreviewWeb({ importFn, fetchStoryIndex });
await preview.initialize({ getProjectAnnotations });
preview.onKeydown({
target: { tagName: 'input', getAttribute: jest.fn().mockReturnValue(null) },

View File

@ -57,21 +57,41 @@ export class PreviewWeb<TFramework extends AnyFramework> {
previousCleanup: () => void;
constructor({
getProjectAnnotations,
importFn,
fetchStoryIndex,
}: {
getProjectAnnotations: () => WebProjectAnnotations<TFramework>;
importFn: ModuleImportFn;
fetchStoryIndex: ConstructorParameters<typeof StoryStore>[0]['fetchStoryIndex'];
}) {
this.channel = addons.getChannel();
this.view = new WebView();
this.urlStore = new UrlStore();
this.storyStore = new StoryStore({ importFn, fetchStoryIndex });
}
// We have a second "sync" code path through `initialize` for back-compat reasons.
// Specifically Storyshots requires the story store to be syncronously loaded completely on bootup
initialize({
getProjectAnnotations,
cacheAllCSFFiles = false,
sync = false,
}: {
getProjectAnnotations: () => WebProjectAnnotations<TFramework>;
cacheAllCSFFiles?: boolean;
sync?: boolean;
}): MaybePromise<void> {
const projectAnnotations = this.getProjectAnnotationsOrRenderError(getProjectAnnotations) || {};
this.urlStore = new UrlStore();
this.storyStore = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
if (sync) {
this.storyStore.initialize({ projectAnnotations, cacheAllCSFFiles, sync: true });
// NOTE: we don't await this, but return the promise so the caller can await it if they want
return this.setupListenersAndRenderSelection();
}
return this.storyStore
.initialize({ projectAnnotations, cacheAllCSFFiles, sync: false })
.then(() => this.setupListenersAndRenderSelection());
}
getProjectAnnotationsOrRenderError(
@ -91,23 +111,6 @@ export class PreviewWeb<TFramework extends AnyFramework> {
}
}
// We have a second "sync" code path through `initialize` for back-compat reasons.
// Specifically Storyshots requires the story store to be syncronously loaded completely on bootup
initialize({
cacheAllCSFFiles = false,
sync = false,
}: { cacheAllCSFFiles?: boolean; sync?: boolean } = {}): MaybePromise<void> {
if (sync) {
this.storyStore.initialize({ cacheAllCSFFiles, sync: true });
// NOTE: we don't await this, but return the promise so the caller can await it if they want
return this.setupListenersAndRenderSelection();
}
return this.storyStore
.initialize({ cacheAllCSFFiles, sync: false })
.then(() => this.setupListenersAndRenderSelection());
}
async setupListenersAndRenderSelection() {
this.setupListeners();

View File

@ -2,7 +2,8 @@ import { GlobalsStore } from './GlobalsStore';
describe('GlobalsStore', () => {
it('is initialized to the value in globals', () => {
const store = new GlobalsStore({
const store = new GlobalsStore();
store.initialize({
globals: {
arg1: 'arg1',
arg2: 2,
@ -19,7 +20,8 @@ describe('GlobalsStore', () => {
});
it('is initialized to the default values from globalTypes if global is unset', () => {
const store = new GlobalsStore({
const store = new GlobalsStore();
store.initialize({
globals: {
arg1: 'arg1',
arg2: 2,
@ -40,7 +42,8 @@ describe('GlobalsStore', () => {
describe('update', () => {
it('changes the global args', () => {
const store = new GlobalsStore({ globals: { foo: 'old' }, globalTypes: { baz: {} } });
const store = new GlobalsStore();
store.initialize({ globals: { foo: 'old' }, globalTypes: { baz: {} } });
store.update({ foo: 'bar' });
expect(store.get()).toEqual({ foo: 'bar' });
@ -54,7 +57,8 @@ describe('GlobalsStore', () => {
});
it('does not merge objects', () => {
const store = new GlobalsStore({ globals: {}, globalTypes: {} });
const store = new GlobalsStore();
store.initialize({ globals: {}, globalTypes: {} });
store.update({ obj: { foo: 'bar' } });
expect(store.get()).toEqual({ obj: { foo: 'bar' } });
@ -66,7 +70,8 @@ describe('GlobalsStore', () => {
describe('updateFromPersisted', () => {
it('only sets values for which globals or globalArgs exist', () => {
const store = new GlobalsStore({
const store = new GlobalsStore();
store.initialize({
globals: {
arg1: 'arg1',
},
@ -87,7 +92,8 @@ describe('GlobalsStore', () => {
describe('resetOnProjectAnnotationsChange', () => {
it('is initialized to the (new) default values from globalTypes if the (new) global is unset', () => {
const store = new GlobalsStore({ globals: {}, globalTypes: {} });
const store = new GlobalsStore();
store.initialize({ globals: {}, globalTypes: {} });
expect(store.get()).toEqual({});
@ -112,7 +118,8 @@ describe('GlobalsStore', () => {
describe('when underlying globals have not changed', () => {
it('retains updated values, but not if they are undeclared', () => {
const store = new GlobalsStore({
const store = new GlobalsStore();
store.initialize({
globals: {
arg1: 'arg1',
},
@ -145,7 +152,8 @@ describe('GlobalsStore', () => {
describe('when underlying globals have changed', () => {
it('retains a the same delta', () => {
const store = new GlobalsStore({
const store = new GlobalsStore();
store.initialize({
globals: {
arg1: 'arg1',
arg4: 'arg4',

View File

@ -21,7 +21,7 @@ export class GlobalsStore {
// NOTE: globals are initialized every time the preview entries are loaded
// This happens both initially when the SB first loads, and also on HMR
constructor({ globals, globalTypes }: { globals: Globals; globalTypes: GlobalTypes }) {
initialize({ globals, globalTypes }: { globals: Globals; globalTypes: GlobalTypes }) {
this.setInitialGlobals({ globals, globalTypes });
this.globals = this.initialGlobals;
}

View File

@ -67,8 +67,8 @@ const fetchStoryIndex = async () => storyIndex;
describe('StoryStore', () => {
describe('projectAnnotations', () => {
it('normalizes on initialization', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
expect(store.projectAnnotations.globalTypes).toEqual({
a: { name: 'a', type: { name: 'string' } },
@ -79,8 +79,8 @@ describe('StoryStore', () => {
});
it('normalizes on updateGlobalAnnotations', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
store.updateProjectAnnotations(projectAnnotations);
expect(store.projectAnnotations.globalTypes).toEqual({
@ -94,8 +94,8 @@ describe('StoryStore', () => {
describe('loadStory', () => {
it('pulls the story via the importFn', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
importFn.mockClear();
expect(await store.loadStory({ storyId: 'component-one--a' })).toMatchObject({
@ -108,8 +108,8 @@ describe('StoryStore', () => {
});
it('uses a cache', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const story = await store.loadStory({ storyId: 'component-one--a' });
expect(processCSFFile).toHaveBeenCalledTimes(1);
@ -132,8 +132,8 @@ describe('StoryStore', () => {
describe('componentStoriesFromCSFFile', () => {
it('returns all the stories in the file', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const csfFile = await store.loadCSFFileByStoryId('component-one--a', { sync: false });
const stories = store.componentStoriesFromCSFFile({ csfFile });
@ -145,8 +145,8 @@ describe('StoryStore', () => {
describe('getStoryContext', () => {
it('returns the args and globals correctly', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const story = await store.loadStory({ storyId: 'component-one--a' });
@ -157,8 +157,8 @@ describe('StoryStore', () => {
});
it('returns the args and globals correctly when they change', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const story = await store.loadStory({ storyId: 'component-one--a' });
@ -172,8 +172,8 @@ describe('StoryStore', () => {
});
it('returns the same hooks each time', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const story = await store.loadStory({ storyId: 'component-one--a' });
@ -184,8 +184,8 @@ describe('StoryStore', () => {
describe('cleanupStory', () => {
it('cleans the hooks from the context', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
const story = await store.loadStory({ storyId: 'component-one--a' });
@ -198,8 +198,8 @@ describe('StoryStore', () => {
describe('loadAllCSFFiles', () => {
it('imports *all* csf files', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
importFn.mockClear();
const csfFiles = await store.loadAllCSFFiles(false);
@ -213,15 +213,15 @@ describe('StoryStore', () => {
describe('extract', () => {
it('throws if you have not called cacheAllCSFFiles', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
expect(() => store.extract()).toThrow(/Cannot call extract/);
});
it('produces objects with functions and hooks stripped', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
await store.cacheAllCSFFiles(false);
expect(store.extract()).toMatchInlineSnapshot(`
@ -340,10 +340,9 @@ describe('StoryStore', () => {
});
const store = new StoryStore({
importFn: docsOnlyImportFn,
projectAnnotations,
fetchStoryIndex,
});
await store.initialize({ sync: false });
await store.initialize({ projectAnnotations, sync: false });
await store.cacheAllCSFFiles(false);
expect((store.extract() as { id: StoryId }[]).map((s) => s.id)).toEqual([
@ -359,8 +358,8 @@ describe('StoryStore', () => {
describe('getSetStoriesPayload', () => {
it('maps stories list to payload correctly', async () => {
const store = new StoryStore({ importFn, projectAnnotations, fetchStoryIndex });
await store.initialize({ sync: false });
const store = new StoryStore({ importFn, fetchStoryIndex });
await store.initialize({ projectAnnotations, sync: false });
await store.cacheAllCSFFiles(false);
expect(store.getSetStoriesPayload()).toMatchInlineSnapshot(`

View File

@ -80,19 +80,15 @@ export class StoryStore<TFramework extends AnyFramework> {
constructor({
importFn,
projectAnnotations,
fetchStoryIndex,
}: {
importFn: ModuleImportFn;
projectAnnotations: ProjectAnnotations<TFramework>;
fetchStoryIndex: ConstructorParameters<typeof StoryIndexStore>[0]['fetchStoryIndex'];
}) {
this.storyIndex = new StoryIndexStore({ fetchStoryIndex });
this.importFn = importFn;
this.projectAnnotations = normalizeProjectAnnotations(projectAnnotations);
const { globals, globalTypes } = projectAnnotations;
this.globals = new GlobalsStore({ globals, globalTypes });
this.globals = new GlobalsStore();
this.args = new ArgsStore();
this.hooks = {};
@ -104,17 +100,31 @@ export class StoryStore<TFramework extends AnyFramework> {
}
// See note in PreviewWeb about the 'sync' init path.
initialize(options: { sync: false; cacheAllCSFFiles?: boolean }): Promise<void>;
initialize(options: {
projectAnnotations: ProjectAnnotations<TFramework>;
sync: false;
cacheAllCSFFiles?: boolean;
}): Promise<void>;
initialize(options: { sync: true; cacheAllCSFFiles?: boolean }): void;
initialize(options: {
projectAnnotations: ProjectAnnotations<TFramework>;
sync: true;
cacheAllCSFFiles?: boolean;
}): void;
initialize({
projectAnnotations,
sync = false,
cacheAllCSFFiles = false,
}: {
projectAnnotations: ProjectAnnotations<TFramework>;
sync?: boolean;
cacheAllCSFFiles?: boolean;
} = {}): MaybePromise<void> {
}): MaybePromise<void> {
this.projectAnnotations = normalizeProjectAnnotations(projectAnnotations);
const { globals, globalTypes } = this.projectAnnotations;
this.globals.initialize({ globals, globalTypes });
if (sync) {
this.storyIndex.initialize({ sync: true });
if (cacheAllCSFFiles) {