Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Core: Restore Docs useParameter using DOCS_PREPARED #22118

Merged
merged 7 commits into from
Apr 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
32 changes: 30 additions & 2 deletions code/e2e-tests/addon-backgrounds.spec.ts
Expand Up @@ -10,11 +10,14 @@ test.describe('addon-backgrounds', () => {
await new SbPage(page).waitUntilLoaded();
});

const backgroundToolbarSelector = '[title="Change the background of the preview"]';
const gridToolbarSelector = '[title="Apply a grid to the preview"]';

test('should have a dark background', async ({ page }) => {
const sbPage = new SbPage(page);

await sbPage.navigateToStory('example/button', 'primary');
await sbPage.selectToolbar('[title="Change the background of the preview"]', '#list-item-dark');
await sbPage.selectToolbar(backgroundToolbarSelector, '#list-item-dark');

await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-color', 'rgb(51, 51, 51)');
});
Expand All @@ -23,8 +26,33 @@ test.describe('addon-backgrounds', () => {
const sbPage = new SbPage(page);

await sbPage.navigateToStory('example/button', 'primary');
await sbPage.selectToolbar('[title="Apply a grid to the preview"]');
await sbPage.selectToolbar(gridToolbarSelector);

await expect(sbPage.getCanvasBodyElement()).toHaveCSS('background-image', /linear-gradient/);
});

test('button should appear for story pages', async ({ page }) => {
const sbPage = new SbPage(page);

await sbPage.navigateToStory('example/button', 'primary');
await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();
});

test('button should appear for attached docs pages', async ({ page }) => {
const sbPage = new SbPage(page);

await sbPage.navigateToStory('example/button', 'docs');
await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();
});

