Fix storybook tests (#5487)

Fixes #5486

---------

Co-authored-by: gitstart-twenty <gitstart-twenty@users.noreply.github.com>
Co-authored-by: v1b3m <vibenjamin6@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
gitstart-twenty
2024-05-22 02:24:08 +08:00
committed by GitHub
parent e47101e08b
commit 36b467d301
16 changed files with 709 additions and 101 deletions

View File

@ -1,12 +1,64 @@
import { MemoryRouter } from 'react-router-dom';
import {
createMemoryRouter,
createRoutesFromElements,
Outlet,
Route,
RouterProvider,
} from 'react-router-dom';
import { Decorator } from '@storybook/react';
import {
computeLocation,
isRouteParams,
} from '~/testing/decorators/PageDecorator';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentWithRouterDecorator: Decorator = (Story) => (
interface StrictArgs {
[name: string]: unknown;
}
const Providers = () => (
<ComponentStorybookLayout>
<MemoryRouter>
<Story />
</MemoryRouter>
<Outlet />
</ComponentStorybookLayout>
);
const createRouter = ({
Story,
args,
initialEntries,
initialIndex,
}: {
Story: () => JSX.Element;
args: StrictArgs;
initialEntries?: {
pathname: string;
}[];
initialIndex?: number;
}) =>
createMemoryRouter(
createRoutesFromElements(
<Route element={<Providers />}>
<Route path={(args.routePath as string) ?? '*'} element={<Story />} />
</Route>,
),
{ initialEntries, initialIndex },
);
export const ComponentWithRouterDecorator: Decorator = (Story, { args }) => {
return (
<RouterProvider
router={createRouter({
Story,
args,
initialEntries:
args.routePath &&
typeof args.routePath === 'string' &&
(args.routeParams === undefined || isRouteParams(args.routeParams))
? [computeLocation(args.routePath, args.routeParams)]
: [{ pathname: '/' }],
})}
/>
);
};

View File

@ -1,5 +1,11 @@
import { HelmetProvider } from 'react-helmet-async';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import {
createMemoryRouter,
createRoutesFromElements,
Outlet,
Route,
RouterProvider,
} from 'react-router-dom';
import { ApolloProvider } from '@apollo/client';
import { loadDevMessages } from '@apollo/client/dev';
import { Decorator } from '@storybook/react';
@ -23,15 +29,26 @@ export type PageDecoratorArgs = {
additionalRoutes?: string[];
};
type RouteParams = {
export type RouteParams = {
[param: string]: string;
};
const computeLocation = (routePath: string, routeParams: RouteParams) => {
export const isRouteParams = (obj: any): obj is RouteParams => {
if (typeof obj !== 'object' || obj === null) {
return false;
}
return Object.keys(obj).every((key) => typeof obj[key] === 'string');
};
export const computeLocation = (
routePath: string,
routeParams?: RouteParams,
) => {
return {
pathname: routePath.replace(
/:(\w+)/g,
(paramName) => routeParams[paramName] ?? '',
(paramName) => routeParams?.[paramName] ?? '',
),
};
};
@ -42,11 +59,7 @@ const ApolloStorybookDevLogEffect = () => {
return <></>;
};
export const PageDecorator: Decorator<{
routePath: string;
routeParams: RouteParams;
additionalRoutes?: string[];
}> = (Story, { args }) => {
const Providers = () => {
return (
<RecoilRoot>
<ApolloProvider client={mockedApolloClient}>
@ -56,32 +69,15 @@ export const PageDecorator: Decorator<{
<UserProvider>
<ClientConfigProviderEffect />
<ClientConfigProvider>
<MemoryRouter
initialEntries={[
computeLocation(args.routePath, args.routeParams),
]}
>
<FullHeightStorybookLayout>
<HelmetProvider>
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
<ObjectMetadataItemsProvider>
<Routes>
<Route element={<DefaultLayout />}>
<Route path={args.routePath} element={<Story />} />
{args.additionalRoutes?.map((route) => (
<Route
key={route}
path={route}
element={<div>Navigated to {route}</div>}
/>
))}
</Route>
</Routes>
</ObjectMetadataItemsProvider>
</SnackBarProviderScope>
</HelmetProvider>
</FullHeightStorybookLayout>
</MemoryRouter>
<FullHeightStorybookLayout>
<HelmetProvider>
<SnackBarProviderScope snackBarManagerScopeId="snack-bar-manager">
<ObjectMetadataItemsProvider>
<Outlet />
</ObjectMetadataItemsProvider>
</SnackBarProviderScope>
</HelmetProvider>
</FullHeightStorybookLayout>
</ClientConfigProvider>
</UserProvider>
</ApolloMetadataClientMockedProvider>
@ -89,3 +85,54 @@ export const PageDecorator: Decorator<{
</RecoilRoot>
);
};
const createRouter = ({
Story,
args,
initialEntries,
initialIndex,
}: {
Story: () => JSX.Element;
args: {
routePath: string;
routeParams: RouteParams;
additionalRoutes?: string[] | undefined;
};
initialEntries?: {
pathname: string;
}[];
initialIndex?: number;
}) =>
createMemoryRouter(
createRoutesFromElements(
<Route element={<Providers />}>
<Route element={<DefaultLayout />}>
<Route path={args.routePath} element={<Story />} />
{args.additionalRoutes?.map((route) => (
<Route
key={route}
path={route}
element={<div>Navigated to {route}</div>}
/>
))}
</Route>
</Route>,
),
{ initialEntries, initialIndex },
);
export const PageDecorator: Decorator<{
routePath: string;
routeParams: RouteParams;
additionalRoutes?: string[];
}> = (Story, { args }) => {
return (
<RouterProvider
router={createRouter({
Story,
args,
initialEntries: [computeLocation(args.routePath, args.routeParams)],
})}
/>
);
};

View File

@ -49,6 +49,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: true,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -93,6 +94,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
nameSingular: 'viewField',
namePlural: 'viewFields',
isSystem: true,
isRemote: false,
},
},
},
@ -110,6 +112,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: false,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -132,6 +135,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: true,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -154,6 +158,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: false,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -176,6 +181,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: false,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -198,6 +204,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: false,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',
@ -220,6 +227,7 @@ const customObjectMetadataItemEdge: ObjectEdge = {
isCustom: false,
isActive: true,
isSystem: true,
options: null,
isNullable: false,
createdAt: '2024-04-08T12:48:49.538Z',
updatedAt: '2024-04-08T12:48:49.538Z',

View File

@ -0,0 +1,104 @@
import {
TimelineCalendarEvent,
TimelineCalendarEventVisibility,
} from '~/generated-metadata/graphql';
export const mockedTimelineCalendarEvents: TimelineCalendarEvent[] = [
{
__typename: 'TimelineCalendarEvent',
id: '20202020-2e3f-45a2-ab16-b580ff4f83e7',
title: 'Jane',
description: 'Tests techniques',
location: '',
startsAt: '2024-05-16T12:00:00.000Z',
endsAt: '2024-05-16T13:00:00.000Z',
conferenceLink: {
url: 'https://meet.google.com/xxx-xxx-xxx',
label: 'Rejoindre la visio',
},
conferenceSolution: 'GOOGLE_MEET',
isCanceled: false,
visibility: TimelineCalendarEventVisibility.ShareEverything,
isFullDay: false,
participants: [
{
__typename: 'TimelineCalendarEventParticipant',
personId: null,
workspaceMemberId: '20202020-78c5-4cbb-87a8-f9cd3ad4d8af',
firstName: 'Tim',
lastName: 'Apple',
displayName: 'Tim',
avatarUrl: '',
handle: 'tim@apple.dev',
},
{
__typename: 'TimelineCalendarEventParticipant',
personId: null,
workspaceMemberId: '20202020-3cf7-453e-a5f4-28f8412e70f0',
firstName: 'Jane',
lastName: 'Doe',
displayName: 'Jane',
avatarUrl: '',
handle: 'jane@apple.dev',
},
],
},
{
__typename: 'TimelineCalendarEvent',
id: '20202020-1020-42d6-8444-541f5e57a7e5',
title: '',
description: '',
location: '',
startsAt: '2024-05-08T12:00:00.000Z',
endsAt: '2024-05-08T12:25:00.000Z',
isFullDay: false,
conferenceLink: {
url: 'https://meet.google.com/xxx-xxx-xxx',
label: 'Rejoindre la visio',
},
conferenceSolution: 'GOOGLE_MEET',
isCanceled: false,
visibility: TimelineCalendarEventVisibility.Metadata,
participants: [
{
__typename: 'TimelineCalendarEventParticipant',
personId: null,
workspaceMemberId: '20202020-78c5-4cbb-87a8-f9cd3ad4d8af',
firstName: 'Tim',
lastName: 'Apple',
displayName: 'Tim',
avatarUrl: '',
handle: 'tim@apple.dev',
},
],
},
{
__typename: 'TimelineCalendarEvent',
id: '20202020-fa61-4d82-b47f-90cca16514e3',
title: '',
description: '',
location: '',
startsAt: '2024-05-06T12:00:00.000Z',
endsAt: '2024-05-06T12:25:00.000Z',
isFullDay: false,
conferenceLink: {
url: 'https://meet.google.com/xxx-xxx-xxx',
label: 'Rejoindre la visio',
},
conferenceSolution: 'GOOGLE_MEET',
isCanceled: false,
visibility: TimelineCalendarEventVisibility.Metadata,
participants: [
{
__typename: 'TimelineCalendarEventParticipant',
personId: null,
workspaceMemberId: '20202020-78c5-4cbb-87a8-f9cd3ad4d8af',
firstName: 'Tim',
lastName: 'Apple',
displayName: 'Tim',
avatarUrl: '',
handle: 'tim@apple.dev',
},
],
},
];