Added basic global args mechanism to story_store

This commit is contained in:
Tom Coleman 2020-02-27 13:27:27 +11:00
parent c64b99d6b8
commit d75b4e09a0
4 changed files with 143 additions and 11 deletions

View File

@ -85,7 +85,7 @@ describe('preview.story_store', () => {
});
describe('args', () => {
it('args is initialized to the value stored in parameters.args[name] || parameters.argType[name].defaultValue', () => {
it('is initialized to the value stored in parameters.args[name] || parameters.argType[name].defaultValue', () => {
const store = new StoryStore({ channel });
addStoryToStore(store, 'a', '1', () => 0, {
argTypes: {
@ -201,6 +201,111 @@ describe('preview.story_store', () => {
});
});
describe('globalArgs', () => {
it.skip('is initialized to the value stored in parameters.globalArgTypes[name].defaultValue', () => {
const store = new StoryStore({ channel });
addStoryToStore(store, 'a', '1', () => 0, {
argTypes: {
arg1: { defaultValue: 'arg1' },
arg2: { defaultValue: 2 },
arg3: { defaultValue: { complex: { object: ['type'] } } },
},
});
expect(store.getRawStory('a', '1').args).toEqual({
arg1: 'arg1',
arg2: 2,
arg3: { complex: { object: ['type'] } },
});
});
it('setGlobalArgs changes the global args', () => {
const store = new StoryStore({ channel });
addStoryToStore(store, 'a', '1', () => 0);
expect(store.getRawStory('a', '1').globalArgs).toEqual({});
store.setGlobalArgs({ foo: 'bar' });
expect(store.getRawStory('a', '1').globalArgs).toEqual({ foo: 'bar' });
store.setGlobalArgs({ baz: 'bing' });
expect(store.getRawStory('a', '1').globalArgs).toEqual({ foo: 'bar', baz: 'bing' });
});
it('is passed to the story in the context', () => {
const storyFn = jest.fn();
const store = new StoryStore({ channel });
store.setGlobalArgs({ foo: 'bar' });
addStoryToStore(store, 'a', '1', storyFn);
store.getRawStory('a', '1').storyFn();
expect(storyFn).toHaveBeenCalledWith(
expect.objectContaining({
globalArgs: { foo: 'bar' },
})
);
store.setGlobalArgs({ baz: 'bing' });
store.getRawStory('a', '1').storyFn();
expect(storyFn).toHaveBeenCalledWith(
expect.objectContaining({
globalArgs: { foo: 'bar', baz: 'bing' },
})
);
});
it('setGlobalArgs emits GLOBAL_ARGS_CHANGED', () => {
const onGlobalArgsChangedChannel = jest.fn();
const testChannel = mockChannel();
testChannel.on(Events.GLOBAL_ARGS_CHANGED, onGlobalArgsChangedChannel);
const store = new StoryStore({ channel: testChannel });
addStoryToStore(store, 'a', '1', () => 0);
store.setGlobalArgs({ foo: 'bar' });
expect(onGlobalArgsChangedChannel).toHaveBeenCalledWith({ foo: 'bar' });
store.setGlobalArgs({ baz: 'bing' });
expect(onGlobalArgsChangedChannel).toHaveBeenCalledWith({ foo: 'bar', baz: 'bing' });
});
it('should update if the CHANGE_GLOBAL_ARGS event is received', () => {
const testChannel = mockChannel();
const store = new StoryStore({ channel: testChannel });
addStoryToStore(store, 'a', '1', () => 0);
testChannel.emit(Events.CHANGE_GLOBAL_ARGS, { foo: 'bar' });
expect(store.getRawStory('a', '1').globalArgs).toEqual({ foo: 'bar' });
});
it('DOES NOT pass globalArgs as the first argument to the story if `parameters.passArgsFirst` is true', () => {
const store = new StoryStore({ channel });
const storyOne = jest.fn();
addStoryToStore(store, 'a', '1', storyOne);
store.setGlobalArgs({ foo: 'bar' });
store.getRawStory('a', '1').storyFn();
expect(storyOne).toHaveBeenCalledWith(
expect.objectContaining({
globalArgs: { foo: 'bar' },
})
);
const storyTwo = jest.fn();
addStoryToStore(store, 'a', '2', storyTwo, { passArgsFirst: true });
store.getRawStory('a', '2').storyFn();
expect(storyTwo).toHaveBeenCalledWith(
{},
expect.objectContaining({
globalArgs: { foo: 'bar' },
})
);
});
});
describe('parameterEnhancer', () => {
it('allows you to alter parameters when stories are added', () => {
const store = new StoryStore({ channel });

View File

@ -22,6 +22,7 @@ import {
StoreData,
AddStoryArgs,
StoreItem,
PublishedStoreItem,
ErrorLike,
GetStorybookKind,
ParameterEnhancer,
@ -75,6 +76,8 @@ export default class StoryStore {
_configuring: boolean;
_globalArgs: Args;
_globalMetadata: StoryMetadata;
// Keyed on kind name
@ -92,6 +95,8 @@ export default class StoryStore {
constructor(params: { channel: Channel }) {
// Assume we are configuring until we hear otherwise
this._configuring = true;
this._globalArgs = {};
this._globalMetadata = { parameters: {}, decorators: [] };
this._kinds = {};
this._stories = {};
@ -115,6 +120,10 @@ export default class StoryStore {
this._channel.on(Events.CHANGE_STORY_ARGS, (id: string, newArgs: Args) =>
this.setStoryArgs(id, newArgs)
);
this._channel.on(Events.CHANGE_GLOBAL_ARGS, (newGlobalArgs: Args) =>
this.setGlobalArgs(newGlobalArgs)
);
}
startConfiguring() {
@ -247,6 +256,7 @@ export default class StoryStore {
parameters,
hooks,
args: _stories[id].args,
globalArgs: this._globalArgs,
});
// Pull out parameters.args.$ || .argTypes.$.defaultValue into initialArgs
@ -306,7 +316,20 @@ export default class StoryStore {
}, {});
}
fromId = (id: string): StoreItem | null => {
setGlobalArgs(newGlobalArgs: Args) {
this._globalArgs = { ...this._globalArgs, ...newGlobalArgs };
this._channel.emit(Events.GLOBAL_ARGS_CHANGED, this._globalArgs);
}
setStoryArgs(id: string, newArgs: Args) {
if (!this._stories[id]) throw new Error(`No story for id ${id}`);
const { args } = this._stories[id];
this._stories[id].args = { ...args, ...newArgs };
this._channel.emit(Events.STORY_ARGS_CHANGED, id, this._stories[id].args);
}
fromId = (id: string): PublishedStoreItem | null => {
try {
const data = this._stories[id as string];
@ -314,7 +337,10 @@ export default class StoryStore {
return null;
}
return data;
return {
...data,
globalArgs: this._globalArgs,
};
} catch (e) {
logger.warn('failed to get story:', this._stories);
logger.error(e);
@ -434,14 +460,6 @@ export default class StoryStore {
this.getStoriesForKind(kind).map(story => this.cleanHooks(story.id));
}
setStoryArgs(id: string, newArgs: Args) {
if (!this._stories[id]) throw new Error(`No story for id ${id}`);
const { args } = this._stories[id];
this._stories[id].args = { ...args, ...newArgs };
this._channel.emit(Events.STORY_ARGS_CHANGED, id, this._stories[id].args);
}
// This API is a reimplementation of Storybook's original getStorybook() API.
// As such it may not behave *exactly* the same, but aims to. Some notes:
// - It is *NOT* sorted by the user's sort function, but remains sorted in "insertion order"

View File

@ -39,6 +39,10 @@ export type StoreItem = StoryIdentifier & {
args: Args;
};
export type PublishedStoreItem = StoreItem & {
globalArgs: Args;
};
export interface StoreData {
[key: string]: StoreItem;
}

View File

@ -23,6 +23,9 @@ enum events {
CHANGE_STORY_ARGS = 'changeStoryArgs',
// The values of a stories args just changed
STORY_ARGS_CHANGED = 'storyArgsChanged',
// As above
CHANGE_GLOBAL_ARGS = 'changeGlobalArgs',
GLOBAL_ARGS_CHANGED = 'globalArgsChanged',
REGISTER_SUBSCRIPTION = 'registerSubscription',
// Tell the manager that the user pressed a key in the preview
PREVIEW_KEYDOWN = 'previewKeydown',
@ -56,6 +59,8 @@ export const {
STORY_THREW_EXCEPTION,
CHANGE_STORY_ARGS,
STORY_ARGS_CHANGED,
CHANGE_GLOBAL_ARGS,
GLOBAL_ARGS_CHANGED,
REGISTER_SUBSCRIPTION,
PREVIEW_KEYDOWN,
SELECT_STORY,