How to use waitForSetCurrentStory method in storybook-root

Best JavaScript code snippet using storybook-root

PreviewWeb.test.ts

Source:PreviewWeb.test.ts Github

copy

Full Screen

...58};59// SET_CURRENT_STORY does some stuff in promises, then waits for60// a timer, so we need to first setImmediate (to get past the resolution), then run the timers61// Probably jest modern timers do this but they aren't working for some bizzarre reason.62async function waitForSetCurrentStory() {63 await new Promise((r) => setImmediate(r));64 jest.runAllTimers();65}66async function createAndRenderPreview({67 importFn: inputImportFn = importFn,68 getProjectAnnotations: inputGetProjectAnnotations = getProjectAnnotations,69}: {70 importFn?: ModuleImportFn;71 getProjectAnnotations?: () => WebProjectAnnotations<AnyFramework>;72} = {}) {73 const preview = new PreviewWeb();74 await preview.initialize({75 importFn: inputImportFn,76 getProjectAnnotations: inputGetProjectAnnotations,77 });78 await waitForRender();79 return preview;80}81beforeEach(() => {82 document.location.search = '';83 mockChannel.emit.mockClear();84 emitter.removeAllListeners();85 componentOneExports.default.loaders[0].mockReset().mockImplementation(async () => ({ l: 7 }));86 componentOneExports.default.parameters.docs.container.mockClear();87 componentOneExports.a.play.mockReset();88 projectAnnotations.renderToDOM.mockReset();89 projectAnnotations.render.mockClear();90 projectAnnotations.decorators[0].mockClear();91 // @ts-ignore92 ReactDOM.render.mockReset().mockImplementation((_: any, _2: any, cb: () => any) => cb());93 // @ts-ignore94 logger.warn.mockClear();95 mockStoryIndex.mockReset().mockReturnValue(storyIndex);96 addons.setChannel(mockChannel as any);97 addons.setServerChannel(createMockChannel());98 mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };99});100describe('PreviewWeb', () => {101 describe('initialize', () => {102 it('shows an error if getProjectAnnotations throws', async () => {103 const err = new Error('meta error');104 const preview = new PreviewWeb();105 await expect(106 preview.initialize({107 importFn,108 getProjectAnnotations: () => {109 throw err;110 },111 })112 ).rejects.toThrow(err);113 expect(preview.view.showErrorDisplay).toHaveBeenCalled();114 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, err);115 });116 it('shows an error if the stories.json endpoint 500s', async () => {117 const err = new Error('sort error');118 mockFetchResult = { status: 500, text: async () => err.toString() };119 const preview = new PreviewWeb();120 await expect(preview.initialize({ importFn, getProjectAnnotations })).rejects.toThrow(121 'sort error'122 );123 expect(preview.view.showErrorDisplay).toHaveBeenCalled();124 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error));125 });126 it('sets globals from the URL', async () => {127 document.location.search = '?id=*&globals=a:c';128 const preview = await createAndRenderPreview();129 expect(preview.storyStore.globals.get()).toEqual({ a: 'c' });130 });131 it('emits the SET_GLOBALS event', async () => {132 await createAndRenderPreview();133 expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {134 globals: { a: 'b' },135 globalTypes: {},136 });137 });138 it('SET_GLOBALS sets globals and types even when undefined', async () => {139 await createAndRenderPreview({ getProjectAnnotations: () => ({ renderToDOM: jest.fn() }) });140 expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {141 globals: {},142 globalTypes: {},143 });144 });145 it('emits the SET_GLOBALS event from the URL', async () => {146 document.location.search = '?id=*&globals=a:c';147 await createAndRenderPreview();148 expect(mockChannel.emit).toHaveBeenCalledWith(Events.SET_GLOBALS, {149 globals: { a: 'c' },150 globalTypes: {},151 });152 });153 it('sets args from the URL', async () => {154 document.location.search = '?id=component-one--a&args=foo:url';155 const preview = await createAndRenderPreview();156 expect(preview.storyStore.args.get('component-one--a')).toEqual({157 foo: 'url',158 });159 });160 it('updates args from the URL', async () => {161 document.location.search = '?id=component-one--a&args=foo:url';162 await createAndRenderPreview();163 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {164 storyId: 'component-one--a',165 args: { foo: 'url' },166 });167 });168 it('allows async getProjectAnnotations', async () => {169 const preview = new PreviewWeb();170 await preview.initialize({171 importFn,172 getProjectAnnotations: async () => {173 return getProjectAnnotations();174 },175 });176 expect(preview.storyStore.globals.get()).toEqual({ a: 'b' });177 });178 });179 describe('initial selection', () => {180 it('selects the story specified in the URL', async () => {181 document.location.search = '?id=component-one--a';182 const preview = await createAndRenderPreview();183 expect(preview.urlStore.selection).toEqual({184 storyId: 'component-one--a',185 viewMode: 'story',186 });187 expect(history.replaceState).toHaveBeenCalledWith(188 {},189 '',190 'pathname?id=component-one--a&viewMode=story'191 );192 });193 it('emits the STORY_SPECIFIED event', async () => {194 document.location.search = '?id=component-one--a';195 await createAndRenderPreview();196 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_SPECIFIED, {197 storyId: 'component-one--a',198 viewMode: 'story',199 });200 });201 it('emits the CURRENT_STORY_WAS_SET event', async () => {202 document.location.search = '?id=component-one--a';203 await createAndRenderPreview();204 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, {205 storyId: 'component-one--a',206 viewMode: 'story',207 });208 });209 describe('if the story specified does not exist', () => {210 it('renders a loading error', async () => {211 document.location.search = '?id=random';212 const preview = await createAndRenderPreview();213 expect(preview.view.showErrorDisplay).toHaveBeenCalled();214 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'random');215 });216 it('tries again with a specifier if CSF file changes', async () => {217 document.location.search = '?id=component-one--d';218 const preview = await createAndRenderPreview();219 expect(preview.view.showErrorDisplay).toHaveBeenCalled();220 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d');221 mockChannel.emit.mockClear();222 const newComponentOneExports = merge({}, componentOneExports, {223 d: { args: { foo: 'd' }, play: jest.fn() },224 });225 const newImportFn = jest.fn(async (path) => {226 return path === './src/ComponentOne.stories.js'227 ? newComponentOneExports228 : componentTwoExports;229 });230 preview.onStoriesChanged({231 importFn: newImportFn,232 storyIndex: {233 v: 3,234 stories: {235 ...storyIndex.stories,236 'component-one--d': {237 id: 'component-one--d',238 title: 'Component One',239 name: 'D',240 importPath: './src/ComponentOne.stories.js',241 },242 },243 },244 });245 await waitForRender();246 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_SPECIFIED, {247 storyId: 'component-one--d',248 viewMode: 'story',249 });250 });251 describe('after selection changes', () => {252 beforeEach(() => jest.useFakeTimers());253 afterEach(() => jest.useRealTimers());254 it('DOES NOT try again if CSF file changes', async () => {255 document.location.search = '?id=component-one--d';256 const preview = await createAndRenderPreview();257 expect(preview.view.showErrorDisplay).toHaveBeenCalled();258 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--d');259 emitter.emit(Events.SET_CURRENT_STORY, {260 storyId: 'component-one--b',261 viewMode: 'story',262 });263 await waitForSetCurrentStory();264 const newComponentOneExports = merge({}, componentOneExports, {265 d: { args: { foo: 'd' }, play: jest.fn() },266 });267 const newImportFn = jest.fn(async (path) => {268 return path === './src/ComponentOne.stories.js'269 ? newComponentOneExports270 : componentTwoExports;271 });272 preview.onStoriesChanged({273 importFn: newImportFn,274 storyIndex: {275 v: 3,276 stories: {277 ...storyIndex.stories,278 'component-one--d': {279 id: 'component-one--d',280 title: 'Component One',281 name: 'D',282 importPath: './src/ComponentOne.stories.js',283 },284 },285 },286 });287 expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_SPECIFIED, {288 storyId: 'component-one--d',289 viewMode: 'story',290 });291 });292 });293 });294 it('renders missing if no selection', async () => {295 const preview = await createAndRenderPreview();296 expect(preview.view.showNoPreview).toHaveBeenCalled();297 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING);298 });299 describe('in story viewMode', () => {300 it('calls view.prepareForStory', async () => {301 document.location.search = '?id=component-one--a';302 const preview = await createAndRenderPreview();303 expect(preview.view.prepareForStory).toHaveBeenCalledWith(304 expect.objectContaining({305 id: 'component-one--a',306 })307 );308 });309 it('emits STORY_PREPARED', async () => {310 document.location.search = '?id=component-one--a';311 await createAndRenderPreview();312 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {313 id: 'component-one--a',314 parameters: {315 __isArgsStory: false,316 docs: { container: expect.any(Function) },317 fileName: './src/ComponentOne.stories.js',318 },319 initialArgs: { foo: 'a' },320 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },321 args: { foo: 'a' },322 });323 });324 it('applies loaders with story context', async () => {325 document.location.search = '?id=component-one--a';326 await createAndRenderPreview();327 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(328 expect.objectContaining({329 id: 'component-one--a',330 parameters: {331 __isArgsStory: false,332 docs: { container: expect.any(Function) },333 fileName: './src/ComponentOne.stories.js',334 },335 initialArgs: { foo: 'a' },336 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },337 args: { foo: 'a' },338 })339 );340 });341 it('passes loaded context to renderToDOM', async () => {342 document.location.search = '?id=component-one--a';343 await createAndRenderPreview();344 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(345 expect.objectContaining({346 forceRemount: true,347 storyContext: expect.objectContaining({348 id: 'component-one--a',349 parameters: {350 __isArgsStory: false,351 docs: { container: expect.any(Function) },352 fileName: './src/ComponentOne.stories.js',353 },354 globals: { a: 'b' },355 initialArgs: { foo: 'a' },356 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },357 args: { foo: 'a' },358 loaded: { l: 7 },359 }),360 }),361 undefined // this is coming from view.prepareForStory, not super important362 );363 });364 it('renders exception if a loader throws', async () => {365 const error = new Error('error');366 componentOneExports.default.loaders[0].mockImplementationOnce(() => {367 throw error;368 });369 document.location.search = '?id=component-one--a';370 const preview = await createAndRenderPreview();371 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);372 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);373 });374 it('renders exception if renderToDOM throws', async () => {375 const error = new Error('error');376 projectAnnotations.renderToDOM.mockImplementationOnce(() => {377 throw error;378 });379 document.location.search = '?id=component-one--a';380 const preview = await createAndRenderPreview();381 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);382 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);383 });384 it('renders helpful message if renderToDOM is undefined', async () => {385 const originalRenderToDOM = projectAnnotations.renderToDOM;386 try {387 projectAnnotations.renderToDOM = undefined;388 document.location.search = '?id=component-one--a';389 const preview = new PreviewWeb();390 await expect(preview.initialize({ importFn, getProjectAnnotations })).rejects.toThrow();391 expect(preview.view.showErrorDisplay).toHaveBeenCalled();392 expect((preview.view.showErrorDisplay as jest.Mock).mock.calls[0][0])393 .toMatchInlineSnapshot(`394 [Error: Expected your framework's preset to export a \\\`renderToDOM\\\` field.395 Perhaps it needs to be upgraded for Storybook 6.4?396 More info: https://github.com/storybookjs/storybook/blob/next/MIGRATION.md#mainjs-framework-field ]397 `);398 } finally {399 projectAnnotations.renderToDOM = originalRenderToDOM;400 }401 });402 it('renders exception if the play function throws', async () => {403 const error = new Error('error');404 componentOneExports.a.play.mockImplementationOnce(() => {405 throw error;406 });407 document.location.search = '?id=component-one--a';408 const preview = await createAndRenderPreview();409 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);410 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);411 });412 it('renders error if the story calls showError', async () => {413 const error = { title: 'title', description: 'description' };414 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>415 context.showError(error)416 );417 document.location.search = '?id=component-one--a';418 const preview = await createAndRenderPreview();419 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error);420 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({421 message: error.title,422 stack: error.description,423 });424 });425 it('renders exception if the story calls showException', async () => {426 const error = new Error('error');427 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>428 context.showException(error)429 );430 document.location.search = '?id=component-one--a';431 const preview = await createAndRenderPreview();432 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);433 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);434 });435 it('executes playFunction', async () => {436 document.location.search = '?id=component-one--a';437 await createAndRenderPreview();438 expect(componentOneExports.a.play).toHaveBeenCalled();439 });440 it('emits STORY_RENDERED', async () => {441 document.location.search = '?id=component-one--a';442 await createAndRenderPreview();443 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');444 });445 it('does not show error display if the render function throws IGNORED_EXCEPTION', async () => {446 document.location.search = '?id=component-one--a';447 projectAnnotations.renderToDOM.mockImplementationOnce(() => {448 throw IGNORED_EXCEPTION;449 });450 const preview = new PreviewWeb();451 await preview.initialize({ importFn, getProjectAnnotations });452 await waitForRender();453 expect(mockChannel.emit).toHaveBeenCalledWith(454 Events.STORY_THREW_EXCEPTION,455 IGNORED_EXCEPTION456 );457 expect(preview.view.showErrorDisplay).not.toHaveBeenCalled();458 });459 });460 describe('in docs viewMode', () => {461 it('calls view.prepareForDocs', async () => {462 document.location.search = '?id=component-one--a&viewMode=docs';463 const preview = await createAndRenderPreview();464 expect(preview.view.prepareForDocs).toHaveBeenCalled();465 });466 it('emits STORY_PREPARED', async () => {467 document.location.search = '?id=component-one--a&viewMode=docs';468 await createAndRenderPreview();469 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {470 id: 'component-one--a',471 parameters: {472 __isArgsStory: false,473 docs: { container: expect.any(Function) },474 fileName: './src/ComponentOne.stories.js',475 },476 initialArgs: { foo: 'a' },477 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },478 args: { foo: 'a' },479 });480 });481 it('render the docs container with the correct context', async () => {482 document.location.search = '?id=component-one--a&viewMode=docs';483 await createAndRenderPreview();484 expect(ReactDOM.render).toHaveBeenCalledWith(485 expect.objectContaining({486 type: componentOneExports.default.parameters.docs.container,487 props: expect.objectContaining({488 context: expect.objectContaining({489 id: 'component-one--a',490 title: 'Component One',491 name: 'A',492 }),493 }),494 }),495 undefined,496 expect.any(Function)497 );498 });499 it('emits DOCS_RENDERED', async () => {500 document.location.search = '?id=component-one--a&viewMode=docs';501 await createAndRenderPreview();502 expect(mockChannel.emit).toHaveBeenCalledWith(Events.DOCS_RENDERED, 'component-one--a');503 });504 });505 });506 describe('onUpdateGlobals', () => {507 it('emits GLOBALS_UPDATED', async () => {508 document.location.search = '?id=component-one--a';509 await createAndRenderPreview();510 emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });511 expect(mockChannel.emit).toHaveBeenCalledWith(Events.GLOBALS_UPDATED, {512 globals: { a: 'b', foo: 'bar' },513 initialGlobals: { a: 'b' },514 });515 });516 it('sets new globals on the store', async () => {517 document.location.search = '?id=component-one--a';518 const preview = await createAndRenderPreview();519 emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });520 expect(preview.storyStore.globals.get()).toEqual({ a: 'b', foo: 'bar' });521 });522 it('passes new globals in context to renderToDOM', async () => {523 document.location.search = '?id=component-one--a';524 const preview = await createAndRenderPreview();525 mockChannel.emit.mockClear();526 projectAnnotations.renderToDOM.mockClear();527 emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });528 await waitForRender();529 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(530 expect.objectContaining({531 forceRemount: false,532 storyContext: expect.objectContaining({533 globals: { a: 'b', foo: 'bar' },534 }),535 }),536 undefined // this is coming from view.prepareForStory, not super important537 );538 });539 it('emits STORY_RENDERED', async () => {540 document.location.search = '?id=component-one--a';541 await createAndRenderPreview();542 mockChannel.emit.mockClear();543 emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });544 await waitForRender();545 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');546 });547 describe('in docs mode', () => {548 it('re-renders the docs container', async () => {549 document.location.search = '?id=component-one--a&viewMode=docs';550 await createAndRenderPreview();551 mockChannel.emit.mockClear();552 emitter.emit(Events.UPDATE_GLOBALS, { globals: { foo: 'bar' } });553 await waitForRender();554 expect(ReactDOM.render).toHaveBeenCalledTimes(2);555 });556 });557 });558 describe('onUpdateArgs', () => {559 it('emits STORY_ARGS_UPDATED', async () => {560 document.location.search = '?id=component-one--a';561 await createAndRenderPreview();562 emitter.emit(Events.UPDATE_STORY_ARGS, {563 storyId: 'component-one--a',564 updatedArgs: { new: 'arg' },565 });566 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {567 storyId: 'component-one--a',568 args: { foo: 'a', new: 'arg' },569 });570 });571 it('sets new args on the store', async () => {572 document.location.search = '?id=component-one--a';573 const preview = await createAndRenderPreview();574 emitter.emit(Events.UPDATE_STORY_ARGS, {575 storyId: 'component-one--a',576 updatedArgs: { new: 'arg' },577 });578 expect(preview.storyStore.args.get('component-one--a')).toEqual({579 foo: 'a',580 new: 'arg',581 });582 });583 it('passes new args in context to renderToDOM', async () => {584 document.location.search = '?id=component-one--a';585 await createAndRenderPreview();586 mockChannel.emit.mockClear();587 projectAnnotations.renderToDOM.mockClear();588 emitter.emit(Events.UPDATE_STORY_ARGS, {589 storyId: 'component-one--a',590 updatedArgs: { new: 'arg' },591 });592 await waitForRender();593 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(594 expect.objectContaining({595 forceRemount: false,596 storyContext: expect.objectContaining({597 initialArgs: { foo: 'a' },598 args: { foo: 'a', new: 'arg' },599 }),600 }),601 undefined // this is coming from view.prepareForStory, not super important602 );603 });604 it('emits STORY_RENDERED', async () => {605 document.location.search = '?id=component-one--a';606 await createAndRenderPreview();607 mockChannel.emit.mockClear();608 emitter.emit(Events.UPDATE_STORY_ARGS, {609 storyId: 'component-one--a',610 updatedArgs: { new: 'arg' },611 });612 await waitForRender();613 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');614 });615 describe('while story is still rendering', () => {616 it('runs loaders again', async () => {617 const [gate, openGate] = createGate();618 document.location.search = '?id=component-one--a';619 componentOneExports.default.loaders[0].mockImplementationOnce(async () => gate);620 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });621 await waitForRenderPhase('loading');622 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(623 expect.objectContaining({624 args: { foo: 'a' },625 })626 );627 componentOneExports.default.loaders[0].mockClear();628 emitter.emit(Events.UPDATE_STORY_ARGS, {629 storyId: 'component-one--a',630 updatedArgs: { new: 'arg' },631 });632 await waitForRender();633 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(634 expect.objectContaining({635 args: { foo: 'a', new: 'arg' },636 })637 );638 // Story gets rendered with updated args639 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(1);640 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(641 expect.objectContaining({642 forceRemount: true, // Wasn't yet rendered so we need to force remount643 storyContext: expect.objectContaining({644 loaded: { l: 7 }, // This is the value returned by the *second* loader call645 args: { foo: 'a', new: 'arg' },646 }),647 }),648 undefined // this is coming from view.prepareForStory, not super important649 );650 // Now let the first loader call resolve651 mockChannel.emit.mockClear();652 projectAnnotations.renderToDOM.mockClear();653 openGate({ l: 8 });654 await waitForRender();655 // Now the first call comes through, but picks up the new args656 // Note this isn't a particularly realistic case (the second loader being quicker than the first)657 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(1);658 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(659 expect.objectContaining({660 storyContext: expect.objectContaining({661 loaded: { l: 8 },662 args: { foo: 'a', new: 'arg' },663 }),664 }),665 undefined // this is coming from view.prepareForStory, not super important666 );667 });668 it('renders a second time if renderToDOM is running', async () => {669 const [gate, openGate] = createGate();670 document.location.search = '?id=component-one--a';671 projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate);672 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });673 await waitForRenderPhase('rendering');674 emitter.emit(Events.UPDATE_STORY_ARGS, {675 storyId: 'component-one--a',676 updatedArgs: { new: 'arg' },677 });678 // Now let the renderToDOM call resolve679 openGate();680 await waitForRender();681 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(2);682 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(683 expect.objectContaining({684 forceRemount: true,685 storyContext: expect.objectContaining({686 loaded: { l: 7 },687 args: { foo: 'a' },688 }),689 }),690 undefined // this is coming from view.prepareForStory, not super important691 );692 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(693 expect.objectContaining({694 forceRemount: false,695 storyContext: expect.objectContaining({696 loaded: { l: 7 },697 args: { foo: 'a', new: 'arg' },698 }),699 }),700 undefined // this is coming from view.prepareForStory, not super important701 );702 });703 it('works if it is called directly from inside non async renderToDOM', async () => {704 document.location.search = '?id=component-one--a';705 projectAnnotations.renderToDOM.mockImplementationOnce(() => {706 emitter.emit(Events.UPDATE_STORY_ARGS, {707 storyId: 'component-one--a',708 updatedArgs: { new: 'arg' },709 });710 });711 await createAndRenderPreview();712 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(2);713 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(714 expect.objectContaining({715 forceRemount: true,716 storyContext: expect.objectContaining({717 loaded: { l: 7 },718 args: { foo: 'a' },719 }),720 }),721 undefined // this is coming from view.prepareForStory, not super important722 );723 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(724 expect.objectContaining({725 forceRemount: false,726 storyContext: expect.objectContaining({727 loaded: { l: 7 },728 args: { foo: 'a', new: 'arg' },729 }),730 }),731 undefined // this is coming from view.prepareForStory, not super important732 );733 });734 it('calls renderToDOM again if play function is running', async () => {735 const [gate, openGate] = createGate();736 componentOneExports.a.play.mockImplementationOnce(async () => gate);737 const renderToDOMCalled = new Promise((resolve) => {738 projectAnnotations.renderToDOM.mockImplementationOnce(() => {739 resolve(null);740 });741 });742 document.location.search = '?id=component-one--a';743 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });744 await waitForRenderPhase('playing');745 await renderToDOMCalled;746 // Story gets rendered with original args747 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(748 expect.objectContaining({749 forceRemount: true,750 storyContext: expect.objectContaining({751 loaded: { l: 7 },752 args: { foo: 'a' },753 }),754 }),755 undefined // this is coming from view.prepareForStory, not super important756 );757 emitter.emit(Events.UPDATE_STORY_ARGS, {758 storyId: 'component-one--a',759 updatedArgs: { new: 'arg' },760 });761 // The second call should emit STORY_RENDERED762 await waitForRender();763 // Story gets rendered with updated args764 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(765 expect.objectContaining({766 forceRemount: false,767 storyContext: expect.objectContaining({768 loaded: { l: 7 },769 args: { foo: 'a', new: 'arg' },770 }),771 }),772 undefined // this is coming from view.prepareForStory, not super important773 );774 // Now let the playFunction call resolve775 openGate();776 });777 });778 describe('in docs mode', () => {779 it('re-renders the docs container', async () => {780 document.location.search = '?id=component-one--a&viewMode=docs';781 await createAndRenderPreview();782 mockChannel.emit.mockClear();783 emitter.emit(Events.UPDATE_STORY_ARGS, {784 storyId: 'component-one--a',785 updatedArgs: { new: 'arg' },786 });787 await waitForRender();788 expect(ReactDOM.render).toHaveBeenCalledTimes(2);789 });790 });791 });792 describe('onResetArgs', () => {793 it('emits STORY_ARGS_UPDATED', async () => {794 document.location.search = '?id=component-one--a';795 await createAndRenderPreview();796 mockChannel.emit.mockClear();797 emitter.emit(Events.UPDATE_STORY_ARGS, {798 storyId: 'component-one--a',799 updatedArgs: { foo: 'new' },800 });801 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {802 storyId: 'component-one--a',803 args: { foo: 'new' },804 });805 mockChannel.emit.mockClear();806 emitter.emit(Events.RESET_STORY_ARGS, {807 storyId: 'component-one--a',808 argNames: ['foo'],809 });810 await waitForEvents([Events.STORY_ARGS_UPDATED]);811 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {812 storyId: 'component-one--a',813 args: { foo: 'a' },814 });815 });816 it('resets a single arg', async () => {817 document.location.search = '?id=component-one--a';818 await createAndRenderPreview();819 mockChannel.emit.mockClear();820 emitter.emit(Events.UPDATE_STORY_ARGS, {821 storyId: 'component-one--a',822 updatedArgs: { foo: 'new', new: 'value' },823 });824 mockChannel.emit.mockClear();825 emitter.emit(Events.RESET_STORY_ARGS, {826 storyId: 'component-one--a',827 argNames: ['foo'],828 });829 await waitForRender();830 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(831 expect.objectContaining({832 forceRemount: false,833 storyContext: expect.objectContaining({834 initialArgs: { foo: 'a' },835 args: { foo: 'a', new: 'value' },836 }),837 }),838 undefined // this is coming from view.prepareForStory, not super important839 );840 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {841 storyId: 'component-one--a',842 args: { foo: 'a', new: 'value' },843 });844 });845 it('resets all args', async () => {846 document.location.search = '?id=component-one--a';847 await createAndRenderPreview();848 emitter.emit(Events.UPDATE_STORY_ARGS, {849 storyId: 'component-one--a',850 updatedArgs: { foo: 'new', new: 'value' },851 });852 mockChannel.emit.mockClear();853 emitter.emit(Events.RESET_STORY_ARGS, {854 storyId: 'component-one--a',855 });856 await waitForRender();857 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(858 expect.objectContaining({859 forceRemount: false,860 storyContext: expect.objectContaining({861 initialArgs: { foo: 'a' },862 args: { foo: 'a' },863 }),864 }),865 undefined // this is coming from view.prepareForStory, not super important866 );867 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {868 storyId: 'component-one--a',869 args: { foo: 'a' },870 });871 });872 });873 describe('on FORCE_RE_RENDER', () => {874 it('rerenders the story with the same args', async () => {875 document.location.search = '?id=component-one--a';876 await createAndRenderPreview();877 mockChannel.emit.mockClear();878 projectAnnotations.renderToDOM.mockClear();879 emitter.emit(Events.FORCE_RE_RENDER);880 await waitForRender();881 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(882 expect.objectContaining({ forceRemount: false }),883 undefined // this is coming from view.prepareForStory, not super important884 );885 });886 });887 describe('on FORCE_REMOUNT', () => {888 beforeEach(() => {889 jest.useFakeTimers();890 });891 afterEach(() => {892 jest.useRealTimers();893 });894 it('remounts the story with the same args', async () => {895 document.location.search = '?id=component-one--a';896 await createAndRenderPreview();897 mockChannel.emit.mockClear();898 projectAnnotations.renderToDOM.mockClear();899 emitter.emit(Events.FORCE_REMOUNT, { storyId: 'component-one--a' });900 await waitForRender();901 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(902 expect.objectContaining({ forceRemount: true }),903 undefined // this is coming from view.prepareForStory, not super important904 );905 });906 it('aborts render function for initial story', async () => {907 const [gate, openGate] = createGate();908 document.location.search = '?id=component-one--a';909 projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate);910 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });911 await waitForRenderPhase('rendering');912 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(913 expect.objectContaining({914 forceRemount: true,915 storyContext: expect.objectContaining({916 id: 'component-one--a',917 loaded: { l: 7 },918 }),919 }),920 undefined // this is coming from view.prepareForStory, not super important921 );922 mockChannel.emit.mockClear();923 emitter.emit(Events.FORCE_REMOUNT, { storyId: 'component-one--a' });924 await waitForSetCurrentStory();925 // Now let the renderToDOM call resolve926 openGate();927 await waitForRenderPhase('aborted');928 await waitForSetCurrentStory();929 await waitForRenderPhase('rendering');930 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(2);931 await waitForRenderPhase('playing');932 expect(componentOneExports.a.play).toHaveBeenCalledTimes(1);933 await waitForRenderPhase('completed');934 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');935 await waitForQuiescence();936 });937 });938 describe('onSetCurrentStory', () => {939 beforeEach(() => {940 jest.useFakeTimers();941 });942 afterEach(() => {943 jest.useRealTimers();944 });945 it('updates URL', async () => {946 document.location.search = '?id=component-one--a';947 await createAndRenderPreview();948 emitter.emit(Events.SET_CURRENT_STORY, {949 storyId: 'component-one--b',950 viewMode: 'story',951 });952 await waitForSetCurrentStory();953 expect(history.replaceState).toHaveBeenCalledWith(954 {},955 '',956 'pathname?id=component-one--b&viewMode=story'957 );958 });959 it('emits CURRENT_STORY_WAS_SET', async () => {960 document.location.search = '?id=component-one--a';961 await createAndRenderPreview();962 emitter.emit(Events.SET_CURRENT_STORY, {963 storyId: 'component-one--b',964 viewMode: 'story',965 });966 await waitForSetCurrentStory();967 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, {968 storyId: 'component-one--b',969 viewMode: 'story',970 });971 });972 it('renders loading error if the story specified does not exist', async () => {973 document.location.search = '?id=component-one--a';974 const preview = await createAndRenderPreview();975 emitter.emit(Events.SET_CURRENT_STORY, {976 storyId: 'random',977 viewMode: 'story',978 });979 await waitForSetCurrentStory();980 await waitForEvents([Events.STORY_MISSING]);981 expect(preview.view.showErrorDisplay).toHaveBeenCalled();982 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_MISSING, 'random');983 });984 describe('if called before the preview is initialized', () => {985 it('still renders the selected story, once ready', async () => {986 document.location.search = '';987 // We intentionally are *not* awaiting here988 new PreviewWeb().initialize({ importFn, getProjectAnnotations });989 emitter.emit(Events.SET_CURRENT_STORY, {990 storyId: 'component-one--b',991 viewMode: 'story',992 });993 await waitForEvents([Events.STORY_RENDERED]);994 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CURRENT_STORY_WAS_SET, {995 storyId: 'component-one--b',996 viewMode: 'story',997 });998 expect(history.replaceState).toHaveBeenCalledWith(999 {},1000 '',1001 'pathname?id=component-one--b&viewMode=story'1002 );1003 expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_MISSING, 'component-one--b');1004 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b');1005 });1006 });1007 describe('if the selection is unchanged', () => {1008 it('emits STORY_UNCHANGED', async () => {1009 document.location.search = '?id=component-one--a';1010 await createAndRenderPreview();1011 emitter.emit(Events.SET_CURRENT_STORY, {1012 storyId: 'component-one--a',1013 viewMode: 'story',1014 });1015 await waitForSetCurrentStory();1016 await waitForEvents([Events.STORY_UNCHANGED]);1017 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_UNCHANGED, 'component-one--a');1018 });1019 it('does NOT call renderToDOM', async () => {1020 document.location.search = '?id=component-one--a';1021 await createAndRenderPreview();1022 projectAnnotations.renderToDOM.mockClear();1023 emitter.emit(Events.SET_CURRENT_STORY, {1024 storyId: 'component-one--a',1025 viewMode: 'story',1026 });1027 await waitForSetCurrentStory();1028 // The renderToDOM would have been async so we need to wait a tick.1029 await waitForQuiescence();1030 expect(projectAnnotations.renderToDOM).not.toHaveBeenCalled();1031 });1032 });1033 describe('when changing story in story viewMode', () => {1034 it('updates URL', async () => {1035 document.location.search = '?id=component-one--a';1036 await createAndRenderPreview();1037 emitter.emit(Events.SET_CURRENT_STORY, {1038 storyId: 'component-one--b',1039 viewMode: 'story',1040 });1041 await waitForSetCurrentStory();1042 expect(history.replaceState).toHaveBeenCalledWith(1043 {},1044 '',1045 'pathname?id=component-one--b&viewMode=story'1046 );1047 });1048 it('renders preparing state', async () => {1049 document.location.search = '?id=component-one--a';1050 const preview = await createAndRenderPreview();1051 emitter.emit(Events.SET_CURRENT_STORY, {1052 storyId: 'component-one--b',1053 viewMode: 'story',1054 });1055 await waitForSetCurrentStory();1056 expect(preview.view.showPreparingStory).toHaveBeenCalled();1057 });1058 it('emits STORY_CHANGED', async () => {1059 document.location.search = '?id=component-one--a';1060 await createAndRenderPreview();1061 mockChannel.emit.mockClear();1062 emitter.emit(Events.SET_CURRENT_STORY, {1063 storyId: 'component-one--b',1064 viewMode: 'story',1065 });1066 await waitForSetCurrentStory();1067 await waitForEvents([Events.STORY_CHANGED]);1068 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--b');1069 });1070 it('emits STORY_PREPARED', async () => {1071 document.location.search = '?id=component-one--a';1072 await createAndRenderPreview();1073 mockChannel.emit.mockClear();1074 emitter.emit(Events.SET_CURRENT_STORY, {1075 storyId: 'component-one--b',1076 viewMode: 'story',1077 });1078 await waitForSetCurrentStory();1079 await waitForEvents([Events.STORY_PREPARED]);1080 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {1081 id: 'component-one--b',1082 parameters: {1083 __isArgsStory: false,1084 docs: { container: expect.any(Function) },1085 fileName: './src/ComponentOne.stories.js',1086 },1087 initialArgs: { foo: 'b' },1088 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1089 args: { foo: 'b' },1090 });1091 });1092 it('applies loaders with story context', async () => {1093 document.location.search = '?id=component-one--a';1094 await createAndRenderPreview();1095 mockChannel.emit.mockClear();1096 emitter.emit(Events.SET_CURRENT_STORY, {1097 storyId: 'component-one--b',1098 viewMode: 'story',1099 });1100 await waitForSetCurrentStory();1101 await waitForRender();1102 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(1103 expect.objectContaining({1104 id: 'component-one--b',1105 parameters: {1106 __isArgsStory: false,1107 docs: { container: expect.any(Function) },1108 fileName: './src/ComponentOne.stories.js',1109 },1110 initialArgs: { foo: 'b' },1111 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1112 args: { foo: 'b' },1113 })1114 );1115 });1116 it('passes loaded context to renderToDOM', async () => {1117 document.location.search = '?id=component-one--a';1118 await createAndRenderPreview();1119 mockChannel.emit.mockClear();1120 emitter.emit(Events.SET_CURRENT_STORY, {1121 storyId: 'component-one--b',1122 viewMode: 'story',1123 });1124 await waitForSetCurrentStory();1125 await waitForRender();1126 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1127 expect.objectContaining({1128 forceRemount: true,1129 storyContext: expect.objectContaining({1130 id: 'component-one--b',1131 parameters: {1132 __isArgsStory: false,1133 docs: { container: expect.any(Function) },1134 fileName: './src/ComponentOne.stories.js',1135 },1136 globals: { a: 'b' },1137 initialArgs: { foo: 'b' },1138 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1139 args: { foo: 'b' },1140 loaded: { l: 7 },1141 }),1142 }),1143 undefined // this is coming from view.prepareForStory, not super important1144 );1145 });1146 it('renders exception if renderToDOM throws', async () => {1147 document.location.search = '?id=component-one--a';1148 const preview = await createAndRenderPreview();1149 const error = new Error('error');1150 projectAnnotations.renderToDOM.mockImplementationOnce(() => {1151 throw error;1152 });1153 mockChannel.emit.mockClear();1154 emitter.emit(Events.SET_CURRENT_STORY, {1155 storyId: 'component-one--b',1156 viewMode: 'story',1157 });1158 await waitForSetCurrentStory();1159 await waitForRender();1160 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1161 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1162 });1163 it('renders error if the story calls showError', async () => {1164 document.location.search = '?id=component-one--a';1165 const preview = await createAndRenderPreview();1166 const error = { title: 'title', description: 'description' };1167 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1168 context.showError(error)1169 );1170 mockChannel.emit.mockClear();1171 emitter.emit(Events.SET_CURRENT_STORY, {1172 storyId: 'component-one--b',1173 viewMode: 'story',1174 });1175 await waitForSetCurrentStory();1176 await waitForRender();1177 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error);1178 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({1179 message: error.title,1180 stack: error.description,1181 });1182 });1183 it('renders exception if the story calls showException', async () => {1184 document.location.search = '?id=component-one--a';1185 const preview = await createAndRenderPreview();1186 const error = new Error('error');1187 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1188 context.showException(error)1189 );1190 mockChannel.emit.mockClear();1191 emitter.emit(Events.SET_CURRENT_STORY, {1192 storyId: 'component-one--b',1193 viewMode: 'story',1194 });1195 await waitForSetCurrentStory();1196 await waitForRender();1197 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1198 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1199 });1200 it('executes playFunction', async () => {1201 document.location.search = '?id=component-one--a';1202 await createAndRenderPreview();1203 mockChannel.emit.mockClear();1204 emitter.emit(Events.SET_CURRENT_STORY, {1205 storyId: 'component-one--b',1206 viewMode: 'story',1207 });1208 await waitForSetCurrentStory();1209 await waitForRender();1210 expect(componentOneExports.b.play).toHaveBeenCalled();1211 });1212 it('emits STORY_RENDERED', async () => {1213 document.location.search = '?id=component-one--a';1214 await createAndRenderPreview();1215 mockChannel.emit.mockClear();1216 emitter.emit(Events.SET_CURRENT_STORY, {1217 storyId: 'component-one--b',1218 viewMode: 'story',1219 });1220 await waitForSetCurrentStory();1221 await waitForRender();1222 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b');1223 });1224 it('retains any arg changes', async () => {1225 document.location.search = '?id=component-one--a';1226 const preview = await createAndRenderPreview();1227 mockChannel.emit.mockClear();1228 emitter.emit(Events.UPDATE_STORY_ARGS, {1229 storyId: 'component-one--a',1230 updatedArgs: { foo: 'updated' },1231 });1232 await waitForRender();1233 expect(preview.storyStore.args.get('component-one--a')).toEqual({1234 foo: 'updated',1235 });1236 mockChannel.emit.mockClear();1237 emitter.emit(Events.SET_CURRENT_STORY, {1238 storyId: 'component-one--b',1239 viewMode: 'story',1240 });1241 await waitForSetCurrentStory();1242 await waitForRender();1243 expect(preview.storyStore.args.get('component-one--a')).toEqual({1244 foo: 'updated',1245 });1246 mockChannel.emit.mockClear();1247 emitter.emit(Events.SET_CURRENT_STORY, {1248 storyId: 'component-one--a',1249 viewMode: 'story',1250 });1251 await waitForSetCurrentStory();1252 await waitForRender();1253 expect(preview.storyStore.args.get('component-one--a')).toEqual({1254 foo: 'updated',1255 });1256 });1257 describe('while story is still rendering', () => {1258 it('stops initial story after loaders if running', async () => {1259 const [gate, openGate] = createGate();1260 componentOneExports.default.loaders[0].mockImplementationOnce(async () => gate);1261 document.location.search = '?id=component-one--a';1262 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });1263 await waitForRenderPhase('loading');1264 emitter.emit(Events.SET_CURRENT_STORY, {1265 storyId: 'component-one--b',1266 viewMode: 'story',1267 });1268 await waitForSetCurrentStory();1269 await waitForRender();1270 // Now let the loader resolve1271 openGate({ l: 8 });1272 await waitForRender();1273 // Story gets rendered with updated args1274 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(1);1275 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1276 expect.objectContaining({1277 forceRemount: true,1278 storyContext: expect.objectContaining({1279 id: 'component-one--b',1280 loaded: { l: 7 },1281 }),1282 }),1283 undefined // this is coming from view.prepareForStory, not super important1284 );1285 });1286 it('aborts render for initial story', async () => {1287 const [gate, openGate] = createGate();1288 document.location.search = '?id=component-one--a';1289 projectAnnotations.renderToDOM.mockImplementationOnce(async () => gate);1290 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });1291 await waitForRenderPhase('rendering');1292 mockChannel.emit.mockClear();1293 emitter.emit(Events.SET_CURRENT_STORY, {1294 storyId: 'component-one--b',1295 viewMode: 'story',1296 });1297 await waitForSetCurrentStory();1298 // Now let the renderToDOM call resolve1299 openGate();1300 await waitForRenderPhase('aborted');1301 await waitForSetCurrentStory();1302 await waitForRenderPhase('rendering');1303 expect(projectAnnotations.renderToDOM).toHaveBeenCalledTimes(2);1304 await waitForRenderPhase('playing');1305 expect(componentOneExports.a.play).not.toHaveBeenCalled();1306 expect(componentOneExports.b.play).toHaveBeenCalled();1307 await waitForRenderPhase('completed');1308 expect(mockChannel.emit).not.toHaveBeenCalledWith(1309 Events.STORY_RENDERED,1310 'component-one--a'1311 );1312 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b');1313 await waitForQuiescence();1314 });1315 it('aborts play function for initial story', async () => {1316 const [gate, openGate] = createGate();1317 componentOneExports.a.play.mockImplementationOnce(async () => gate);1318 document.location.search = '?id=component-one--a';1319 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });1320 await waitForRenderPhase('playing');1321 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1322 expect.objectContaining({1323 forceRemount: true,1324 storyContext: expect.objectContaining({1325 id: 'component-one--a',1326 loaded: { l: 7 },1327 }),1328 }),1329 undefined // this is coming from view.prepareForStory, not super important1330 );1331 mockChannel.emit.mockClear();1332 emitter.emit(Events.SET_CURRENT_STORY, {1333 storyId: 'component-one--b',1334 viewMode: 'story',1335 });1336 await waitForSetCurrentStory();1337 // Now let the playFunction call resolve1338 openGate();1339 await waitForRenderPhase('aborted');1340 await waitForSetCurrentStory();1341 await waitForRenderPhase('rendering');1342 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--b');1343 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1344 expect.objectContaining({1345 forceRemount: true,1346 storyContext: expect.objectContaining({1347 id: 'component-one--b',1348 loaded: { l: 7 },1349 }),1350 }),1351 undefined // this is coming from view.prepareForStory, not super important1352 );1353 await waitForRenderPhase('playing');1354 await waitForRenderPhase('completed');1355 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--b');1356 // Final story rendered is not emitted for the first story1357 await waitForQuiescence();1358 expect(mockChannel.emit).not.toHaveBeenCalledWith(1359 Events.STORY_RENDERED,1360 'component-one--a'1361 );1362 });1363 it('reloads page if playFunction fails to abort in time', async () => {1364 const [gate] = createGate();1365 componentOneExports.a.play.mockImplementationOnce(async () => gate);1366 document.location.search = '?id=component-one--a';1367 await new PreviewWeb().initialize({ importFn, getProjectAnnotations });1368 await waitForRenderPhase('playing');1369 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1370 expect.objectContaining({1371 forceRemount: true,1372 storyContext: expect.objectContaining({1373 id: 'component-one--a',1374 loaded: { l: 7 },1375 }),1376 }),1377 undefined // this is coming from view.prepareForStory, not super important1378 );1379 mockChannel.emit.mockClear();1380 emitter.emit(Events.SET_CURRENT_STORY, {1381 storyId: 'component-one--b',1382 viewMode: 'story',1383 });1384 // Wait three ticks without resolving the play function1385 await waitForSetCurrentStory();1386 await waitForSetCurrentStory();1387 await waitForSetCurrentStory();1388 expect(global.window.location.reload).toHaveBeenCalled();1389 expect(mockChannel.emit).not.toHaveBeenCalledWith(1390 Events.STORY_CHANGED,1391 'component-one--b'1392 );1393 expect(projectAnnotations.renderToDOM).not.toHaveBeenCalledWith(1394 expect.objectContaining({1395 storyContext: expect.objectContaining({ id: 'component-one--b' }),1396 }),1397 undefined1398 );1399 });1400 });1401 });1402 describe('when changing from story viewMode to docs', () => {1403 it('updates URL', async () => {1404 document.location.search = '?id=component-one--a';1405 await createAndRenderPreview();1406 emitter.emit(Events.SET_CURRENT_STORY, {1407 storyId: 'component-one--a',1408 viewMode: 'docs',1409 });1410 await waitForSetCurrentStory();1411 expect(history.replaceState).toHaveBeenCalledWith(1412 {},1413 '',1414 'pathname?id=component-one--a&viewMode=docs'1415 );1416 });1417 it('renders preparing state', async () => {1418 document.location.search = '?id=component-one--a';1419 const preview = await createAndRenderPreview();1420 emitter.emit(Events.SET_CURRENT_STORY, {1421 storyId: 'component-one--a',1422 viewMode: 'docs',1423 });1424 await waitForSetCurrentStory();1425 expect(preview.view.showPreparingDocs).toHaveBeenCalled();1426 });1427 it('emits STORY_CHANGED', async () => {1428 document.location.search = '?id=component-one--a';1429 await createAndRenderPreview();1430 mockChannel.emit.mockClear();1431 emitter.emit(Events.SET_CURRENT_STORY, {1432 storyId: 'component-one--a',1433 viewMode: 'docs',1434 });1435 await waitForSetCurrentStory();1436 await waitForEvents([Events.STORY_CHANGED]);1437 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a');1438 });1439 it('calls view.prepareForDocs', async () => {1440 document.location.search = '?id=component-one--a';1441 const preview = await createAndRenderPreview();1442 mockChannel.emit.mockClear();1443 emitter.emit(Events.SET_CURRENT_STORY, {1444 storyId: 'component-one--a',1445 viewMode: 'docs',1446 });1447 await waitForSetCurrentStory();1448 await waitForRender();1449 expect(preview.view.prepareForDocs).toHaveBeenCalled();1450 });1451 it('render the docs container with the correct context', async () => {1452 document.location.search = '?id=component-one--a';1453 await createAndRenderPreview();1454 mockChannel.emit.mockClear();1455 emitter.emit(Events.SET_CURRENT_STORY, {1456 storyId: 'component-one--a',1457 viewMode: 'docs',1458 });1459 await waitForSetCurrentStory();1460 await waitForRender();1461 expect(ReactDOM.render).toHaveBeenCalledWith(1462 expect.objectContaining({1463 type: componentOneExports.default.parameters.docs.container,1464 props: expect.objectContaining({1465 context: expect.objectContaining({1466 id: 'component-one--a',1467 title: 'Component One',1468 name: 'A',1469 }),1470 }),1471 }),1472 undefined,1473 expect.any(Function)1474 );1475 });1476 it('emits DOCS_RENDERED', async () => {1477 document.location.search = '?id=component-one--a';1478 await createAndRenderPreview();1479 mockChannel.emit.mockClear();1480 emitter.emit(Events.SET_CURRENT_STORY, {1481 storyId: 'component-one--a',1482 viewMode: 'docs',1483 });1484 await waitForSetCurrentStory();1485 await waitForRender();1486 expect(mockChannel.emit).toHaveBeenCalledWith(Events.DOCS_RENDERED, 'component-one--a');1487 });1488 });1489 describe('when changing from docs viewMode to story', () => {1490 it('updates URL', async () => {1491 document.location.search = '?id=component-one--a&viewMode=docs';1492 await createAndRenderPreview();1493 emitter.emit(Events.SET_CURRENT_STORY, {1494 storyId: 'component-one--a',1495 viewMode: 'story',1496 });1497 await waitForSetCurrentStory();1498 expect(history.replaceState).toHaveBeenCalledWith(1499 {},1500 '',1501 'pathname?id=component-one--a&viewMode=story'1502 );1503 });1504 it('unmounts docs', async () => {1505 document.location.search = '?id=component-one--a&viewMode=docs';1506 await createAndRenderPreview();1507 mockChannel.emit.mockClear();1508 emitter.emit(Events.SET_CURRENT_STORY, {1509 storyId: 'component-one--a',1510 viewMode: 'story',1511 });1512 await waitForSetCurrentStory();1513 await waitForRender();1514 expect(ReactDOM.unmountComponentAtNode).toHaveBeenCalled();1515 });1516 // NOTE: I am not sure this entirely makes sense but this is the behaviour from 6.31517 it('emits STORY_CHANGED', async () => {1518 document.location.search = '?id=component-one--a&viewMode=docs';1519 await createAndRenderPreview();1520 mockChannel.emit.mockClear();1521 emitter.emit(Events.SET_CURRENT_STORY, {1522 storyId: 'component-one--a',1523 viewMode: 'story',1524 });1525 await waitForSetCurrentStory();1526 await waitForEvents([Events.STORY_CHANGED]);1527 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a');1528 });1529 it('calls view.prepareForStory', async () => {1530 document.location.search = '?id=component-one--a&viewMode=docs';1531 const preview = await createAndRenderPreview();1532 mockChannel.emit.mockClear();1533 emitter.emit(Events.SET_CURRENT_STORY, {1534 storyId: 'component-one--a',1535 viewMode: 'story',1536 });1537 await waitForSetCurrentStory();1538 await waitForRender();1539 expect(preview.view.prepareForStory).toHaveBeenCalledWith(1540 expect.objectContaining({1541 id: 'component-one--a',1542 })1543 );1544 });1545 it('emits STORY_PREPARED', async () => {1546 document.location.search = '?id=component-one--a&viewMode=docs';1547 await createAndRenderPreview();1548 mockChannel.emit.mockClear();1549 emitter.emit(Events.SET_CURRENT_STORY, {1550 storyId: 'component-one--a',1551 viewMode: 'story',1552 });1553 await waitForSetCurrentStory();1554 await waitForEvents([Events.STORY_PREPARED]);1555 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {1556 id: 'component-one--a',1557 parameters: {1558 __isArgsStory: false,1559 docs: { container: expect.any(Function) },1560 fileName: './src/ComponentOne.stories.js',1561 },1562 initialArgs: { foo: 'a' },1563 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1564 args: { foo: 'a' },1565 });1566 });1567 it('applies loaders with story context', async () => {1568 document.location.search = '?id=component-one--a&viewMode=docs';1569 await createAndRenderPreview();1570 mockChannel.emit.mockClear();1571 emitter.emit(Events.SET_CURRENT_STORY, {1572 storyId: 'component-one--a',1573 viewMode: 'story',1574 });1575 await waitForSetCurrentStory();1576 await waitForRender();1577 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(1578 expect.objectContaining({1579 id: 'component-one--a',1580 parameters: {1581 __isArgsStory: false,1582 docs: { container: expect.any(Function) },1583 fileName: './src/ComponentOne.stories.js',1584 },1585 initialArgs: { foo: 'a' },1586 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1587 args: { foo: 'a' },1588 })1589 );1590 });1591 it('passes loaded context to renderToDOM', async () => {1592 document.location.search = '?id=component-one--a&viewMode=docs';1593 await createAndRenderPreview();1594 mockChannel.emit.mockClear();1595 emitter.emit(Events.SET_CURRENT_STORY, {1596 storyId: 'component-one--a',1597 viewMode: 'story',1598 });1599 await waitForSetCurrentStory();1600 await waitForRender();1601 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1602 expect.objectContaining({1603 forceRemount: true,1604 storyContext: expect.objectContaining({1605 id: 'component-one--a',1606 parameters: {1607 __isArgsStory: false,1608 docs: { container: expect.any(Function) },1609 fileName: './src/ComponentOne.stories.js',1610 },1611 globals: { a: 'b' },1612 initialArgs: { foo: 'a' },1613 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1614 args: { foo: 'a' },1615 loaded: { l: 7 },1616 }),1617 }),1618 undefined // this is coming from view.prepareForStory, not super important1619 );1620 });1621 it('renders exception if renderToDOM throws', async () => {1622 document.location.search = '?id=component-one--a&viewMode=docs';1623 const preview = await createAndRenderPreview();1624 const error = new Error('error');1625 projectAnnotations.renderToDOM.mockImplementationOnce(() => {1626 throw error;1627 });1628 mockChannel.emit.mockClear();1629 emitter.emit(Events.SET_CURRENT_STORY, {1630 storyId: 'component-one--a',1631 viewMode: 'story',1632 });1633 await waitForSetCurrentStory();1634 await waitForRender();1635 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1636 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1637 });1638 it('renders error if the story calls showError', async () => {1639 const error = { title: 'title', description: 'description' };1640 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1641 context.showError(error)1642 );1643 document.location.search = '?id=component-one--a&viewMode=docs';1644 const preview = await createAndRenderPreview();1645 mockChannel.emit.mockClear();1646 emitter.emit(Events.SET_CURRENT_STORY, {1647 storyId: 'component-one--a',1648 viewMode: 'story',1649 });1650 await waitForSetCurrentStory();1651 await waitForRender();1652 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error);1653 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({1654 message: error.title,1655 stack: error.description,1656 });1657 });1658 it('renders exception if the story calls showException', async () => {1659 const error = new Error('error');1660 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1661 context.showException(error)1662 );1663 document.location.search = '?id=component-one--a&viewMode=docs';1664 const preview = await createAndRenderPreview();1665 mockChannel.emit.mockClear();1666 emitter.emit(Events.SET_CURRENT_STORY, {1667 storyId: 'component-one--a',1668 viewMode: 'story',1669 });1670 await waitForSetCurrentStory();1671 await waitForRender();1672 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1673 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1674 });1675 it('executes playFunction', async () => {1676 document.location.search = '?id=component-one--a&viewMode=docs';1677 await createAndRenderPreview();1678 mockChannel.emit.mockClear();1679 emitter.emit(Events.SET_CURRENT_STORY, {1680 storyId: 'component-one--a',1681 viewMode: 'story',1682 });1683 await waitForSetCurrentStory();1684 await waitForRender();1685 expect(componentOneExports.a.play).toHaveBeenCalled();1686 });1687 it('emits STORY_RENDERED', async () => {1688 document.location.search = '?id=component-one--a&viewMode=docs';1689 await createAndRenderPreview();1690 mockChannel.emit.mockClear();1691 emitter.emit(Events.SET_CURRENT_STORY, {1692 storyId: 'component-one--a',1693 viewMode: 'story',1694 });1695 await waitForSetCurrentStory();1696 await waitForRender();1697 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');1698 });1699 });1700 });1701 describe('onStoriesChanged', () => {1702 describe('if stories.json endpoint 500s initially', () => {1703 it('recovers and renders the story', async () => {1704 document.location.search = '?id=component-one--a';1705 const err = new Error('sort error');1706 mockFetchResult = { status: 500, text: async () => err.toString() };1707 const preview = new PreviewWeb();1708 await expect(preview.initialize({ importFn, getProjectAnnotations })).rejects.toThrow(1709 'sort error'1710 );1711 expect(preview.view.showErrorDisplay).toHaveBeenCalled();1712 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error));1713 mockChannel.emit.mockClear();1714 mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };1715 preview.onStoryIndexChanged();1716 await waitForRender();1717 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');1718 });1719 it('sets story args from the URL', async () => {1720 document.location.search = '?id=component-one--a&args=foo:url';1721 const err = new Error('sort error');1722 mockFetchResult = { status: 500, text: async () => err.toString() };1723 const preview = new PreviewWeb();1724 await expect(preview.initialize({ importFn, getProjectAnnotations })).rejects.toThrow(1725 'sort error'1726 );1727 expect(preview.view.showErrorDisplay).toHaveBeenCalled();1728 expect(mockChannel.emit).toHaveBeenCalledWith(Events.CONFIG_ERROR, expect.any(Error));1729 mockChannel.emit.mockClear();1730 mockFetchResult = { status: 200, json: mockStoryIndex, text: () => 'error text' };1731 preview.onStoryIndexChanged();1732 await waitForRender();1733 expect(preview.storyStore.args.get('component-one--a')).toEqual({1734 foo: 'url',1735 });1736 });1737 });1738 describe('when the current story changes', () => {1739 const newComponentOneExports = merge({}, componentOneExports, {1740 a: { args: { foo: 'edited' } },1741 });1742 const newImportFn = jest.fn(async (path) => {1743 return path === './src/ComponentOne.stories.js'1744 ? newComponentOneExports1745 : componentTwoExports;1746 });1747 it('does not emit STORY_UNCHANGED', async () => {1748 document.location.search = '?id=component-one--a';1749 const preview = await createAndRenderPreview();1750 mockChannel.emit.mockClear();1751 preview.onStoriesChanged({ importFn: newImportFn });1752 await waitForRender();1753 expect(mockChannel.emit).not.toHaveBeenCalledWith(1754 Events.STORY_UNCHANGED,1755 'component-one--a'1756 );1757 });1758 it('does not emit STORY_CHANGED', async () => {1759 document.location.search = '?id=component-one--a';1760 const preview = await createAndRenderPreview();1761 mockChannel.emit.mockClear();1762 preview.onStoriesChanged({ importFn: newImportFn });1763 await waitForRender();1764 expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a');1765 });1766 it('emits STORY_PREPARED with new annotations', async () => {1767 document.location.search = '?id=component-one--a';1768 const preview = await createAndRenderPreview();1769 mockChannel.emit.mockClear();1770 preview.onStoriesChanged({ importFn: newImportFn });1771 await waitForRender();1772 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_PREPARED, {1773 id: 'component-one--a',1774 parameters: {1775 __isArgsStory: false,1776 docs: { container: expect.any(Function) },1777 fileName: './src/ComponentOne.stories.js',1778 },1779 initialArgs: { foo: 'edited' },1780 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1781 args: { foo: 'edited' },1782 });1783 });1784 it('emits STORY_ARGS_UPDATED with new args', async () => {1785 document.location.search = '?id=component-one--a';1786 const preview = await createAndRenderPreview();1787 mockChannel.emit.mockClear();1788 preview.onStoriesChanged({ importFn: newImportFn });1789 await waitForRender();1790 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ARGS_UPDATED, {1791 storyId: 'component-one--a',1792 args: { foo: 'edited' },1793 });1794 });1795 it('applies loaders with story context', async () => {1796 document.location.search = '?id=component-one--a';1797 const preview = await createAndRenderPreview();1798 mockChannel.emit.mockClear();1799 componentOneExports.default.loaders[0].mockClear();1800 preview.onStoriesChanged({ importFn: newImportFn });1801 await waitForRender();1802 expect(componentOneExports.default.loaders[0]).toHaveBeenCalledWith(1803 expect.objectContaining({1804 id: 'component-one--a',1805 parameters: {1806 __isArgsStory: false,1807 docs: { container: expect.any(Function) },1808 fileName: './src/ComponentOne.stories.js',1809 },1810 initialArgs: { foo: 'edited' },1811 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1812 args: { foo: 'edited' },1813 })1814 );1815 });1816 it('passes loaded context to renderToDOM', async () => {1817 document.location.search = '?id=component-one--a';1818 const preview = await createAndRenderPreview();1819 mockChannel.emit.mockClear();1820 projectAnnotations.renderToDOM.mockClear();1821 preview.onStoriesChanged({ importFn: newImportFn });1822 await waitForRender();1823 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1824 expect.objectContaining({1825 forceRemount: true,1826 storyContext: expect.objectContaining({1827 id: 'component-one--a',1828 parameters: {1829 __isArgsStory: false,1830 docs: { container: expect.any(Function) },1831 fileName: './src/ComponentOne.stories.js',1832 },1833 globals: { a: 'b' },1834 initialArgs: { foo: 'edited' },1835 argTypes: { foo: { name: 'foo', type: { name: 'string' } } },1836 args: { foo: 'edited' },1837 loaded: { l: 7 },1838 }),1839 }),1840 undefined // this is coming from view.prepareForStory, not super important1841 );1842 });1843 it('retains the same delta to the args', async () => {1844 document.location.search = '?id=component-one--a';1845 const preview = await createAndRenderPreview();1846 mockChannel.emit.mockClear();1847 emitter.emit(Events.UPDATE_STORY_ARGS, {1848 storyId: 'component-one--a',1849 updatedArgs: { foo: 'updated' },1850 });1851 await waitForRender();1852 mockChannel.emit.mockClear();1853 projectAnnotations.renderToDOM.mockClear();1854 preview.onStoriesChanged({ importFn: newImportFn });1855 await waitForRender();1856 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(1857 expect.objectContaining({1858 forceRemount: true,1859 storyContext: expect.objectContaining({1860 id: 'component-one--a',1861 args: { foo: 'updated' },1862 }),1863 }),1864 undefined // this is coming from view.prepareForStory, not super important1865 );1866 });1867 it('renders exception if renderToDOM throws', async () => {1868 document.location.search = '?id=component-one--a';1869 const preview = await createAndRenderPreview();1870 const error = new Error('error');1871 projectAnnotations.renderToDOM.mockImplementationOnce(() => {1872 throw error;1873 });1874 mockChannel.emit.mockClear();1875 preview.onStoriesChanged({ importFn: newImportFn });1876 await waitForRender();1877 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1878 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1879 });1880 it('renders error if the story calls showError', async () => {1881 document.location.search = '?id=component-one--a';1882 const preview = await createAndRenderPreview();1883 const error = { title: 'title', description: 'description' };1884 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1885 context.showError(error)1886 );1887 mockChannel.emit.mockClear();1888 preview.onStoriesChanged({ importFn: newImportFn });1889 await waitForRender();1890 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_ERRORED, error);1891 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith({1892 message: error.title,1893 stack: error.description,1894 });1895 });1896 it('renders exception if the story calls showException', async () => {1897 document.location.search = '?id=component-one--a';1898 const preview = await createAndRenderPreview();1899 const error = new Error('error');1900 projectAnnotations.renderToDOM.mockImplementationOnce((context) =>1901 context.showException(error)1902 );1903 mockChannel.emit.mockClear();1904 preview.onStoriesChanged({ importFn: newImportFn });1905 await waitForRender();1906 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_THREW_EXCEPTION, error);1907 expect(preview.view.showErrorDisplay).toHaveBeenCalledWith(error);1908 });1909 it('executes playFunction', async () => {1910 document.location.search = '?id=component-one--a';1911 const preview = await createAndRenderPreview();1912 mockChannel.emit.mockClear();1913 componentOneExports.a.play.mockClear();1914 preview.onStoriesChanged({ importFn: newImportFn });1915 await waitForRender();1916 expect(componentOneExports.a.play).toHaveBeenCalled();1917 });1918 it('emits STORY_RENDERED', async () => {1919 document.location.search = '?id=component-one--a';1920 const preview = await createAndRenderPreview();1921 mockChannel.emit.mockClear();1922 preview.onStoriesChanged({ importFn: newImportFn });1923 await waitForRender();1924 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_RENDERED, 'component-one--a');1925 });1926 });1927 describe('when the current story changes importPath', () => {1928 const newImportFn = jest.fn(async (path) => ({ ...componentOneExports }));1929 const newStoryIndex = {1930 v: 3,1931 stories: {1932 ...storyIndex.stories,1933 'component-one--a': {1934 ...storyIndex.stories['component-one--a'],1935 importPath: './src/ComponentOne-new.stories.js',1936 },1937 },1938 };1939 beforeEach(() => {1940 newImportFn.mockClear();1941 });1942 it('re-imports the component', async () => {1943 document.location.search = '?id=component-one--a';1944 const preview = await createAndRenderPreview();1945 mockChannel.emit.mockClear();1946 preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });1947 await waitForRender();1948 expect(newImportFn).toHaveBeenCalledWith('./src/ComponentOne-new.stories.js');1949 });1950 describe('if it was previously rendered', () => {1951 beforeEach(() => jest.useFakeTimers());1952 afterEach(() => jest.useRealTimers());1953 it('is reloaded when it is re-selected', async () => {1954 document.location.search = '?id=component-one--a';1955 const preview = await createAndRenderPreview();1956 mockChannel.emit.mockClear();1957 emitter.emit(Events.SET_CURRENT_STORY, {1958 storyId: 'component-one--b',1959 viewMode: 'story',1960 });1961 await waitForSetCurrentStory();1962 await waitForRender();1963 preview.onStoriesChanged({ importFn: newImportFn, storyIndex: newStoryIndex });1964 mockChannel.emit.mockClear();1965 emitter.emit(Events.SET_CURRENT_STORY, {1966 storyId: 'component-one--a',1967 viewMode: 'story',1968 });1969 await waitForSetCurrentStory();1970 await waitForRender();1971 expect(newImportFn).toHaveBeenCalledWith('./src/ComponentOne-new.stories.js');1972 });1973 });1974 });1975 describe('when the current story has not changed', () => {1976 const newComponentTwoExports = { ...componentTwoExports };1977 const newImportFn = jest.fn(async (path) => {1978 return path === './src/ComponentOne.stories.js'1979 ? componentOneExports1980 : newComponentTwoExports;1981 });1982 it('emits STORY_UNCHANGED', async () => {1983 document.location.search = '?id=component-one--a';1984 const preview = await createAndRenderPreview();1985 mockChannel.emit.mockClear();1986 preview.onStoriesChanged({ importFn: newImportFn });1987 await waitForEvents([Events.STORY_UNCHANGED]);1988 expect(mockChannel.emit).toHaveBeenCalledWith(Events.STORY_UNCHANGED, 'component-one--a');1989 expect(mockChannel.emit).not.toHaveBeenCalledWith(Events.STORY_CHANGED, 'component-one--a');1990 });1991 it('clears preparing state', async () => {1992 document.location.search = '?id=component-one--a';1993 const preview = await createAndRenderPreview();1994 (preview.view.showMain as jest.Mock).mockClear();1995 mockChannel.emit.mockClear();1996 preview.onStoriesChanged({ importFn: newImportFn });1997 await waitForEvents([Events.STORY_UNCHANGED]);1998 expect(preview.view.showMain).toHaveBeenCalled();1999 });2000 it('does not re-render the story', async () => {2001 document.location.search = '?id=component-one--a';2002 const preview = await createAndRenderPreview();2003 mockChannel.emit.mockClear();2004 projectAnnotations.renderToDOM.mockClear();2005 preview.onStoriesChanged({ importFn: newImportFn });2006 await waitForQuiescence();2007 expect(projectAnnotations.renderToDOM).not.toHaveBeenCalled();2008 expect(mockChannel.emit).not.toHaveBeenCalledWith(2009 Events.STORY_RENDERED,2010 'component-one--a'2011 );2012 });2013 });2014 describe('when another (not current) story changes', () => {2015 beforeEach(() => {2016 jest.useFakeTimers();2017 });2018 afterEach(() => {2019 jest.useRealTimers();2020 });2021 const newComponentOneExports = merge({}, componentOneExports, {2022 a: { args: { bar: 'edited' }, argTypes: { bar: { type: { name: 'string' } } } },2023 });2024 const newImportFn = jest.fn(async (path) => {2025 return path === './src/ComponentOne.stories.js'2026 ? newComponentOneExports2027 : componentTwoExports;2028 });2029 it('retains the same delta to the args', async () => {2030 // Start at Story A2031 document.location.search = '?id=component-one--a';2032 const preview = await createAndRenderPreview();2033 // Change A's args2034 mockChannel.emit.mockClear();2035 emitter.emit(Events.UPDATE_STORY_ARGS, {2036 storyId: 'component-one--a',2037 updatedArgs: { foo: 'updated' },2038 });2039 await waitForRender();2040 // Change to story B2041 mockChannel.emit.mockClear();2042 emitter.emit(Events.SET_CURRENT_STORY, {2043 storyId: 'component-one--b',2044 viewMode: 'story',2045 });2046 await waitForSetCurrentStory();2047 await waitForRender();2048 expect(preview.storyStore.args.get('component-one--a')).toEqual({2049 foo: 'updated',2050 });2051 // Update story A's args via HMR2052 mockChannel.emit.mockClear();2053 projectAnnotations.renderToDOM.mockClear();2054 preview.onStoriesChanged({ importFn: newImportFn });2055 await waitForRender();2056 // Change back to Story A2057 mockChannel.emit.mockClear();2058 emitter.emit(Events.SET_CURRENT_STORY, {2059 storyId: 'component-one--a',2060 viewMode: 'story',2061 });2062 await waitForSetCurrentStory();2063 await waitForRender();2064 expect(preview.storyStore.args.get('component-one--a')).toEqual({2065 foo: 'updated',2066 bar: 'edited',2067 });2068 expect(projectAnnotations.renderToDOM).toHaveBeenCalledWith(2069 expect.objectContaining({2070 forceRemount: true,2071 storyContext: expect.objectContaining({2072 id: 'component-one--a',2073 args: { foo: 'updated', bar: 'edited' },2074 }),2075 }),2076 undefined // this is coming from view.prepareForStory, not super important...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1import { waitForSetCurrentStory } from 'storybook-root-provider';2import { waitForElementToBeRemoved } from '@testing-library/react';3const waitForSetCurrentStory = async () => {4 await waitForElementToBeRemoved(() => document.querySelector('.sb-show-main'));5};6const story = await waitForSetCurrentStory();7const storyId = story.id;

