diff --git a/packages/react-cosmos-core/src/renderer/rendererConnect.ts b/packages/react-cosmos-core/src/renderer/rendererConnect.ts index da32e70be2..3b450aa319 100644 --- a/packages/react-cosmos-core/src/renderer/rendererConnect.ts +++ b/packages/react-cosmos-core/src/renderer/rendererConnect.ts @@ -1,5 +1,9 @@ import { FixtureState } from '../fixtureState/types.js'; -import { FixtureId, FixtureList } from '../userModules/fixtureTypes.js'; +import { + FixtureId, + FixtureList, + FixtureListItem, +} from '../userModules/fixtureTypes.js'; // FYI: Renderer ids are self assigned in remote environments, so uniqueness // cannot be established by consensus @@ -73,6 +77,14 @@ export type FixtureListUpdateResponse = { }; }; +export type FixtureLoadedResponse = { + type: 'fixtureLoaded'; + payload: { + rendererId: RendererId; + fixture: FixtureListItem; + }; +}; + // Caused by an organic state change inside the renderer. Also dispatched // after a fixtureSelect request, when rendering stateful components, as their // initial state is read. @@ -98,6 +110,7 @@ export type PlaygroundCommandResponse = { export type RendererResponse = | RendererReadyResponse | RendererErrorResponse + | FixtureLoadedResponse | FixtureListUpdateResponse | FixtureStateChangeResponse | PlaygroundCommandResponse; diff --git a/packages/react-cosmos-renderer/src/__tests__/fixtureSelect.ts b/packages/react-cosmos-renderer/src/__tests__/fixtureSelect.ts index 4e2c0cb09a..7b07d3af5a 100644 --- a/packages/react-cosmos-renderer/src/__tests__/fixtureSelect.ts +++ b/packages/react-cosmos-renderer/src/__tests__/fixtureSelect.ts @@ -112,3 +112,35 @@ testRenderer( ); } ); + +testRenderer( + 'returns fixtureLoaded response for single fixture', + { rendererId, fixtures }, + async ({ selectFixture, fixtureLoaded }) => { + selectFixture({ + rendererId, + fixtureId: { path: 'second' }, + fixtureState: {}, + }); + await fixtureLoaded({ + rendererId, + fixture: { type: 'single' }, + }); + } +); + +testRenderer( + 'returns fixtureLoaded response for multi fixture', + { rendererId, fixtures }, + async ({ selectFixture, fixtureLoaded }) => { + selectFixture({ + rendererId, + fixtureId: { path: 'first', name: 'one' }, + fixtureState: {}, + }); + await fixtureLoaded({ + rendererId, + fixture: { type: 'multi', fixtureNames: ['one'] }, + }); + } +); diff --git a/packages/react-cosmos-renderer/src/__tests__/fixtureSelectLazy.ts b/packages/react-cosmos-renderer/src/__tests__/fixtureSelectLazy.ts new file mode 100644 index 0000000000..4f9e6b46e6 --- /dev/null +++ b/packages/react-cosmos-renderer/src/__tests__/fixtureSelectLazy.ts @@ -0,0 +1,44 @@ +import { uuid } from 'react-cosmos-core'; +import { testRenderer } from '../testHelpers/testRenderer.js'; +import { wrapActSetTimeout } from '../testHelpers/wrapActSetTimeout.js'; +import { wrapDefaultExport } from '../testHelpers/wrapDefaultExport.js'; + +beforeAll(wrapActSetTimeout); + +const rendererId = uuid(); +const fixtures = wrapDefaultExport({ + first: { one: 'First' }, + second: 'Second', +}); + +testRenderer( + 'returns lazy fixtureLoaded response for single fixture', + { rendererId, fixtures, lazy: true }, + async ({ selectFixture, fixtureLoaded }) => { + selectFixture({ + rendererId, + fixtureId: { path: 'second' }, + fixtureState: {}, + }); + await fixtureLoaded({ + rendererId, + fixture: { type: 'single' }, + }); + } +); + +testRenderer( + 'returns lazy fixtureLoaded response for multi fixture', + { rendererId, fixtures, lazy: true }, + async ({ selectFixture, fixtureLoaded }) => { + selectFixture({ + rendererId, + fixtureId: { path: 'first', name: 'one' }, + fixtureState: {}, + }); + await fixtureLoaded({ + rendererId, + fixture: { type: 'multi', fixtureNames: ['one'] }, + }); + } +); diff --git a/packages/react-cosmos-renderer/src/fixtureModule/FixtureProvider.tsx b/packages/react-cosmos-renderer/src/fixtureModule/FixtureProvider.tsx index fe8130f0a7..5abafe7b69 100644 --- a/packages/react-cosmos-renderer/src/fixtureModule/FixtureProvider.tsx +++ b/packages/react-cosmos-renderer/src/fixtureModule/FixtureProvider.tsx @@ -45,6 +45,16 @@ export function FixtureProvider(props: Props) { } }, [props.fixtureId.path, props.fixtureItem, props.lazy, setLazyItems]); + React.useEffect(() => { + rendererConnect.postMessage({ + type: 'fixtureLoaded', + payload: { + rendererId, + fixture: props.fixtureItem, + }, + }); + }, [props.fixtureItem, rendererConnect, rendererId]); + React.useEffect(() => { if (!isEqual(state.fixtureState, state.syncedFixtureState)) { rendererConnect.postMessage({ diff --git a/packages/react-cosmos-renderer/src/testHelpers/createRendererConnectTestApi.ts b/packages/react-cosmos-renderer/src/testHelpers/createRendererConnectTestApi.ts index 1722b6391c..25ca5130ac 100644 --- a/packages/react-cosmos-renderer/src/testHelpers/createRendererConnectTestApi.ts +++ b/packages/react-cosmos-renderer/src/testHelpers/createRendererConnectTestApi.ts @@ -2,6 +2,7 @@ import until from 'async-until'; import { findLast } from 'lodash-es'; import { FixtureListUpdateResponse, + FixtureLoadedResponse, FixtureState, FixtureStateChangeResponse, ReloadRendererRequest, @@ -23,6 +24,7 @@ export type RendererConnectTestApi = { fixtureListUpdate: ( payload: FixtureListUpdateResponse['payload'] ) => Promise; + fixtureLoaded: (payload: FixtureLoadedResponse['payload']) => Promise; fixtureStateChange: ( payload: FixtureStateChangeResponse['payload'] ) => Promise; @@ -43,6 +45,7 @@ export function createRendererConnectTestApi(args: { setFixtureState, rendererReady, fixtureListUpdate, + fixtureLoaded, fixtureStateChange, getLastFixtureState, clearResponses: args.clearResponses, @@ -98,6 +101,13 @@ export function createRendererConnectTestApi(args: { }); } + async function fixtureLoaded(payload: FixtureLoadedResponse['payload']) { + await untilResponse({ + type: 'fixtureLoaded', + payload, + }); + } + async function fixtureStateChange( payload: FixtureStateChangeResponse['payload'] ) {