Skip to content
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.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
import { ManagerContext } from 'storybook/manager-api';
import { expect, fn } from 'storybook/test';

import preview from '../../../../../.storybook/preview.tsx';
import { FramesRenderer } from './FramesRenderer.tsx';

// Use the `Icons` composed ref that this Storybook already references, so the active ref frame
// renders a real story instead of a non-existent URL.
const refId = 'icons';
const refUrl = 'https://main--64b56e737c0aeefed9d5e675.chromatic.com';
const storyId = 'icons-accessibilityicon--default';

// getStoryHrefs returns the composed ref's iframe URL whenever a refId is passed, so we can
// assert the local preview frame is requested without one (mirrors manager-api/url.ts).
const getStoryHrefs = fn((id: string, opts?: { refId?: string }) => ({
managerHref: '',
previewHref: opts?.refId
? `${refUrl}/iframe.html?id=${id}&refId=${opts.refId}`
: `iframe.html?id=${id}`,
})).mockName('api::getStoryHrefs');

const api: any = {
getStoryHrefs,
getIsFullscreen: fn(() => false),
getIsNavShown: fn(() => true),
getCurrentParameter: fn(() => undefined),
getGlobals: fn(() => ({})),
getStoryGlobals: fn(() => ({})),
getUserGlobals: fn(() => ({})),
getUrlState: fn(() => ({ viewMode: 'story' })),
updateGlobals: fn(),
setAddonShortcut: fn(),
on: fn(),
off: fn(),
emit: fn(),
};

const managerContext: any = {
state: { storyId },
api,
};

const meta = preview.meta({
component: FramesRenderer,
args: {
api,
refId,
storyId,
viewMode: 'story',
scale: 1,
baseUrl: 'iframe.html',
queryParams: {},
entry: { type: 'story', id: storyId } as any,
refs: {
[refId]: { id: refId, url: refUrl, type: 'lazy', title: 'Icons' },
} as any,
},
decorators: [
(Story) => (
<ManagerContext.Provider value={managerContext}>
<Story />
</ManagerContext.Provider>
),
],
parameters: { layout: 'fullscreen' },
});

/**
* Regression test for #34553: when a composed-ref story is the initial selection, the local
* preview frame must still point at the host's own iframe URL. Otherwise the local frame
* stays stuck on the ref's Storybook (it is only set once) and host stories never render.
*/
export const RefStoryKeepsLocalPreviewOnHost = meta.story({
play: async ({ canvasElement }) => {
const localFrame = canvasElement.querySelector<HTMLIFrameElement>('#storybook-preview-iframe');
await expect(localFrame).not.toBeNull();

const src = localFrame?.getAttribute('src') ?? '';
await expect(src).not.toContain(refUrl);
await expect(src).toContain(`iframe.html?id=${storyId}`);
},
});
6 changes: 5 additions & 1 deletion code/core/src/manager/components/preview/FramesRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,13 @@ export const FramesRenderer: FC<FramesRendererProps> = ({
}, {});

if (!frames['storybook-preview-iframe']) {
// The local preview iframe must always use the host's own URL, so pass `refId: undefined`
// explicitly. Passing the current story's `refId` makes getStoryHrefs return the composed
// ref's iframe URL, and since this is only set once, the local frame would stay stuck on
// the ref's Storybook when a ref story is loaded first (#34553).
frames['storybook-preview-iframe'] = api.getStoryHrefs(storyId, {
queryParams: { ...queryParams, ...(version && { version }) },
refId,
Comment thread
Sidnioulz marked this conversation as resolved.
refId: undefined,
viewMode,
}).previewHref;
}
Expand Down