Adding storybook tests on meta-types/display/components (#1862)

* working on a story for MoneyFieldDisplay

* Write test on MoneyDisplayField
This commit is contained in:
bosiraphael
2023-10-04 13:26:06 +02:00
committed by GitHub
parent aab2f3ab3c
commit 46dffeadef
6 changed files with 196 additions and 35 deletions

View File

@ -3,7 +3,7 @@ import { createContext } from 'react';
import { FieldDefinition } from '../types/FieldDefinition'; import { FieldDefinition } from '../types/FieldDefinition';
import { FieldMetadata } from '../types/FieldMetadata'; import { FieldMetadata } from '../types/FieldMetadata';
type GenericFieldContextType = { export type GenericFieldContextType = {
fieldDefinition: FieldDefinition<FieldMetadata>; fieldDefinition: FieldDefinition<FieldMetadata>;
// TODO: add better typing for mutation hook // TODO: add better typing for mutation hook
useUpdateEntityMutation: () => [(params: any) => void, any]; useUpdateEntityMutation: () => [(params: any) => void, any];

View File

@ -0,0 +1,35 @@
import {
FieldContext,
GenericFieldContextType,
} from '@/ui/field/contexts/FieldContext';
type FieldDisplayContextProviderProps = {
children: React.ReactNode;
fieldDefinition: GenericFieldContextType['fieldDefinition'];
entityId?: string;
};
export const FieldDisplayContextProvider = ({
children,
fieldDefinition,
entityId,
}: FieldDisplayContextProviderProps) => {
return (
<FieldContext.Provider
value={{
entityId: entityId ?? '1',
recoilScopeId: '1',
hotkeyScope: 'hotkey-scope',
fieldDefinition,
useUpdateEntityMutation: () => [
() => {
return;
},
{},
],
}}
>
{children}
</FieldContext.Provider>
);
};

View File

@ -0,0 +1,112 @@
import { useEffect } from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { v4 } from 'uuid';
import { CatalogDecorator } from '~/testing/decorators/CatalogDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CatalogStory } from '~/testing/types';
import { useMoneyField } from '../../../hooks/useMoneyField';
import { MoneyFieldDisplay } from '../MoneyFieldDisplay';
import { FieldDisplayContextProvider } from './FieldDisplayContextProvider';
const MoneyFieldValueSetterEffect = ({ value }: { value: number }) => {
const { setFieldValue } = useMoneyField();
useEffect(() => {
setFieldValue(value);
}, [setFieldValue, value]);
return <></>;
};
type MoneyFieldDisplayWithContextProps = {
value: number;
entityId?: string;
};
const MoneyFieldDisplayWithContext = ({
value,
entityId,
}: MoneyFieldDisplayWithContextProps) => {
return (
<FieldDisplayContextProvider
fieldDefinition={{
key: 'money',
name: 'Money',
type: 'moneyAmount',
metadata: {
fieldName: 'Amount',
placeHolder: 'Amount',
isPositive: true,
},
}}
entityId={entityId}
>
<MoneyFieldValueSetterEffect value={value} />
<MoneyFieldDisplay />
</FieldDisplayContextProvider>
);
};
const meta: Meta = {
title: 'UI/Field/MoneyFieldDisplay',
component: MoneyFieldDisplayWithContext,
};
export default meta;
type Story = StoryObj<typeof MoneyFieldDisplayWithContext>;
export const Default: Story = {
args: {
value: 100,
},
};
export const Elipsis: Story = {
args: {
value: 1e100,
},
argTypes: {
value: { control: false },
},
parameters: {
container: {
width: 100,
},
},
decorators: [ComponentDecorator],
};
export const Catalog: CatalogStory<Story, typeof MoneyFieldDisplayWithContext> =
{
argTypes: {
value: { control: false },
},
parameters: {
catalog: {
dimensions: [
{
name: 'currency',
values: ['$'] satisfies string[],
props: (_value: string) => ({}),
},
{
name: 'value',
values: [
100, 1000, -1000, 1e10, 1.357802, -1.283, 0,
] satisfies number[],
props: (value: number) => ({ value, entityId: v4() }),
},
],
options: {
elementContainer: {
width: 100,
},
},
},
},
decorators: [CatalogDecorator],
};

View File

@ -1,6 +1,6 @@
import styled from '@emotion/styled'; import styled from '@emotion/styled';
const StyledLayout = styled.div` const StyledLayout = styled.div<{ width?: number }>`
background: ${({ theme }) => theme.background.primary}; background: ${({ theme }) => theme.background.primary};
border: 1px solid ${({ theme }) => theme.border.color.light}; border: 1px solid ${({ theme }) => theme.border.color.light};
border-radius: 5px; border-radius: 5px;
@ -12,13 +12,17 @@ const StyledLayout = styled.div`
max-width: calc(100% - 40px); max-width: calc(100% - 40px);
min-width: 300px; min-width: 300px;
padding: 20px; padding: 20px;
width: fit-content; width: ${({ width }) => (width ? width + 'px' : 'fit-content')};
`; `;
type OwnProps = { type ComponentStorybookLayoutProps = {
width?: number;
children: JSX.Element; children: JSX.Element;
}; };
export const ComponentStorybookLayout = ({ children }: OwnProps) => ( export const ComponentStorybookLayout = ({
<StyledLayout>{children}</StyledLayout> width,
children,
}: ComponentStorybookLayoutProps) => (
<StyledLayout width={width}>{children}</StyledLayout>
); );

View File

@ -108,41 +108,47 @@ export const CatalogDecorator: Decorator = (Story, context) => {
<StyledColumnContainer key={value4}> <StyledColumnContainer key={value4}>
<StyledColumnTitle> <StyledColumnTitle>
{dimension4.labels?.(value4) ?? {dimension4.labels?.(value4) ??
(typeof value4 === 'string' ? value4 : '')} (['string', 'number'].includes(typeof value4) ? value4 : '')}
</StyledColumnTitle> </StyledColumnTitle>
{dimension3.values.map((value3: any) => ( {dimension3.values.map((value3: any) => (
<StyledRowsContainer key={value3}> <StyledRowsContainer key={value3}>
<StyledRowsTitle> <StyledRowsTitle>
{dimension3.labels?.(value3) ?? {dimension3.labels?.(value3) ??
(typeof value3 === 'string' ? value3 : '')} (['string', 'number'].includes(typeof value3) ? value3 : '')}
</StyledRowsTitle> </StyledRowsTitle>
{dimension2.values.map((value2: any) => ( {dimension2.values.map((value2: any) => (
<StyledRowContainer key={value2}> <StyledRowContainer key={value2}>
<StyledRowTitle> <StyledRowTitle>
{dimension2.labels?.(value2) ?? {dimension2.labels?.(value2) ??
(typeof value2 === 'string' ? value2 : '')} (['string', 'number'].includes(typeof value2)
? value2
: '')}
</StyledRowTitle> </StyledRowTitle>
{dimension1.values.map((value1: any) => ( {dimension1.values.map((value1: any) => {
<StyledCellContainer key={value1} id={value1}> return (
<StyledElementTitle> <StyledCellContainer key={value1} id={value1}>
{dimension1.labels?.(value1) ?? <StyledElementTitle>
(typeof value1 === 'string' ? value1 : '')} {dimension1.labels?.(value1) ??
</StyledElementTitle> (['string', 'number'].includes(typeof value1)
<StyledElementContainer ? value1
width={options?.elementContainer?.width} : '')}
> </StyledElementTitle>
<Story <StyledElementContainer
args={{ width={options?.elementContainer?.width}
...context.args, >
...dimension1.props(value1), <Story
...dimension2.props(value2), args={{
...dimension3.props(value3), ...context.args,
...dimension4.props(value4), ...dimension1.props(value1),
}} ...dimension2.props(value2),
/> ...dimension3.props(value3),
</StyledElementContainer> ...dimension4.props(value4),
</StyledCellContainer> }}
))} />
</StyledElementContainer>
</StyledCellContainer>
);
})}
</StyledRowContainer> </StyledRowContainer>
))} ))}
</StyledRowsContainer> </StyledRowsContainer>

View File

@ -2,8 +2,12 @@ import { Decorator } from '@storybook/react';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout'; import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentDecorator: Decorator = (Story) => ( export const ComponentDecorator: Decorator = (Story, context) => {
<ComponentStorybookLayout> const { container } = context.parameters;
<Story />
</ComponentStorybookLayout> return (
); <ComponentStorybookLayout width={container?.width}>
<Story />
</ComponentStorybookLayout>
);
};