From 623d2d08236a771795ffbbcf98809dd412f17a3d Mon Sep 17 00:00:00 2001 From: Dhenain Ambroise Date: Sat, 16 Jan 2021 20:03:50 +0100 Subject: [PATCH] Refactor withChildrenMock > withPropMock for simpler and more reusable usage --- src/stories/nrn/dataDisplay/Btn.stories.tsx | 4 +- .../nrn/dataDisplay/CircleBtn.stories.tsx | 4 +- .../dataDisplay/DocumentButton.stories.tsx | 4 +- .../nrn/dataDisplay/ExternalLink.stories.tsx | 4 +- .../nrn/dataDisplay/LinkButton.stories.tsx | 4 +- src/stories/nrn/dataDisplay/Stamp.stories.tsx | 4 +- src/stories/nrn/dataDisplay/Text.stories.tsx | 4 +- src/stories/nrn/i18n/I18nLink.stories.tsx | 4 +- src/stories/nrn/layout/Cards.stories.tsx | 3 +- .../nrn/overlay/SimpleTooltip.stories.tsx | 4 +- src/stories/nrn/overlay/Tooltip.stories.tsx | 7 +- src/stories/nrn/text/EllipsisText.stories.tsx | 4 +- src/stories/shared/hocs/withChildrenMock.tsx | 71 ---------------- src/stories/shared/hocs/withPropMock.tsx | 81 +++++++++++++++++++ 14 files changed, 107 insertions(+), 95 deletions(-) delete mode 100644 src/stories/shared/hocs/withChildrenMock.tsx create mode 100644 src/stories/shared/hocs/withPropMock.tsx diff --git a/src/stories/nrn/dataDisplay/Btn.stories.tsx b/src/stories/nrn/dataDisplay/Btn.stories.tsx index 1c841c26a..cc3d1b69f 100644 --- a/src/stories/nrn/dataDisplay/Btn.stories.tsx +++ b/src/stories/nrn/dataDisplay/Btn.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import Btn, { Props } from '../../../components/utils/Btn'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/Btn', component: Btn, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/CircleBtn.stories.tsx b/src/stories/nrn/dataDisplay/CircleBtn.stories.tsx index 790bb9bf2..2826bba87 100644 --- a/src/stories/nrn/dataDisplay/CircleBtn.stories.tsx +++ b/src/stories/nrn/dataDisplay/CircleBtn.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import CircleBtn, { Props } from '../../../components/utils/CircleBtn'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/CircleBtn', component: CircleBtn, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/DocumentButton.stories.tsx b/src/stories/nrn/dataDisplay/DocumentButton.stories.tsx index ff142bf42..0e188aacb 100644 --- a/src/stories/nrn/dataDisplay/DocumentButton.stories.tsx +++ b/src/stories/nrn/dataDisplay/DocumentButton.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import DocumentButton, { Props } from '../../../components/utils/DocumentButton'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/DocumentButton', component: DocumentButton, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/ExternalLink.stories.tsx b/src/stories/nrn/dataDisplay/ExternalLink.stories.tsx index 2ff2bfb7c..429d01ae4 100644 --- a/src/stories/nrn/dataDisplay/ExternalLink.stories.tsx +++ b/src/stories/nrn/dataDisplay/ExternalLink.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import ExternalLink, { Props } from '../../../components/utils/ExternalLink'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/ExternalLink', component: ExternalLink, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/LinkButton.stories.tsx b/src/stories/nrn/dataDisplay/LinkButton.stories.tsx index e66fb9a42..c0a7f9ec0 100644 --- a/src/stories/nrn/dataDisplay/LinkButton.stories.tsx +++ b/src/stories/nrn/dataDisplay/LinkButton.stories.tsx @@ -5,7 +5,7 @@ import { import React from 'react'; import ExternalLink from '../../../components/utils/ExternalLink'; import LinkButton, { Props } from '../../../components/utils/LinkButton'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -16,7 +16,7 @@ export default { title: 'Next Right Now/Data display/LinkButton', component: LinkButton, subcomponents: { ExternalLink }, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/Stamp.stories.tsx b/src/stories/nrn/dataDisplay/Stamp.stories.tsx index 7c681f2ad..7778194e8 100644 --- a/src/stories/nrn/dataDisplay/Stamp.stories.tsx +++ b/src/stories/nrn/dataDisplay/Stamp.stories.tsx @@ -5,7 +5,7 @@ import { import React from 'react'; import EllipsisText from '../../../components/utils/EllipsisText'; import Stamp, { Props } from '../../../components/utils/Stamp'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string | React.ReactElement; @@ -14,7 +14,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/Stamp', component: Stamp, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/dataDisplay/Text.stories.tsx b/src/stories/nrn/dataDisplay/Text.stories.tsx index 8129243f6..274f98b74 100644 --- a/src/stories/nrn/dataDisplay/Text.stories.tsx +++ b/src/stories/nrn/dataDisplay/Text.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import Text, { Props } from '../../../components/utils/Text'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Data display/Text', component: Text, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/i18n/I18nLink.stories.tsx b/src/stories/nrn/i18n/I18nLink.stories.tsx index c847f9a9f..8363e3a02 100644 --- a/src/stories/nrn/i18n/I18nLink.stories.tsx +++ b/src/stories/nrn/i18n/I18nLink.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import I18nLink, { Props } from '../../../components/i18n/I18nLink'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; import styles from './I18nLink.module.css'; type PropsWithChildrenMock = { @@ -15,7 +15,7 @@ type PropsWithChildrenMock = { export default { title: 'Next Right Now/I18n/I18nLink', component: I18nLink, - argTypes: withChildrenMock({ + argTypes: withPropMock({ wrapChildrenAsLink: { control: { disable: true, // Disable field because it crashes the UI when being used (expected behavior but bad UX) diff --git a/src/stories/nrn/layout/Cards.stories.tsx b/src/stories/nrn/layout/Cards.stories.tsx index 8bd86f70f..00bd6fef5 100644 --- a/src/stories/nrn/layout/Cards.stories.tsx +++ b/src/stories/nrn/layout/Cards.stories.tsx @@ -15,12 +15,11 @@ import I18nLink from '../../../components/i18n/I18nLink'; import Btn from '../../../components/utils/Btn'; import Cards, { Props } from '../../../components/utils/Cards'; import ExternalLink from '../../../components/utils/ExternalLink'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; export default { title: 'Next Right Now/Layout/Cards', component: Cards, - argTypes: withChildrenMock({}, { hasChildrenMock: false }), + argTypes: {}, } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/overlay/SimpleTooltip.stories.tsx b/src/stories/nrn/overlay/SimpleTooltip.stories.tsx index cae5027ff..f4ef16734 100644 --- a/src/stories/nrn/overlay/SimpleTooltip.stories.tsx +++ b/src/stories/nrn/overlay/SimpleTooltip.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import SimpleTooltip, { Props } from '../../../components/utils/SimpleTooltip'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -14,7 +14,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Overlay/SimpleTooltip', component: SimpleTooltip, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/overlay/Tooltip.stories.tsx b/src/stories/nrn/overlay/Tooltip.stories.tsx index 44bce5640..d35b2c108 100644 --- a/src/stories/nrn/overlay/Tooltip.stories.tsx +++ b/src/stories/nrn/overlay/Tooltip.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import Tooltip, { Props } from '../../../components/utils/Tooltip'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -14,7 +14,10 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Overlay/Tooltip', component: Tooltip, - argTypes: withChildrenMock({}), + argTypes: withPropMock(withPropMock({}, { + propName: 'overlay', + propMockName: 'tooltipText', + })), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/nrn/text/EllipsisText.stories.tsx b/src/stories/nrn/text/EllipsisText.stories.tsx index 258bab2d7..46cb02ec6 100644 --- a/src/stories/nrn/text/EllipsisText.stories.tsx +++ b/src/stories/nrn/text/EllipsisText.stories.tsx @@ -4,7 +4,7 @@ import { } from '@storybook/react/types-6-0'; import React from 'react'; import EllipsisText, { Props } from '../../../components/utils/EllipsisText'; -import withChildrenMock from '../../shared/hocs/withChildrenMock'; +import withPropMock from '../../shared/hocs/withPropMock'; type PropsWithChildrenMock = Props & { text?: string; @@ -13,7 +13,7 @@ type PropsWithChildrenMock = Props & { export default { title: 'Next Right Now/Text/EllipsisText', component: EllipsisText, - argTypes: withChildrenMock({}), + argTypes: withPropMock({}), } as Meta; const Template: Story = (props) => { diff --git a/src/stories/shared/hocs/withChildrenMock.tsx b/src/stories/shared/hocs/withChildrenMock.tsx deleted file mode 100644 index eca3b2b02..000000000 --- a/src/stories/shared/hocs/withChildrenMock.tsx +++ /dev/null @@ -1,71 +0,0 @@ -import { ArgTypes } from '@storybook/addons/dist/types'; - -/** - * HOC options. - */ -type Options = { - hasChildren?: boolean; - hasChildrenMock?: boolean; - childrenMockName?: string; -}; - -/** - * Options applied by default. - */ -const defaultOptions: Partial = { - hasChildren: true, - hasChildrenMock: true, - childrenMockName: 'text', -}; - -/** - * Mocks the "argTypes" to automatically disable `children` control and add a mock field (default: `text`) with default documentation. - * Helps avoid code duplication - */ -const withChildrenMock = (argTypes: ArgTypes, options?: Options): ArgTypes => { - const { - hasChildren, - hasChildrenMock, - childrenMockName, - } = { ...defaultOptions, ...options || {} }; - let computedArgTypes: ArgTypes; - - // If there is a "children" property, disable its interactivity - if (hasChildren) { - computedArgTypes = { - ...argTypes, - - /** - * Disables children control by default, as it's often JSX and not user-friendly. - * Also, can often crash the app if not proper children is passed down, bad UX. - */ - children: { - control: { - disable: true, - }, - }, - }; - - if (hasChildrenMock) { - computedArgTypes = { - ...computedArgTypes, - - /** - * `children` mock field, meant to replace the `children` prop by providing interactivity (controls enabled). - * Must be added to the Story `args` with a default value to be interactive. - * - * @default text - */ - [childrenMockName]: { - description: `children mock.

MockThis property doesn't really exist in the component.
It is made available to help manipulate the children from Storybook
.

You must use children instead during actual code implementation.`, - }, - }; - } - - return computedArgTypes; - } else { - return argTypes; - } -}; - -export default withChildrenMock; diff --git a/src/stories/shared/hocs/withPropMock.tsx b/src/stories/shared/hocs/withPropMock.tsx new file mode 100644 index 000000000..d7a2b9820 --- /dev/null +++ b/src/stories/shared/hocs/withPropMock.tsx @@ -0,0 +1,81 @@ +import { ArgTypes } from '@storybook/addons/dist/types'; + +/** + * HOC options. + */ +type Options = { + /** + * Name of the property to mock. + * + * Disables `children` by default, because it's the main reason why we use this HOC. + * Also, can often crash the app if not proper `children` is passed down, bad UX. + * + * @default children + */ + propName: string; + + /** + * Whether to mock the `propName`. + * + * @default true + */ + shouldMockProp?: boolean; + + /** + * Name of the property that mocks the `propName`. + * + * Replaces `children` prop by `text` by default, because that's our most common use-case. + * + * @default text + */ + propMockName?: string; +}; + +/** + * Options applied by default. + */ +const defaultOptions: Partial = { + propName: 'children', + shouldMockProp: true, + propMockName: 'text', +}; + +/** + * Mocks the "argTypes" to automatically disable `children` control and add a mock field (default: `text`) with default documentation. + * Helps avoid code duplication + */ +const withPropMock = (argTypes: ArgTypes, options?: Options): ArgTypes => { + const { + propName, + shouldMockProp, + propMockName, + } = { ...defaultOptions, ...options || {} }; + let computedArgTypes: ArgTypes; + + if (shouldMockProp) { + computedArgTypes = { + ...argTypes, + + /** + * Disables `propName` control. + */ + [propName]: { + control: { + disable: true, + }, + }, + + /** + * `propName` mock field, meant to replace the `propName` prop by providing interactivity (controls enabled). + * Must be added to the Story `args` with a default value to be interactive. + */ + [propMockName]: { + description: `${propName} mock property.

MockThis property doesn't really exist in the component.
It is made available to help manipulate the ${propName} from Storybook
.

You must use ${propName} instead during actual code implementation.`, + }, + }; + } + + return computedArgTypes; +}; + +export default withPropMock;