diff --git a/code/e2e-tests/navigation.spec.ts b/code/e2e-tests/navigation.spec.ts new file mode 100644 index 000000000000..a4c68bdaee36 --- /dev/null +++ b/code/e2e-tests/navigation.spec.ts @@ -0,0 +1,18 @@ +import { test, expect } from '@playwright/test'; +import process from 'process'; +import { SbPage } from './util'; + +const storybookUrl = process.env.STORYBOOK_URL || 'http://localhost:8001'; + +test.describe('navigating', () => { + test('a URL with a partial storyId will redirect to the first story', async ({ page }) => { + // this is purposefully not using the SbPage class, and the URL is a partial (it does not contain the full storyId) + await page.goto(`${storybookUrl}?path=/story/example-button`); + + const sbPage = new SbPage(page); + + await sbPage.waitUntilLoaded(); + + await expect(sbPage.page.url()).toContain('/docs/example-button--docs'); + }); +}); diff --git a/code/lib/manager-api/src/modules/stories.ts b/code/lib/manager-api/src/modules/stories.ts index aff85aabcea3..07d6fb702d30 100644 --- a/code/lib/manager-api/src/modules/stories.ts +++ b/code/lib/manager-api/src/modules/stories.ts @@ -637,15 +637,18 @@ export const init: ModuleFn = ({ state.path === '/' || state.viewMode === 'story' || state.viewMode === 'docs'; const stateHasSelection = state.viewMode && state.storyId; const stateSelectionDifferent = state.viewMode !== viewMode || state.storyId !== storyId; + const { type } = state.index[state.storyId] || {}; + const isStory = !(type === 'root' || type === 'component' || type === 'group'); + /** * When storybook starts, we want to navigate to the first story. * But there are a few exceptions: - * - If the current storyId and viewMode are already set/correct. + * - If the current storyId and viewMode are already set/correct AND the url section is a leaf-type. * - If the user has navigated away already. * - If the user started storybook with a specific page-URL like "/settings/about" */ if (isCanvasRoute) { - if (stateHasSelection && stateSelectionDifferent) { + if (stateHasSelection && stateSelectionDifferent && isStory) { // The manager state is correct, the preview state is lagging behind provider.channel.emit(SET_CURRENT_STORY, { storyId: state.storyId, diff --git a/code/lib/manager-api/src/tests/stories.test.ts b/code/lib/manager-api/src/tests/stories.test.ts index a93cd1df9a99..a6617bce9f41 100644 --- a/code/lib/manager-api/src/tests/stories.test.ts +++ b/code/lib/manager-api/src/tests/stories.test.ts @@ -542,7 +542,7 @@ describe('stories API', () => { describe('STORY_SPECIFIED event', () => { it('navigates to the story', async () => { - const moduleArgs = createMockModuleArgs({ initialState: { path: '/' } }); + const moduleArgs = createMockModuleArgs({ initialState: { path: '/', index: {} } }); initStories(moduleArgs as unknown as ModuleArgs); const { navigate, provider } = moduleArgs; @@ -550,7 +550,7 @@ describe('stories API', () => { expect(navigate).toHaveBeenCalledWith('/story/a--1'); }); it('DOES not navigate if the story was already selected', async () => { - const moduleArgs = createMockModuleArgs({ initialState: { path: '/story/a--1' } }); + const moduleArgs = createMockModuleArgs({ initialState: { path: '/story/a--1', index: {} } }); initStories(moduleArgs as unknown as ModuleArgs); const { navigate, provider } = moduleArgs; @@ -558,7 +558,9 @@ describe('stories API', () => { expect(navigate).not.toHaveBeenCalled(); }); it('DOES not navigate if a settings page was selected', async () => { - const moduleArgs = createMockModuleArgs({ initialState: { path: '/settings/about' } }); + const moduleArgs = createMockModuleArgs({ + initialState: { path: '/settings/about', index: {} }, + }); initStories(moduleArgs as unknown as ModuleArgs); const { navigate, provider } = moduleArgs; @@ -566,7 +568,9 @@ describe('stories API', () => { expect(navigate).not.toHaveBeenCalled(); }); it('DOES not navigate if a custom page was selected', async () => { - const moduleArgs = createMockModuleArgs({ initialState: { path: '/custom/page' } }); + const moduleArgs = createMockModuleArgs({ + initialState: { path: '/custom/page', index: {} }, + }); initStories(moduleArgs as unknown as ModuleArgs); const { navigate, provider } = moduleArgs;