How to use includeStories method in storybook-root

Best JavaScript code snippet using storybook-root

mdx2.test.ts

Source:mdx2.test.ts Github

copy

Full Screen

1import { dedent } from 'ts-dedent';2import prettier from 'prettier';3import { compileSync, SEPARATOR, wrapperJs } from './mdx2';4// @ts-ignore5expect.addSnapshotSerializer({6 print: (val: any) => val,7 test: (val) => true,8});9const clean = (mdx: string) => {10 const code = compileSync(mdx);11 const trimmed = code.split(SEPARATOR)[1].split(wrapperJs)[0];12 return prettier13 .format(trimmed, {14 parser: 'babel',15 printWidth: 100,16 tabWidth: 2,17 bracketSpacing: true,18 trailingComma: 'es5',19 singleQuote: true,20 })21 .trim();22};23describe('mdx2', () => {24 it('works', () => {25 const input = dedent`26 # hello27 <Meta title="foobar" />28 world {2 + 1}29 <Story name="foo">bar</Story>30 `;31 // @ts-ignore32 expect(clean(input)).toMatchInlineSnapshot(`33 export const foo = () => 'bar';34 foo.storyName = 'foo';35 foo.parameters = { storySource: { source: '"bar"' } };36 const componentMeta = { title: 'foobar', includeStories: ['foo'] };37 const mdxStoryNameToKey = { foo: 'foo' };38 `);39 });40 it('full snapshot', () => {41 const input = dedent`42 # hello43 <Meta title="foobar" />44 world {2 + 1}45 <Story name="foo">bar</Story>46 `;47 // @ts-ignore48 expect(compileSync(input)).toMatchInlineSnapshot(`49 /*@jsxRuntime automatic @jsxImportSource react*/50 import { assertIsFn, AddContext } from "@storybook/addon-docs";51 import {Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs} from "react/jsx-runtime";52 function MDXContent(props = {}) {53 const {wrapper: MDXLayout} = props.components || ({});54 return MDXLayout ? _jsx(MDXLayout, Object.assign({}, props, {55 children: _jsx(_createMdxContent, {})56 })) : _createMdxContent();57 function _createMdxContent() {58 const _components = Object.assign({59 h1: "h1",60 p: "p"61 }, props.components), {Meta, Story} = _components;62 if (!Meta) _missingMdxReference("Meta", true);63 if (!Story) _missingMdxReference("Story", true);64 return _jsxs(_Fragment, {65 children: [_jsx(_components.h1, {66 children: "hello"67 }), "\\n", _jsx(Meta, {68 title: "foobar"69 }), "\\n", _jsxs(_components.p, {70 children: ["world ", 2 + 1]71 }), "\\n", _jsx(Story, {72 name: "foo",73 children: "bar"74 })]75 });76 }77 }78 function _missingMdxReference(id, component) {79 throw new Error("Expected " + (component ? "component" : "object") + " \`" + id + "\` to be defined: you likely forgot to import, pass, or provide it.");80 }81 // =========82 export const foo = () => (83 "bar"84 );85 foo.storyName = 'foo';86 foo.parameters = { storySource: { source: '\\"bar\\"' } };87 const componentMeta = { title: 'foobar', includeStories: ["foo"], };88 const mdxStoryNameToKey = {"foo":"foo"};89 componentMeta.parameters = componentMeta.parameters || {};90 componentMeta.parameters.docs = {91 ...(componentMeta.parameters.docs || {}),92 page: () => <AddContext mdxStoryNameToKey={mdxStoryNameToKey} mdxComponentAnnotations={componentMeta}><MDXContent /></AddContext>,93 };94 export default componentMeta;95 `);96 });97 it('standalone jsx expressions', () => {98 expect(99 clean(dedent`100 # Standalone JSX expressions101 {3 + 3}102 `)103 ).toMatchInlineSnapshot(`104 const componentMeta = { includeStories: [] };105 const mdxStoryNameToKey = {};106 `);107 });108});109describe('docs-mdx-compiler-plugin', () => {110 it('component-args.mdx', () => {111 expect(112 clean(dedent`113 import { Button } from '@storybook/react/demo';114 import { Story, Meta } from '@storybook/addon-docs';115 <Meta title="Button" args={{ a: 1, b: 2 }} argTypes={{ a: { name: 'A' }, b: { name: 'B' } }} />116 # Args117 <Story name="component notes">118 <Button>Component notes</Button>119 </Story>120 `)121 ).toMatchInlineSnapshot(`122 export const componentNotes = () => <Button>{'Component notes'}</Button>;123 componentNotes.storyName = 'component notes';124 componentNotes.parameters = { storySource: { source: '<Button>{"Component notes"}</Button>' } };125 const componentMeta = {126 title: 'Button',127 args: {128 a: 1,129 b: 2,130 },131 argTypes: {132 a: {133 name: 'A',134 },135 b: {136 name: 'B',137 },138 },139 includeStories: ['componentNotes'],140 };141 const mdxStoryNameToKey = { 'component notes': 'componentNotes' };142 `);143 });144 it('component-id.mdx', () => {145 expect(146 clean(dedent`147 import { Button } from '@storybook/react/demo';148 import { Story, Meta } from '@storybook/addon-docs';149 150 <Meta title="Button" component={Button} id="button-id" />151 152 <Story name="component notes">153 <Button>Component notes</Button>154 </Story> 155 `)156 ).toMatchInlineSnapshot(`157 export const componentNotes = () => <Button>{'Component notes'}</Button>;158 componentNotes.storyName = 'component notes';159 componentNotes.parameters = { storySource: { source: '<Button>{"Component notes"}</Button>' } };160 const componentMeta = {161 title: 'Button',162 id: 'button-id',163 component: Button,164 includeStories: ['componentNotes'],165 };166 const mdxStoryNameToKey = { 'component notes': 'componentNotes' };167 `);168 });169 it('csf-imports.mdx', () => {170 expect(171 clean(dedent`172 import { Story, Meta, Canvas } from '@storybook/addon-docs';173 import { Welcome, Button } from '@storybook/angular/demo';174 import * as MyStories from './My.stories';175 import { Other } from './Other.stories';176 177 <Meta title="MDX/CSF imports" />178 179 # Stories from CSF imports180 181 <Story story={MyStories.Basic} />182 183 <Canvas>184 <Story story={Other} />185 </Canvas>186 187 <Story name="renamed" story={MyStories.Foo} /> 188 `)189 ).toMatchInlineSnapshot(`190 export const _Basic_ = MyStories.Basic;191 export const _Other_ = Other;192 export const _Foo_ = MyStories.Foo;193 _Foo_.storyName = 'renamed';194 const componentMeta = { title: 'MDX/CSF imports', includeStories: ['_Basic_', '_Other_', '_Foo_'] };195 const mdxStoryNameToKey = { _Basic_: '_Basic_', _Other_: '_Other_', renamed: '_Foo_' };196 `);197 });198 it('decorators.mdx', () => {199 expect(200 clean(dedent`201 import { Button } from '@storybook/react/demo';202 import { Story, Meta } from '@storybook/addon-docs';203 <Meta204 title="Button"205 decorators={[(storyFn) => <div style={{ backgroundColor: 'yellow' }}>{storyFn()}</div>]}206 />207 # Decorated story208 <Story name="one" decorators={[(storyFn) => <div className="local">{storyFn()}</div>]}>209 <Button>One</Button>210 </Story>211 `)212 ).toMatchInlineSnapshot(`213 export const one = () => <Button>{'One'}</Button>;214 one.storyName = 'one';215 one.parameters = { storySource: { source: '<Button>{"One"}</Button>' } };216 one.decorators = [(storyFn) => <div className="local">{storyFn()}</div>];217 const componentMeta = {218 title: 'Button',219 decorators: [220 (storyFn) => (221 <div222 style={{223 backgroundColor: 'yellow',224 }}225 >226 {storyFn()}227 </div>228 ),229 ],230 includeStories: ['one'],231 };232 const mdxStoryNameToKey = { one: 'one' };233 `);234 });235 it('docs-only.mdx', () => {236 expect(237 clean(dedent`238 import { Meta } from '@storybook/addon-docs';239 <Meta title="docs-only" />240 # Documentation only241 This is a documentation-only MDX file which cleans a dummy 'docsOnly: true' story.242 `)243 ).toMatchInlineSnapshot(`244 export const __page = () => {245 throw new Error('Docs-only story');246 };247 __page.parameters = { docsOnly: true };248 const componentMeta = { title: 'docs-only', includeStories: ['__page'] };249 const mdxStoryNameToKey = {};250 `);251 });252 it('loaders.mdx', () => {253 expect(254 clean(dedent`255 import { Button } from '@storybook/react/demo';256 import { Story, Meta } from '@storybook/addon-docs';257 <Meta title="Button" loaders={[async () => ({ foo: 1 })]} />258 # Story with loader259 <Story name="one" loaders={[async () => ({ bar: 2 })]}>260 <Button>One</Button>261 </Story>262 `)263 ).toMatchInlineSnapshot(`264 export const one = () => <Button>{'One'}</Button>;265 one.storyName = 'one';266 one.parameters = { storySource: { source: '<Button>{"One"}</Button>' } };267 one.loaders = [268 async () => ({269 bar: 2,270 }),271 ];272 const componentMeta = {273 title: 'Button',274 loaders: [275 async () => ({276 foo: 1,277 }),278 ],279 includeStories: ['one'],280 };281 const mdxStoryNameToKey = { one: 'one' };282 `);283 });284 it('meta-quotes-in-title.mdx', () => {285 expect(286 clean(dedent`287 import { Meta } from '@storybook/addon-docs';288 <Meta title="Addons/Docs/what's in a title?" />289 `)290 ).toMatchInlineSnapshot(`291 export const __page = () => {292 throw new Error('Docs-only story');293 };294 __page.parameters = { docsOnly: true };295 const componentMeta = { title: "Addons/Docs/what's in a title?", includeStories: ['__page'] };296 const mdxStoryNameToKey = {};297 `);298 });299 it('non-story-exports.mdx', () => {300 expect(301 clean(dedent`302 import { Button } from '@storybook/react/demo';303 import { Story, Meta } from '@storybook/addon-docs';304 <Meta title="Button" />305 # Story definition306 <Story name="one">307 <Button>One</Button>308 </Story>309 export const two = 2;310 <Story name="hello story">311 <Button>Hello button</Button>312 </Story>313 `)314 ).toMatchInlineSnapshot(`315 export const one = () => <Button>{'One'}</Button>;316 one.storyName = 'one';317 one.parameters = { storySource: { source: '<Button>{"One"}</Button>' } };318 export const helloStory = () => <Button>{'Hello button'}</Button>;319 helloStory.storyName = 'hello story';320 helloStory.parameters = { storySource: { source: '<Button>{"Hello button"}</Button>' } };321 const componentMeta = { title: 'Button', includeStories: ['one', 'helloStory'] };322 const mdxStoryNameToKey = { one: 'one', 'hello story': 'helloStory' };323 `);324 });325 it('parameters.mdx', () => {326 expect(327 clean(dedent`328 import { Button } from '@storybook/react/demo';329 import { Story, Meta } from '@storybook/addon-docs';330 <Meta title="Button" component={Button} parameters={{ notes: 'component notes' }} />331 <Story name="component notes">332 <Button>Component notes</Button>333 </Story>334 <Story name="story notes" parameters={{ notes: 'story notes' }}>335 <Button>Story notes</Button>336 </Story>337 `)338 ).toMatchInlineSnapshot(`339 export const componentNotes = () => <Button>{'Component notes'}</Button>;340 componentNotes.storyName = 'component notes';341 componentNotes.parameters = { storySource: { source: '<Button>{"Component notes"}</Button>' } };342 export const storyNotes = () => <Button>{'Story notes'}</Button>;343 storyNotes.storyName = 'story notes';344 storyNotes.parameters = {345 storySource: { source: '<Button>{"Story notes"}</Button>' },346 ...{347 notes: 'story notes',348 },349 };350 const componentMeta = {351 title: 'Button',352 parameters: {353 notes: 'component notes',354 },355 component: Button,356 includeStories: ['componentNotes', 'storyNotes'],357 };358 const mdxStoryNameToKey = { 'component notes': 'componentNotes', 'story notes': 'storyNotes' };359 `);360 });361 it('previews.mdx', () => {362 expect(363 clean(dedent`364 import { Button } from '@storybook/react/demo';365 import { Canvas, Story, Meta } from '@storybook/addon-docs';366 <Meta title="Button" component={Button} parameters={{ notes: 'component notes' }} />367 # Canvas368 Canvases can contain normal components, stories, and story references369 <Canvas>370 <Button>Just a button</Button>371 <Story name="hello button">372 <Button>Hello button</Button>373 </Story>374 <Story name="two">375 <Button>Two</Button>376 </Story>377 <Story id="welcome--welcome" />378 </Canvas>379 Canvas without a story380 <Canvas>381 <Button>Just a button</Button>382 </Canvas>383 `)384 ).toMatchInlineSnapshot(`385 export const helloButton = () => <Button>{'Hello button'}</Button>;386 helloButton.storyName = 'hello button';387 helloButton.parameters = { storySource: { source: '<Button>{"Hello button"}</Button>' } };388 export const two = () => <Button>{'Two'}</Button>;389 two.storyName = 'two';390 two.parameters = { storySource: { source: '<Button>{"Two"}</Button>' } };391 const componentMeta = {392 title: 'Button',393 parameters: {394 notes: 'component notes',395 },396 component: Button,397 includeStories: ['helloButton', 'two'],398 };399 const mdxStoryNameToKey = { 'hello button': 'helloButton', two: 'two' };400 `);401 });402 it('story-args.mdx', () => {403 expect(404 clean(dedent`405 import { Button } from '@storybook/react/demo';406 import { Story, Meta } from '@storybook/addon-docs';407 <Meta title="Button" />408 # Args409 export const Template = (args) => <Button>Component notes</Button>;410 <Story411 name="component notes"412 args={{ a: 1, b: 2 }}413 argTypes={{ a: { name: 'A' }, b: { name: 'B' } }}414 >415 {Template.bind({})}416 </Story>417 `)418 ).toMatchInlineSnapshot(`419 export const componentNotes = Template.bind({});420 componentNotes.storyName = 'component notes';421 componentNotes.argTypes = {422 a: {423 name: 'A',424 },425 b: {426 name: 'B',427 },428 };429 componentNotes.args = {430 a: 1,431 b: 2,432 };433 componentNotes.parameters = { storySource: { source: 'args => <Button>Component notes</Button>' } };434 const componentMeta = { title: 'Button', includeStories: ['componentNotes'] };435 const mdxStoryNameToKey = { 'component notes': 'componentNotes' };436 `);437 });438 it('story-current.mdx', () => {439 expect(440 clean(dedent`441 import { Story } from '@storybook/addon-docs';442 # Current story443 <Story id="." />444 `)445 ).toMatchInlineSnapshot(`446 const componentMeta = { includeStories: [] };447 const mdxStoryNameToKey = {};448 `);449 });450 it('story-def-text-only.mdx', () => {451 expect(452 clean(dedent`453 import { Story, Meta } from '@storybook/addon-docs';454 <Meta title="Text" />455 # Story definition456 <Story name="text">Plain text</Story>457 `)458 ).toMatchInlineSnapshot(`459 export const text = () => 'Plain text';460 text.storyName = 'text';461 text.parameters = { storySource: { source: '"Plain text"' } };462 const componentMeta = { title: 'Text', includeStories: ['text'] };463 const mdxStoryNameToKey = { text: 'text' };464 `);465 });466 it('story-definitions.mdx', () => {467 expect(468 clean(dedent`469 import { Button } from '@storybook/react/demo';470 import { Story, Meta } from '@storybook/addon-docs';471 472 <Meta title="Button" />473 474 # Story definition475 476 <Story name="one">477 <Button>One</Button>478 </Story>479 480 <Story name="hello story">481 <Button>Hello button</Button>482 </Story>483 484 <Story name="w/punctuation">485 <Button>with punctuation</Button>486 </Story>487 488 <Story name="1 fine day">489 <Button>starts with number</Button>490 </Story>491 `)492 ).toMatchInlineSnapshot(`493 export const one = () => <Button>{'One'}</Button>;494 one.storyName = 'one';495 one.parameters = { storySource: { source: '<Button>{"One"}</Button>' } };496 export const helloStory = () => <Button>{'Hello button'}</Button>;497 helloStory.storyName = 'hello story';498 helloStory.parameters = { storySource: { source: '<Button>{"Hello button"}</Button>' } };499 export const wPunctuation = () => <Button>{'with punctuation'}</Button>;500 wPunctuation.storyName = 'w/punctuation';501 wPunctuation.parameters = { storySource: { source: '<Button>{"with punctuation"}</Button>' } };502 export const _1FineDay = () => <Button>{'starts with number'}</Button>;503 _1FineDay.storyName = '1 fine day';504 _1FineDay.parameters = { storySource: { source: '<Button>{"starts with number"}</Button>' } };505 const componentMeta = {506 title: 'Button',507 includeStories: ['one', 'helloStory', 'wPunctuation', '_1FineDay'],508 };509 const mdxStoryNameToKey = {510 one: 'one',511 'hello story': 'helloStory',512 'w/punctuation': 'wPunctuation',513 '1 fine day': '_1FineDay',514 };515 `);516 });517 it('story-function-var.mdx', () => {518 expect(519 clean(dedent`520 import { Meta, Story } from '@storybook/addon-docs';521 <Meta title="story-function-var" />522 523 export const basicFn = () => <Button />;524 525 # Button526 527 I can define a story with the function defined in CSF:528 529 <Story name="basic">{basicFn}</Story> 530 `)531 ).toMatchInlineSnapshot(`532 export const basic = assertIsFn(basicFn);533 basic.storyName = 'basic';534 basic.parameters = { storySource: { source: 'basicFn' } };535 const componentMeta = { title: 'story-function-var', includeStories: ['basic'] };536 const mdxStoryNameToKey = { basic: 'basic' };537 `);538 });539 it('story-function.mdx', () => {540 expect(541 clean(dedent`542 <Story name="function" height="100px">543 {() => {544 const btn = document.createElement('button');545 btn.innerHTML = 'Hello Button';546 btn.addEventListener('click', action('Click'));547 return btn;548 }}549 </Story>550 `)551 ).toMatchInlineSnapshot(`552 export const functionStory = () => {553 const btn = document.createElement('button');554 btn.innerHTML = 'Hello Button';555 btn.addEventListener('click', action('Click'));556 return btn;557 };558 functionStory.storyName = 'function';559 functionStory.parameters = {560 storySource: {561 source:562 '() => {\\n const btn = document.createElement("button");\\n btn.innerHTML = "Hello Button";\\n btn.addEventListener("click", action("Click"));\\n return btn;\\n}',563 },564 };565 const componentMeta = { includeStories: ['functionStory'] };566 const mdxStoryNameToKey = { function: 'functionStory' };567 `);568 });569 it('story-multiple-children.mdx', () => {570 expect(571 clean(dedent`572 import { Story, Meta } from '@storybook/addon-docs';573 <Meta title="Multiple" />574 575 # Multiple children576 577 <Story name="multiple children">578 <p>Hello Child #1</p>579 <p>Hello Child #2</p>580 </Story>581 `)582 ).toMatchInlineSnapshot(`583 export const multipleChildren = () => (584 <>585 <p>{'Hello Child #1'}</p>586 "\\n"587 <p>{'Hello Child #2'}</p>588 </>589 );590 multipleChildren.storyName = 'multiple children';591 multipleChildren.parameters = {592 storySource: { source: '<p>{"Hello Child #1"}</p>\\n"\\\\n"\\n<p>{"Hello Child #2"}</p>' },593 };594 const componentMeta = { title: 'Multiple', includeStories: ['multipleChildren'] };595 const mdxStoryNameToKey = { 'multiple children': 'multipleChildren' };596 `);597 });598 it('story-object.mdx', () => {599 expect(600 clean(dedent`601 import { Story, Meta } from '@storybook/addon-docs';602 import { Welcome, Button } from '@storybook/angular/demo';603 import { linkTo } from '@storybook/addon-links';604 605 <Meta title="MDX|Welcome" />606 607 # Story object608 609 <Story name="to storybook" height="300px">610 {{611 template: '<storybook-welcome-component (showApp)="showApp()"></storybook-welcome-component>',612 props: {613 showApp: linkTo('Button'),614 },615 moduleMetadata: {616 declarations: [Welcome],617 },618 }}619 </Story>620 `)621 ).toMatchInlineSnapshot(`622 export const toStorybook = () => ({623 template: '<storybook-welcome-component (showApp)="showApp()"></storybook-welcome-component>',624 props: {625 showApp: linkTo('Button'),626 },627 moduleMetadata: {628 declarations: [Welcome],629 },630 });631 toStorybook.storyName = 'to storybook';632 toStorybook.parameters = {633 storySource: {634 source:635 '{\\n template: "<storybook-welcome-component (showApp)=\\\\"showApp()\\\\"></storybook-welcome-component>",\\n props: {\\n showApp: linkTo("Button")\\n },\\n moduleMetadata: {\\n declarations: [Welcome]\\n }\\n}',636 },637 };638 const componentMeta = { title: 'MDX|Welcome', includeStories: ['toStorybook'] };639 const mdxStoryNameToKey = { 'to storybook': 'toStorybook' };640 `);641 });642 it('story-references.mdx', () => {643 expect(644 clean(dedent`645 import { Story } from '@storybook/addon-docs';646 # Story reference647 <Story id="welcome--welcome" />648 `)649 ).toMatchInlineSnapshot(`650 const componentMeta = { includeStories: [] };651 const mdxStoryNameToKey = {};652 `);653 });654 it('title-template-string.mdx', () => {655 expect(656 clean(657 [658 "import { Meta, Story } from '@storybook/addon-docs';",659 "import { titleFunction } from '../title-generators';",660 '',661 // eslint-disable-next-line no-template-curly-in-string662 "<Meta title={`${titleFunction('template')}`} />",663 ].join('\n')664 )665 ).toMatchInlineSnapshot(`666 export const __page = () => {667 throw new Error('Docs-only story');668 };669 __page.parameters = { docsOnly: true };670 const componentMeta = { title: \`\${titleFunction('template')}\`, includeStories: ['__page'] };671 const mdxStoryNameToKey = {};672 `);673 });674 it('vanilla.mdx', () => {675 expect(676 clean(dedent`677 import { Button } from '@storybook/react/demo';678 # Hello MDX679 This is some random content.680 <Button>Hello button</Button>681 `)682 ).toMatchInlineSnapshot(`683 const componentMeta = { includeStories: [] };684 const mdxStoryNameToKey = {};685 `);686 });687 it('errors on missing story props', async () => {688 await expect(async () =>689 clean(dedent`690 import { Button } from '@storybook/react/demo';691 import { Story, Meta } from '@storybook/addon-docs';692 <Meta title="Button" />693 # Bad story694 <Story>695 <Button>One</Button>696 </Story> 697 `)698 ).rejects.toThrow('Expected a Story name, id, or story attribute');699 });700 describe('csf3', () => {701 it('auto-title-docs-only.mdx', () => {702 expect(703 clean(dedent`704 import { Meta } from '@storybook/addon-docs';705 706 <Meta />707 708 # Auto-title Docs Only709 Spme **markdown** here!710 `)711 ).toMatchInlineSnapshot(`712 export const __page = () => {713 throw new Error('Docs-only story');714 };715 __page.parameters = { docsOnly: true };716 const componentMeta = { includeStories: ['__page'] };717 const mdxStoryNameToKey = {};718 `);719 });720 it('auto-title.mdx', () => {721 expect(722 clean(dedent`723 import { Button } from '@storybook/react/demo';724 import { Story, Meta } from '@storybook/addon-docs';725 <Meta component={Button} />726 <Story name="Basic">727 <Button>Basic</Button>728 </Story>729 `)730 ).toMatchInlineSnapshot(`731 export const basic = () => <Button>{'Basic'}</Button>;732 basic.storyName = 'Basic';733 basic.parameters = { storySource: { source: '<Button>{"Basic"}</Button>' } };734 const componentMeta = { component: Button, includeStories: ['basic'] };735 const mdxStoryNameToKey = { Basic: 'basic' };736 `);737 });738 it('default-render.mdx', () => {739 expect(740 clean(dedent`741 import { Button } from '@storybook/react/demo';742 import { Story, Meta } from '@storybook/addon-docs';743 <Meta title="Button" component={Button} />744 <Story name="Basic" />745 `)746 ).toMatchInlineSnapshot(`747 export const basic = {};748 basic.storyName = 'Basic';749 basic.parameters = { storySource: { source: '{}' } };750 const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };751 const mdxStoryNameToKey = { Basic: 'basic' };752 `);753 });754 it('component-render.mdx', () => {755 expect(756 clean(dedent`757 import { Button } from '@storybook/react/demo';758 import { Story, Meta } from '@storybook/addon-docs';759 <Meta title="Button" component={Button} render={(args) => <Button {...args} />} />760 <Story name="Basic" />761 `)762 ).toMatchInlineSnapshot(`763 export const basic = {};764 basic.storyName = 'Basic';765 basic.parameters = { storySource: { source: '{}' } };766 const componentMeta = {767 title: 'Button',768 component: Button,769 render: (args) => <Button {...args} />,770 includeStories: ['basic'],771 };772 const mdxStoryNameToKey = { Basic: 'basic' };773 `);774 });775 it('story-render.mdx', () => {776 expect(777 clean(dedent`778 import { Button } from '@storybook/react/demo';779 import { Story, Meta } from '@storybook/addon-docs';780 <Meta title="Button" component={Button} />781 <Story name="Basic" render={(args) => <Button {...args} />} />782 `)783 ).toMatchInlineSnapshot(`784 export const basic = {};785 basic.storyName = 'Basic';786 basic.parameters = { storySource: { source: '{}' } };787 basic.render = (args) => <Button {...args} />;788 const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };789 const mdxStoryNameToKey = { Basic: 'basic' };790 `);791 });792 it('story-play.mdx', () => {793 expect(794 clean(dedent`795 import { Button } from '@storybook/react/demo';796 import { Story, Meta } from '@storybook/addon-docs';797 <Meta title="Button" component={Button} />798 <Story name="Basic" play={() => console.log('play')} />799 `)800 ).toMatchInlineSnapshot(`801 export const basic = {};802 basic.storyName = 'Basic';803 basic.parameters = { storySource: { source: '{}' } };804 basic.play = () => console.log('play');805 const componentMeta = { title: 'Button', component: Button, includeStories: ['basic'] };806 const mdxStoryNameToKey = { Basic: 'basic' };807 `);808 });809 });810 it('style tag', () => {811 expect(812 clean(dedent`813 import { Meta } from '@storybook/addon-docs';814 <Meta title="Example/Introduction" />815 <style>{\`816 .subheading {817 --mediumdark: '#999999';818 font-weight: 900;819 font-size: 13px;820 color: #999;821 letter-spacing: 6px;822 line-height: 24px;823 text-transform: uppercase;824 margin-bottom: 12px;825 margin-top: 40px;826 }827 .link-list {828 display: grid;829 grid-template-columns: 1fr;830 grid-template-rows: 1fr 1fr;831 row-gap: 10px;832 }833 \`}</style>834 `)835 ).toMatchInlineSnapshot(`836 export const __page = () => {837 throw new Error('Docs-only story');838 };839 __page.parameters = { docsOnly: true };840 const componentMeta = { title: 'Example/Introduction', includeStories: ['__page'] };841 const mdxStoryNameToKey = {};842 `);843 });...

Full Screen

Full Screen

mdx.ts

Source:mdx.ts Github

copy

Full Screen

1// import recast from 'recast';2import mdx from '@mdx-js/mdx'3import prettier from 'prettier'4import { sanitizeName, prettify } from '../support'5/**6 * Convert a component's MDX file into module story format7 */8export function mdxTransformer(file, api) {9 const j = api.jscodeshift10 const code = mdx.sync(file.source, {})11 const root = j(code)12 function parseJsxAttributes(attributes) {13 const result = {}14 attributes.forEach((attr) => {15 const key = attr.name.name16 const val =17 attr.value.type === 'JSXExpressionContainer'18 ? attr.value.expression19 : attr.value20 result[key] = val21 })22 return result23 }24 function genObjectExpression(attrs) {25 return j.objectExpression(26 Object.entries(attrs).map(([key, val]) =>27 j.property('init', j.identifier(key), val),28 ),29 )30 }31 function convertToStories(path) {32 const base = j(path)33 const meta: any = {}34 const includeStories = []35 const storyStatements = []36 // get rid of all mdxType junk37 base.find(j.JSXAttribute)38 .filter((attr) => attr.node.name.name === 'mdxType')39 .remove()40 // parse <Meta title="..." />41 base.find(j.JSXElement)42 .filter((elt) => elt.node.openingElement.name.name === 'Meta')43 .forEach((elt) => {44 const attrs = parseJsxAttributes(45 elt.node.openingElement.attributes,46 )47 Object.assign(meta, attrs)48 })49 // parse <Story name="..." />50 base.find(j.JSXElement)51 .filter((elt) => elt.node.openingElement.name.name === 'Story')52 .forEach((elt) => {53 const attrs: any = parseJsxAttributes(54 elt.node.openingElement.attributes,55 )56 if (attrs.name) {57 const storyKey = sanitizeName(attrs.name.value)58 includeStories.push(storyKey)59 if (storyKey === attrs.name.value) {60 delete attrs.name61 }62 let body =63 elt.node.children.find((n) => n.type !== 'JSXText') ||64 j.literal(elt.node.children[0].value)65 if (body.type === 'JSXExpressionContainer') {66 body = body.expression67 }68 storyStatements.push(69 j.exportDeclaration(70 false,71 j.variableDeclaration('const', [72 j.variableDeclarator(73 j.identifier(storyKey),74 body.type === 'ArrowFunctionExpression'75 ? body76 : j.arrowFunctionExpression([], body),77 ),78 ]),79 ),80 )81 if (Object.keys(attrs).length > 0) {82 storyStatements.push(83 j.assignmentStatement(84 '=',85 j.memberExpression(86 j.identifier(storyKey),87 j.identifier('story'),88 ),89 genObjectExpression(attrs),90 ),91 )92 }93 storyStatements.push(j.emptyStatement())94 }95 })96 if (root.find(j.ExportNamedDeclaration).size() > 0) {97 meta.includeStories = j.arrayExpression(98 includeStories.map((key) => j.literal(key)),99 )100 }101 const statements = [102 j.exportDefaultDeclaration(genObjectExpression(meta)),103 j.emptyStatement(),104 ...storyStatements,105 ]106 const lastStatement = root.find(j.Statement).at(-1)107 statements.reverse().forEach((stmt) => {108 lastStatement.insertAfter(stmt)109 })110 base.remove()111 }112 root.find(j.ExportDefaultDeclaration).forEach(convertToStories)113 // strip out Story/Meta import and MDX junk114 // /* @jsx mdx */115 root.find(j.ImportDeclaration)116 .at(0)117 .replaceWith((exp) =>118 j.importDeclaration(exp.node.specifiers, exp.node.source),119 )120 // import { Story, Meta } from '@storybook/addon-docs/blocks';121 root.find(j.ImportDeclaration)122 .filter(123 (exp) => exp.node.source.value === '@storybook/addon-docs/blocks',124 )125 .remove()126 // const makeShortcode = ...127 // const layoutProps = {};128 // const MDXLayout = 'wrapper';129 const MDX_DECLS = ['makeShortcode', 'layoutProps', 'MDXLayout']130 root.find(j.VariableDeclaration)131 .filter(132 (decl) =>133 decl.node.declarations.length === 1 &&134 MDX_DECLS.includes(decl.node.declarations[0].id.name),135 )136 .remove()137 // const Source = makeShortcode('Source');138 root.find(j.VariableDeclarator)139 .filter(140 (expr) =>141 expr.node.init.type === 'CallExpression' &&142 expr.node.init.callee.type === 'Identifier' &&143 expr.node.init.callee.name === 'makeShortcode',144 )145 .remove()146 // MDXContent.isMDXComponent = true;147 root.find(j.AssignmentExpression)148 .filter(149 (expr) =>150 expr.node.left.type === 'MemberExpression' &&151 expr.node.left.object.type === 'Identifier' &&152 expr.node.left.object.name === 'MDXContent',153 )154 .remove()155 // Add back `import React from 'react';` which is implicit in MDX156 const react = root157 .find(j.ImportDeclaration)158 .filter((decl) => decl.node.source.value === 'react')159 if (react.size() === 0) {160 root.find(j.Statement)161 .at(0)162 .insertBefore(163 j.importDeclaration(164 [j.importDefaultSpecifier(j.identifier('React'))],165 j.literal('react'),166 ),167 )168 }169 const source = root.toSource({170 trailingComma: true,171 quote: 'single',172 tabWidth: 2,173 })174 return prettify(source)...

Full Screen

Full Screen

mdx2.ts

Source:mdx2.ts Github

copy

Full Screen

1import generate from '@babel/generator';2import * as t from '@babel/types';3import cloneDeep from 'lodash/cloneDeep';4import toBabel from 'estree-to-babel';5// Keeping as much code as possible from the original compiler to avoid breaking changes6import {7 genCanvasExports,8 genStoryExport,9 genMeta,10 CompilerOptions,11 Context,12 MetaExport,13 wrapperJs,14 stringifyMeta,15} from './sb-mdx-plugin';16export const SEPARATOR = '// =========';17export { wrapperJs };18function extractExports(root: t.File, options: CompilerOptions) {19 const context: Context = {20 counter: 0,21 storyNameToKey: {},22 namedExports: {},23 };24 const storyExports = [];25 const includeStories = [];26 let metaExport: MetaExport | null = null;27 const { code } = generate(root, {});28 let contents: t.ExpressionStatement;29 root.program.body.forEach((child) => {30 if (t.isExpressionStatement(child) && t.isJSXFragment(child.expression)) {31 if (contents) throw new Error('duplicate contents');32 contents = child;33 } else if (34 t.isExportNamedDeclaration(child) &&35 t.isVariableDeclaration(child.declaration) &&36 child.declaration.declarations.length === 137 ) {38 const declaration = child.declaration.declarations[0];39 if (t.isVariableDeclarator(declaration) && t.isIdentifier(declaration.id)) {40 const { name } = declaration.id;41 context.namedExports[name] = declaration.init;42 }43 }44 });45 if (contents) {46 const jsx = contents.expression as t.JSXFragment;47 jsx.children.forEach((child) => {48 if (t.isJSXElement(child)) {49 if (t.isJSXIdentifier(child.openingElement.name)) {50 const name = child.openingElement.name.name;51 let stories;52 if (['Canvas', 'Preview'].includes(name)) {53 stories = genCanvasExports(child, context);54 } else if (name === 'Story') {55 stories = genStoryExport(child, context);56 } else if (name === 'Meta') {57 const meta = genMeta(child, options);58 if (meta) {59 if (metaExport) {60 throw new Error('Meta can only be declared once');61 }62 metaExport = meta;63 }64 }65 if (stories) {66 Object.entries(stories).forEach(([key, story]) => {67 includeStories.push(key);68 storyExports.push(story);69 });70 }71 }72 } else if (t.isJSXExpressionContainer(child)) {73 // Skip string literals & other JSX expressions74 } else {75 throw new Error(`Unexpected JSX child: ${child.type}`);76 }77 });78 }79 if (metaExport) {80 if (!storyExports.length) {81 storyExports.push('export const __page = () => { throw new Error("Docs-only story"); };');82 storyExports.push('__page.parameters = { docsOnly: true };');83 includeStories.push('__page');84 }85 } else {86 metaExport = {};87 }88 metaExport.includeStories = JSON.stringify(includeStories);89 const fullJsx = [90 ...storyExports,91 `const componentMeta = ${stringifyMeta(metaExport)};`,92 `const mdxStoryNameToKey = ${JSON.stringify(context.storyNameToKey)};`,93 wrapperJs,94 'export default componentMeta;',95 ].join('\n\n');96 return fullJsx;97}98export const plugin = (store: any) => (root: any) => {99 const estree = store.toEstree(root);100 // toBabel mutates root, so we need to clone it101 const clone = cloneDeep(estree);102 const babel = toBabel(clone);103 store.exports = extractExports(babel, {});104 return root;105};106export const postprocess = (code: string, extractedExports: string) => {107 const lines = code.toString().trim().split('\n');108 // /*@jsxRuntime automatic @jsxImportSource react*/109 const first = lines.shift();110 return [111 first,112 'import { assertIsFn, AddContext } from "@storybook/addon-docs";',113 ...lines.filter((line) => !line.match(/^export default/)),114 SEPARATOR,115 extractedExports,116 ].join('\n');117};118export const mdxSync = (code: string) => {119 const { compileSync } = require('@mdx-js/mdx');120 const { toEstree } = require('hast-util-to-estree');121 const store = { exports: '', toEstree };122 const output = compileSync(code, {123 rehypePlugins: [[plugin, store]],124 });125 return postprocess(output.toString(), store.exports);126};...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1const req = require.context('../src', true, /\.stories\.js$/);2function loadStories() {3 req.keys().forEach(filename => req(filename));4}5configure(loadStories, module);6import { configure } from '@storybook/react';7import { setOptions } from '@storybook/addon-options';8import { setDefaults } from '@storybook/addon-info';9setOptions({

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