test('button should appear for unattached docs pages', async ({ page }) => {
const sbPage = new SbPage(page);

// We start on the introduction page by default.
await sbPage.page.waitForURL((url) =>
url.search.includes(`path=/docs/example-introduction--docs`)
);

await expect(sbPage.page.locator(backgroundToolbarSelector)).toBeVisible();
});
});
3 changes: 3 additions & 0 deletions code/lib/core-events/src/index.ts
Expand Up @@ -25,6 +25,8 @@ enum events {
PRELOAD_ENTRIES = 'preloadStories',
// The story has been loaded into the store, we have parameters/args/etc
STORY_PREPARED = 'storyPrepared',
// The a docs entry has been loaded into the store, we have parameters
DOCS_PREPARED = 'docsPrepared',
// The next 6 events are emitted by the StoryRenderer when rendering the current story
STORY_CHANGED = 'storyChanged',
STORY_UNCHANGED = 'storyUnchanged',
Expand Down Expand Up @@ -73,6 +75,7 @@ export const {
CHANNEL_CREATED,
CONFIG_ERROR,
CURRENT_STORY_WAS_SET,
DOCS_PREPARED,
DOCS_RENDERED,
FORCE_RE_RENDER,
FORCE_REMOUNT,
Expand Down
2 changes: 1 addition & 1 deletion code/lib/manager-api/src/lib/stories.ts
Expand Up @@ -261,7 +261,7 @@ export const transformStoryIndexToStoriesHash = (
depth: paths.length,
parent: paths[paths.length - 1],
renderLabel,
...(item.type !== 'docs' && { prepared: !!item.parameters }),
prepared: !!item.parameters,

// deprecated fields
kind: item.title,
Expand Down
40 changes: 37 additions & 3 deletions code/lib/manager-api/src/modules/stories.ts
Expand Up @@ -15,6 +15,9 @@ import type {
StoryIndex,
API_LoadedRefData,
API_IndexHash,
StoryPreparedPayload,
DocsPreparedPayload,
API_DocsEntry,
} from '@storybook/types';
import {
PRELOAD_ENTRIES,
Expand All @@ -31,6 +34,7 @@ import {
CONFIG_ERROR,
CURRENT_STORY_WAS_SET,
STORY_MISSING,
DOCS_PREPARED,
} from '@storybook/core-events';
import { logger } from '@storybook/client-logger';

Expand All @@ -54,7 +58,10 @@ type Direction = -1 | 1;
type ParameterName = string;

type ViewMode = 'story' | 'info' | 'settings' | string | undefined;
type StoryUpdate = Pick<API_StoryEntry, 'parameters' | 'initialArgs' | 'argTypes' | 'args'>;
type StoryUpdate = Partial<
Pick<API_StoryEntry, 'prepared' | 'parameters' | 'initialArgs' | 'argTypes' | 'args'>
>;
type DocsUpdate = Partial<Pick<API_DocsEntry, 'prepared' | 'parameters'>>;

export interface SubState extends API_LoadedRefData {
storyId: StoryId;
Expand Down Expand Up @@ -93,6 +100,7 @@ export interface SubAPI {
): StoryId;
fetchIndex: () => Promise<void>;
updateStory: (storyId: StoryId, update: StoryUpdate, ref?: API_ComposedRef) => Promise<void>;
updateDocs: (storyId: StoryId, update: DocsUpdate, ref?: API_ComposedRef) => Promise<void>;
setPreviewInitialized: (ref?: ComposedRef) => Promise<void>;
}

Expand Down Expand Up @@ -157,7 +165,7 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
: storyIdOrCombo;
const data = api.getData(storyId, refId);

if (data?.type === 'story') {
if (['story', 'docs'].includes(data?.type)) {
const { parameters } = data;

if (parameters) {
Expand Down Expand Up @@ -370,6 +378,27 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
await fullAPI.updateRef(refId, { index });
}
},
updateDocs: async (
docsId: StoryId,
update: DocsUpdate,
ref?: API_ComposedRef
): Promise<void> => {
if (!ref) {
const { index } = store.getState();
index[docsId] = {
...index[docsId],
...update,
} as API_DocsEntry;
await store.setState({ index });
} else {
const { id: refId, index } = ref;
index[docsId] = {
...index[docsId],
...update,
} as API_DocsEntry;
await fullAPI.updateRef(refId, { index });
}
},
setPreviewInitialized: async (ref?: ComposedRef): Promise<void> => {
if (!ref) {
store.setState({ previewInitialized: true });
Expand Down Expand Up @@ -428,7 +457,7 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
}
});

fullAPI.on(STORY_PREPARED, function handler({ id, ...update }) {
fullAPI.on(STORY_PREPARED, function handler({ id, ...update }: StoryPreparedPayload) {
const { ref, sourceType } = getEventMetadata(this, fullAPI);
fullAPI.updateStory(id, { ...update, prepared: true }, ref);

Expand Down Expand Up @@ -458,6 +487,11 @@ export const init: ModuleFn<SubAPI, SubState, true> = ({
}
});

fullAPI.on(DOCS_PREPARED, function handler({ id, ...update }: DocsPreparedPayload) {
const { ref } = getEventMetadata(this, fullAPI);
fullAPI.updateStory(id, { ...update, prepared: true }, ref);
});

fullAPI.on(SET_INDEX, function handler(index: API_PreparedStoryIndex) {
const { ref } = getEventMetadata(this, fullAPI);

Expand Down
53 changes: 52 additions & 1 deletion code/lib/manager-api/src/tests/stories.test.ts
Expand Up @@ -48,6 +48,14 @@ jest.mock('@storybook/global', () => ({
const getEventMetadataMock = getEventMetadata as ReturnType<typeof jest.fn>;

const mockEntries: StoryIndex['entries'] = {
'component-a--docs': {
type: 'docs',
id: 'component-a--docs',
title: 'Component A',
name: 'Docs',
importPath: './path/to/component-a.ts',
storiesImports: [],
},
'component-a--story-1': {
type: 'story',
id: 'component-a--story-1',
Expand Down Expand Up @@ -139,6 +147,7 @@ describe('stories API', () => {
// We need exact key ordering, even if in theory JS doesn't guarantee it
expect(Object.keys(index)).toEqual([
'component-a',
'component-a--docs',
'component-a--story-1',
'component-a--story-2',
'component-b',
Expand All @@ -147,7 +156,17 @@ describe('stories API', () => {
expect(index['component-a']).toMatchObject({
type: 'component',
id: 'component-a',
children: ['component-a--story-1', 'component-a--story-2'],
children: ['component-a--docs', 'component-a--story-1', 'component-a--story-2'],
});

expect(index['component-a--docs']).toMatchObject({
type: 'docs',
id: 'component-a--docs',
parent: 'component-a',
title: 'Component A',
name: 'Docs',
storiesImports: [],
prepared: false,
});

expect(index['component-a--story-1']).toMatchObject({
Expand Down Expand Up @@ -232,6 +251,7 @@ describe('stories API', () => {
// We need exact key ordering, even if in theory JS doesn't guarantee it
expect(Object.keys(index)).toEqual([
'component-a',
'component-a--docs',
'component-a--story-1',
'component-a--story-2',
'component-b',
Expand Down Expand Up @@ -1424,6 +1444,37 @@ describe('stories API', () => {
});
});

describe('DOCS_PREPARED', () => {
it('prepares the docs entry', async () => {
const navigate = jest.fn();
const store = createMockStore();
const fullAPI = Object.assign(new EventEmitter(), {
setStories: jest.fn(),
setOptions: jest.fn(),
});

const { api, init } = initStoriesAndSetState({ store, navigate, provider, fullAPI } as any);
Object.assign(fullAPI, api);

await init();
fullAPI.emit(STORY_PREPARED, {
Copy link

@quantizor quantizor Apr 24, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potential buggy test here @tmeasday, shouldn't this be DOCS_PREPARED?

cc @shilman

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @probablyup

id: 'component-a--docs',
parameters: { a: 'b' },
});

const { index } = store.getState();
expect(index['component-a--docs']).toMatchObject({
type: 'docs',
id: 'component-a--docs',
parent: 'component-a',
title: 'Component A',
name: 'Docs',
prepared: true,
parameters: { a: 'b' },
});
});
});

describe('CONFIG_ERROR', () => {
it('sets previewInitialized to true, local', async () => {
const navigate = jest.fn();
Expand Down
Expand Up @@ -32,6 +32,9 @@ export const componentTwoExports = {
default: { title: 'Component Two' },
c: { args: { foo: 'c' } },
};
export const attachedDocsExports = {
default: jest.fn(),
};
export const unattachedDocsExports = {
default: jest.fn(),
};
Expand All @@ -49,6 +52,7 @@ export const importFn: jest.Mocked<ModuleImportFn> = jest.fn(
async (path: string) =>
({
'./src/ComponentOne.stories.js': componentOneExports,
'./src/ComponentOne.mdx': attachedDocsExports,
'./src/ComponentTwo.stories.js': componentTwoExports,
'./src/Introduction.mdx': unattachedDocsExports,
'./src/ExtraComponentOne.stories.js': extraComponentOneExports,
Expand Down Expand Up @@ -80,7 +84,16 @@ export const storyIndex: StoryIndex = {
name: 'Docs',
importPath: './src/ComponentOne.stories.js',
storiesImports: ['./src/ExtraComponentOne.stories.js'],
tags: ['autodocs'],
tags: ['autodocs', 'docs'],
},
'component-one--attached-docs': {
type: 'docs',
id: 'component-one--attached-docs',
title: 'Component One',
name: 'Attached Docs',
importPath: './src/ComponentOne.mdx',
storiesImports: ['./src/ComponentOne.stories.js'],
tags: ['attached-mdx', 'docs'],
},
'component-one--a': {
type: 'story',
Expand Down Expand Up @@ -110,7 +123,7 @@ export const storyIndex: StoryIndex = {
name: 'Docs',
importPath: './src/ComponentTwo.stories.js',
storiesImports: [],
tags: ['autodocs'],
tags: ['autodocs', 'docs'],
},
'component-two--c': {
type: 'story',
Expand All @@ -126,6 +139,7 @@ export const storyIndex: StoryIndex = {
name: 'Docs',
importPath: './src/Introduction.mdx',
storiesImports: ['./src/ComponentTwo.stories.js'],
tags: ['unattached-mdx', 'docs'],
},
},
};
Expand Down