Full Screen

Using AI Code Generation

copy

Full Screen

1export function getCurrentStory() {2 return store.getState().storyStore.storyFn;3}4export function waitForSetCurrentStory() {5 return new Promise((resolve, reject) => {6 const unsubscribe = store.subscribe(() => {7 const { storyStore } = store.getState();8 if (storyStore.storyFn) {9 unsubscribe();10 resolve();11 }12 });13 });14}15export function getStorybook() {16 return store.getState().storyStore.storybook;17}18export function getStorybookUI(options) {19 return StorybookUI(options);20}21export function configure(loadStories, module) {22 const { clientApi, storyStore } = store.getState();23 clientApi.clearDecorators();24 clientApi.setAddon(addons);25 storyStore.clearGlobalDecorators();26 loadStories();27 if (module && module.hot) {28 module.hot.accept(() => {29 const currentExports = module.__proto__.exports;30 Object.keys(currentExports).forEach(key => delete currentExports[key]);31 loadStories();32 });33 }34}35export function setAddon(addon) {36 const { clientApi } = store.getState();37 clientApi.setAddon(addon);38}39export function addDecorator(decorator) {40 const { clientApi } = store.getState();41 clientApi.addDecorator(decorator);42}43export function addParameters(parameters) {44 const { clientApi } = store.getState();45 clientApi.addParameters(parameters);46}47export function clearDecorators() {48 const { clientApi } = store.getState();49 clientApi.clearDecorators();50}51export function forceReRender() {52 const { storyStore } = store.getState();53 storyStore.forceReRender();54}55export function setAddon(add

Full Screen

Using AI Code Generation

copy

Full Screen

1const { waitForSetCurrentStory } = require('test-storybook-root-element');2const storySelector = 'my-story';3const story = {4 props: { foo: 'bar' },5};6describe('My Story', () => {7 it('should render', async () => {8 await waitForSetCurrentStory(storySelector, story);9 });10});11import { html } from 'lit-html';12import { storiesOf } from '@open-wc/demoing-storybook';13import '../my-story.js';14storiesOf('My Story', module)15 .add('My Story', () => html`16 `);17### waitForSetCurrentStory(storySelector, story)18- `storySelector` (string): The story selector19- `story` (object): The story to set in the storybook-root-element20[MIT License](./LICENSE)

Full Screen

Using AI Code Generation

copy

Full Screen

1const waitForSetCurrentStory = (story) => {2 return new Promise((resolve) => {3 const storybookRootElm = document.querySelector('storybook-root-elm');4 storybookRootElm.waitForSetCurrentStory(story).then(resolve);5 });6};7const waitForSetCurrentStory = (story) => {8 return new Promise((resolve) => {9 const storybookRootElm = document.querySelector('storybook-root-elm');10 storybookRootElm.waitForSetCurrentStory(story).then(resolve);11 });12};13const waitForSetCurrentStory = (story) => {14 return new Promise((resolve) => {15 const storybookRootElm = document.querySelector('storybook-root-elm');16 storybookRootElm.waitForSetCurrentStory(story).then(resolve);17 });18};19const waitForSetCurrentStory = (story) => {20 return new Promise((resolve) => {21 const storybookRootElm = document.querySelector('storybook-root-elm');22 storybookRootElm.waitForSetCurrentStory(story).then(resolve);23 });24};25const waitForSetCurrentStory = (story) => {26 return new Promise((resolve) => {27 const storybookRootElm = document.querySelector('storybook-root-elm

Full Screen

Automation Testing Tutorials

Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.

LambdaTest Learning Hubs:

YouTube

You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.

Run storybook-root automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful