Docs/storybook improvements (#877)
* docs: use PageDecorator * docs: use decorators in TableHeader stories * docs: use theming parameter in App stories * docs: enable auto-generated docs for stories Closes #702
This commit is contained in:
@ -1,63 +1,73 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
webpackFinal: config => {
|
||||
webpackFinal: (config) => {
|
||||
config.module.rules.push({
|
||||
test: /\.tsx?$/,
|
||||
exclude: /node_modules/,
|
||||
use: [{
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
presets: [require('@babel/preset-typescript').default, [require('@babel/preset-react').default, {
|
||||
runtime: 'automatic'
|
||||
}], require('@babel/preset-env').default]
|
||||
}
|
||||
}]
|
||||
use: [
|
||||
{
|
||||
loader: require.resolve('babel-loader'),
|
||||
options: {
|
||||
presets: [
|
||||
require('@babel/preset-typescript').default,
|
||||
[
|
||||
require('@babel/preset-react').default,
|
||||
{
|
||||
runtime: 'automatic',
|
||||
},
|
||||
],
|
||||
require('@babel/preset-env').default,
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
config.resolve.extensions.push('.ts', '.tsx');
|
||||
config.module.rules.push({
|
||||
test: /\.mjs$/,
|
||||
include: /node_modules/,
|
||||
type: 'javascript/auto'
|
||||
type: 'javascript/auto',
|
||||
});
|
||||
config.module.rules.push({
|
||||
test: /\.svg$/,
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack'
|
||||
loader: '@svgr/webpack',
|
||||
},
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: 'static/media/[path][name].[ext]'
|
||||
}
|
||||
}
|
||||
name: 'static/media/[path][name].[ext]',
|
||||
},
|
||||
},
|
||||
],
|
||||
type: 'javascript/auto',
|
||||
issuer: {
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/]
|
||||
}
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
});
|
||||
config.resolve.extensions.push('.mjs');
|
||||
config.resolve.alias = {
|
||||
...config.resolve.alias,
|
||||
'~': path.resolve(__dirname, "../src"),
|
||||
'@': path.resolve(__dirname, "../src/modules"),
|
||||
'~': path.resolve(__dirname, '../src'),
|
||||
'@': path.resolve(__dirname, '../src/modules'),
|
||||
};
|
||||
return config;
|
||||
},
|
||||
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
|
||||
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
|
||||
addons: [
|
||||
"@storybook/addon-links",
|
||||
"@storybook/addon-essentials",
|
||||
"@storybook/addon-interactions",
|
||||
"@storybook/addon-coverage",
|
||||
"@storybook/addon-styling",
|
||||
"storybook-addon-pseudo-states",
|
||||
"storybook-addon-cookie",
|
||||
'@storybook/addon-links',
|
||||
'@storybook/addon-essentials',
|
||||
'@storybook/addon-interactions',
|
||||
'@storybook/addon-coverage',
|
||||
'@storybook/addon-styling',
|
||||
'storybook-addon-pseudo-states',
|
||||
'storybook-addon-cookie',
|
||||
],
|
||||
docs: { autodocs: true },
|
||||
framework: {
|
||||
name: '@storybook/react-webpack5',
|
||||
options: {}
|
||||
options: {},
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@ -1,21 +0,0 @@
|
||||
import { Meta } from '@storybook/react';
|
||||
|
||||
import { App } from '~/App';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
|
||||
import { Story } from './App.stories';
|
||||
import { renderWithDarkMode } from './shared';
|
||||
|
||||
const meta: Meta<typeof App> = {
|
||||
title: 'App/App/DarkMode',
|
||||
component: App,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const DarkMode: Story = {
|
||||
render: () => renderWithDarkMode(true),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
@ -1,21 +1,52 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { isAuthenticatingState } from '@/auth/states/isAuthenticatingState';
|
||||
import { App } from '~/App';
|
||||
import { FullHeightStorybookLayout } from '~/testing/FullHeightStorybookLayout';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
||||
|
||||
import { render } from './shared';
|
||||
const MockedAuth: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const [, setCurrentUser] = useRecoilState(currentUserState);
|
||||
const [, setIsAuthenticating] = useRecoilState(isAuthenticatingState);
|
||||
|
||||
setCurrentUser(mockedUsersData[0]);
|
||||
setIsAuthenticating(false);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
const meta: Meta<typeof App> = {
|
||||
title: 'App/App',
|
||||
component: App,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<MemoryRouter>
|
||||
<FullHeightStorybookLayout>
|
||||
<MockedAuth>
|
||||
<Story />
|
||||
</MockedAuth>
|
||||
</FullHeightStorybookLayout>
|
||||
</MemoryRouter>
|
||||
),
|
||||
],
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
export type Story = StoryObj<typeof App>;
|
||||
|
||||
export const Default: Story = {
|
||||
render,
|
||||
export const Default: Story = {};
|
||||
|
||||
export const DarkMode: Story = {
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
theming: {
|
||||
themeOverride: 'dark',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,42 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { useRecoilState } from 'recoil';
|
||||
|
||||
import { currentUserState } from '@/auth/states/currentUserState';
|
||||
import { isAuthenticatingState } from '@/auth/states/isAuthenticatingState';
|
||||
import { darkTheme } from '@/ui/themes/themes';
|
||||
import { App } from '~/App';
|
||||
import { FullHeightStorybookLayout } from '~/testing/FullHeightStorybookLayout';
|
||||
import { mockedUsersData } from '~/testing/mock-data/users';
|
||||
|
||||
export const render = () => renderWithDarkMode(false);
|
||||
|
||||
const MockedAuth: React.FC<React.PropsWithChildren> = ({ children }) => {
|
||||
const [, setCurrentUser] = useRecoilState(currentUserState);
|
||||
const [, setIsAuthenticating] = useRecoilState(isAuthenticatingState);
|
||||
|
||||
setCurrentUser(mockedUsersData[0]);
|
||||
setIsAuthenticating(false);
|
||||
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export const renderWithDarkMode = (forceDarkMode?: boolean) => {
|
||||
const AppInStoryBook = (
|
||||
<FullHeightStorybookLayout>
|
||||
<MockedAuth>
|
||||
<App />
|
||||
</MockedAuth>
|
||||
</FullHeightStorybookLayout>
|
||||
);
|
||||
|
||||
return (
|
||||
<MemoryRouter>
|
||||
{forceDarkMode ? (
|
||||
<ThemeProvider theme={darkTheme}>{AppInStoryBook}</ThemeProvider>
|
||||
) : (
|
||||
AppInStoryBook
|
||||
)}
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
@ -13,6 +13,7 @@ const meta: Meta<typeof RoundedIconButton> = {
|
||||
title: 'UI/Button/RoundedIconButton',
|
||||
component: RoundedIconButton,
|
||||
decorators: [ComponentDecorator],
|
||||
argTypes: { icon: { control: false } },
|
||||
args: { onClick: clickJestFn, icon: <IconArrowRight size={15} /> },
|
||||
};
|
||||
|
||||
|
||||
@ -2,37 +2,45 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import { IconList } from '@/ui/icon/index';
|
||||
import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope';
|
||||
import { companiesFilters } from '~/pages/companies/companies-filters';
|
||||
import { availableSorts } from '~/pages/companies/companies-sorts';
|
||||
import { getRenderWrapperForEntityTableComponent } from '~/testing/renderWrappers';
|
||||
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
|
||||
|
||||
import { HooksEntityTable } from '../../../components/HooksEntityTable';
|
||||
import { TableContext } from '../../../states/TableContext';
|
||||
import { TableHeader } from '../TableHeader';
|
||||
|
||||
const meta: Meta<typeof TableHeader> = {
|
||||
title: 'UI/Table/TableHeader',
|
||||
component: TableHeader,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<RecoilScope SpecificContext={TableContext}>
|
||||
{/* TODO: add company mocked loader <CompanyEntityTableData */}
|
||||
<HooksEntityTable
|
||||
availableFilters={companiesFilters}
|
||||
numberOfColumns={5}
|
||||
/>
|
||||
<Story />
|
||||
</RecoilScope>
|
||||
),
|
||||
ComponentDecorator,
|
||||
],
|
||||
argTypes: { viewIcon: { control: false } },
|
||||
args: {
|
||||
viewName: 'ViewName',
|
||||
viewIcon: <IconList />,
|
||||
availableSorts,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof TableHeader>;
|
||||
|
||||
export const Empty: Story = {
|
||||
render: getRenderWrapperForEntityTableComponent(
|
||||
<TableHeader
|
||||
viewName="ViewName"
|
||||
viewIcon={<IconList />}
|
||||
availableSorts={availableSorts}
|
||||
/>,
|
||||
),
|
||||
};
|
||||
export const Empty: Story = {};
|
||||
|
||||
export const WithSortsAndFilters: Story = {
|
||||
render: getRenderWrapperForEntityTableComponent(
|
||||
<TableHeader
|
||||
viewName="ViewName"
|
||||
viewIcon={<IconList />}
|
||||
availableSorts={availableSorts}
|
||||
/>,
|
||||
),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const outsideClick = await canvas.findByText('ViewName');
|
||||
|
||||
@ -3,24 +3,22 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { graphql } from 'msw';
|
||||
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
||||
|
||||
import { GET_CURRENT_USER } from '../../../modules/users/queries';
|
||||
import { mockedOnboardingUsersData } from '../../../testing/mock-data/users';
|
||||
import { CreateProfile } from '../CreateProfile';
|
||||
|
||||
const meta: Meta<typeof CreateProfile> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/CreateProfile',
|
||||
component: CreateProfile,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof CreateProfile>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<CreateProfile />, '/create/profile'),
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/create/profile' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
graphql.query(
|
||||
getOperationName(GET_CURRENT_USER) ?? '',
|
||||
@ -34,6 +32,13 @@ export const Default: Story = {
|
||||
),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof CreateProfile>;
|
||||
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await canvas.findByText('Create profile');
|
||||
|
||||
@ -3,24 +3,22 @@ import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
import { graphql } from 'msw';
|
||||
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { mockedOnboardingUsersData } from '~/testing/mock-data/users';
|
||||
|
||||
import { GET_CURRENT_USER } from '../../../modules/users/queries';
|
||||
import { mockedOnboardingUsersData } from '../../../testing/mock-data/users';
|
||||
import { CreateWorkspace } from '../CreateWorkspace';
|
||||
|
||||
const meta: Meta<typeof CreateWorkspace> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/CreateWorkspace',
|
||||
component: CreateWorkspace,
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof CreateWorkspace>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<CreateWorkspace />, '/create/workspace'),
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/create/workspace' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
graphql.query(
|
||||
getOperationName(GET_CURRENT_USER) ?? '',
|
||||
@ -34,6 +32,13 @@ export const Default: Story = {
|
||||
),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof CreateWorkspace>;
|
||||
|
||||
export const Default: Story = {
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await canvas.findByText('Create your workspace');
|
||||
|
||||
@ -1,14 +1,26 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { fireEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { SignInUp } from '../SignInUp';
|
||||
|
||||
const meta: Meta<typeof SignInUp> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Auth/SignInUp',
|
||||
component: SignInUp,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/sign-in' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
cookie: {
|
||||
tokenPair: '{}',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -16,13 +28,6 @@ export default meta;
|
||||
export type Story = StoryObj<typeof SignInUp>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<SignInUp />, '/sign-in'),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
cookie: {
|
||||
tokenPair: '{}',
|
||||
},
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const continueWithEmailButton = await canvas.findByText(
|
||||
|
||||
@ -3,23 +3,31 @@ import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import { sleep } from '~/testing/sleep';
|
||||
|
||||
import { Companies } from '../Companies';
|
||||
|
||||
import { Story } from './Companies.stories';
|
||||
|
||||
const meta: Meta<typeof Companies> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/FilterBy',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const FilterByName: Story = {
|
||||
render: getRenderWrapperForPage(<Companies />, '/companies'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -50,13 +58,9 @@ export const FilterByName: Story = {
|
||||
expect(await canvas.findByText('Name:')).toBeInTheDocument();
|
||||
expect(await canvas.findByText('Contains Air')).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export const FilterByAccountOwner: Story = {
|
||||
render: getRenderWrapperForPage(<Companies />, '/companies'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -99,7 +103,4 @@ export const FilterByAccountOwner: Story = {
|
||||
expect(await canvas.findByText('Account owner:')).toBeInTheDocument();
|
||||
expect(await canvas.findByText('Is Charles Test')).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
@ -2,22 +2,30 @@ import { expect } from '@storybook/jest';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { Companies } from '../Companies';
|
||||
|
||||
import { Story } from './Companies.stories';
|
||||
|
||||
const meta: Meta<typeof Companies> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/SortBy',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const SortByName: Story = {
|
||||
render: getRenderWrapperForPage(<Companies />, '/companies'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -36,7 +44,4 @@ export const SortByName: Story = {
|
||||
|
||||
await expect(canvas.queryAllByTestId('remove-icon-name')).toStrictEqual([]);
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,22 +1,26 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { Companies } from '../Companies';
|
||||
|
||||
const meta: Meta<typeof Companies> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies',
|
||||
component: Companies,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof Companies>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<Companies />, '/companies'),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -10,57 +10,53 @@ import {
|
||||
} from '@/activities/queries';
|
||||
import { CREATE_COMMENT_THREAD_WITH_COMMENT } from '@/activities/queries/create';
|
||||
import { GET_COMPANY } from '@/companies/queries';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedCommentThreads } from '~/testing/mock-data/comment-threads';
|
||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { CompanyShow } from '../CompanyShow';
|
||||
|
||||
const meta: Meta<typeof CompanyShow> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Companies/Company',
|
||||
component: CompanyShow,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: [
|
||||
...graphqlMocks,
|
||||
graphql.query(
|
||||
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||
(req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
findManyCommentThreads: mockedCommentThreads,
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
graphql.query(getOperationName(GET_COMPANY) ?? '', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
findUniqueCompany: mockedCompaniesData[0],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
],
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof CompanyShow>;
|
||||
|
||||
const companyShowCommonGraphqlMocks = [
|
||||
graphql.query(
|
||||
getOperationName(GET_COMMENT_THREADS_BY_TARGETS) ?? '',
|
||||
(req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
findManyCommentThreads: mockedCommentThreads,
|
||||
}),
|
||||
);
|
||||
},
|
||||
),
|
||||
graphql.query(getOperationName(GET_COMPANY) ?? '', (req, res, ctx) => {
|
||||
return res(
|
||||
ctx.data({
|
||||
findUniqueCompany: mockedCompaniesData[0],
|
||||
}),
|
||||
);
|
||||
}),
|
||||
];
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(
|
||||
<CompanyShow />,
|
||||
'/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||
),
|
||||
parameters: {
|
||||
msw: [...graphqlMocks, ...companyShowCommonGraphqlMocks],
|
||||
},
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
export const EditNote: Story = {
|
||||
render: getRenderWrapperForPage(
|
||||
<CompanyShow />,
|
||||
'/companies/89bb825c-171e-4bcc-9cf7-43448d6fb278',
|
||||
),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const firstNoteTitle = await canvas.findByText('My very first note');
|
||||
@ -84,8 +80,7 @@ export const EditNote: Story = {
|
||||
},
|
||||
parameters: {
|
||||
msw: [
|
||||
...graphqlMocks,
|
||||
...companyShowCommonGraphqlMocks,
|
||||
...meta.parameters?.msw,
|
||||
graphql.mutation(
|
||||
getOperationName(CREATE_COMMENT_THREAD_WITH_COMMENT) ?? '',
|
||||
(req, res, ctx) => {
|
||||
|
||||
@ -1,14 +1,23 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { Opportunities } from '../Opportunities';
|
||||
|
||||
const meta: Meta<typeof Opportunities> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Opportunities/Default',
|
||||
component: Opportunities,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/opportunities' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -16,10 +25,6 @@ export default meta;
|
||||
export type Story = StoryObj<typeof Opportunities>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<Opportunities />, '/opportunities'),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await canvas.findByText('All opportunities');
|
||||
|
||||
@ -3,23 +3,31 @@ import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
import assert from 'assert';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import { sleep } from '~/testing/sleep';
|
||||
|
||||
import { People } from '../People';
|
||||
|
||||
import { Story } from './People.stories';
|
||||
|
||||
const meta: Meta<typeof People> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/FilterBy',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Email: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -49,13 +57,9 @@ export const Email: Story = {
|
||||
expect(await canvas.findByText('Email:')).toBeInTheDocument();
|
||||
expect(await canvas.findByText('Contains al')).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export const CompanyName: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -98,7 +102,4 @@ export const CompanyName: Story = {
|
||||
expect(await canvas.findByText('Company:')).toBeInTheDocument();
|
||||
expect(await canvas.findByText('Is Qonto')).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
@ -7,26 +7,34 @@ import { graphql } from 'msw';
|
||||
import { UPDATE_ONE_PERSON } from '@/people/queries';
|
||||
import { SEARCH_COMPANY_QUERY } from '@/search/queries/search';
|
||||
import { Company } from '~/generated/graphql';
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { fetchOneFromData } from '~/testing/mock-data';
|
||||
import { mockedCompaniesData } from '~/testing/mock-data/companies';
|
||||
import { mockedPeopleData } from '~/testing/mock-data/people';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import { sleep } from '~/testing/sleep';
|
||||
|
||||
import { People } from '../People';
|
||||
|
||||
import { Story } from './People.stories';
|
||||
|
||||
const meta: Meta<typeof People> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/Input',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const InteractWithManyRows: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -64,13 +72,9 @@ export const InteractWithManyRows: Story = {
|
||||
canvas.queryByTestId('editable-cell-edit-mode-container'),
|
||||
).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export const CheckCheckboxes: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -95,9 +99,6 @@ export const CheckCheckboxes: Story = {
|
||||
|
||||
expect(secondCheckbox.checked).toBe(false);
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
const editRelationMocks = (
|
||||
@ -185,7 +186,6 @@ const editRelationMocks = (
|
||||
];
|
||||
|
||||
export const EditRelation: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement, step }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -229,7 +229,6 @@ export const EditRelation: Story = {
|
||||
});
|
||||
},
|
||||
parameters: {
|
||||
actions: {},
|
||||
msw: editRelationMocks('Qonto', ['Airbnb', 'Aircall'], {
|
||||
name: 'Airbnb',
|
||||
domainName: 'airbnb.com',
|
||||
@ -238,7 +237,6 @@ export const EditRelation: Story = {
|
||||
};
|
||||
|
||||
export const SelectRelationWithKeys: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -274,7 +272,6 @@ export const SelectRelationWithKeys: Story = {
|
||||
expect(allAirbns.length).toBe(1);
|
||||
},
|
||||
parameters: {
|
||||
actions: {},
|
||||
msw: editRelationMocks('Qonto', ['Airbnb', 'Aircall'], {
|
||||
name: 'Aircall',
|
||||
domainName: 'aircall.io',
|
||||
|
||||
@ -2,23 +2,31 @@ import { expect } from '@storybook/jest';
|
||||
import type { Meta } from '@storybook/react';
|
||||
import { userEvent, within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
import { sleep } from '~/testing/sleep';
|
||||
|
||||
import { People } from '../People';
|
||||
|
||||
import { Story } from './People.stories';
|
||||
|
||||
const meta: Meta<typeof People> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/SortBy',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export const Email: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -32,13 +40,9 @@ export const Email: Story = {
|
||||
|
||||
expect(await canvas.findByText('Alexandre Prot')).toBeInTheDocument();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export const Cancel: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
|
||||
@ -59,7 +63,4 @@ export const Cancel: Story = {
|
||||
[],
|
||||
);
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,22 +1,26 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { People } from '../People';
|
||||
|
||||
const meta: Meta<typeof People> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People',
|
||||
component: People,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/people' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof People>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<People />, '/people'),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -1,30 +1,35 @@
|
||||
import { Route, Routes } from 'react-router-dom';
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import {} from '@storybook/react';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { mockedPeopleData } from '~/testing/mock-data/people';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { PersonShow } from '../PersonShow';
|
||||
|
||||
const meta: Meta<typeof PersonShow> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/People/Person',
|
||||
component: PersonShow,
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<Routes>
|
||||
<Route path="/person/:personId" element={<Story />} />
|
||||
</Routes>
|
||||
),
|
||||
PageDecorator,
|
||||
],
|
||||
args: { currentPath: `/person/${mockedPeopleData[0].id}` },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof PersonShow>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(
|
||||
<Routes>
|
||||
<Route path="/person/:personId" element={<PersonShow />} />
|
||||
</Routes>,
|
||||
`/person/${mockedPeopleData[0].id}`,
|
||||
),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
@ -1,35 +1,35 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { SettingsProfile } from '../SettingsProfile';
|
||||
|
||||
const meta: Meta<typeof SettingsProfile> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/SettingsProfile',
|
||||
component: SettingsProfile,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/settings/profile' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
export type Story = StoryObj<typeof SettingsProfile>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(<SettingsProfile />, '/settings/profile'),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
export const Default: Story = {};
|
||||
|
||||
export const LogOut: Story = {
|
||||
render: getRenderWrapperForPage(<SettingsProfile />, '/settings/profile'),
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
const logoutButton = await canvas.findByText('Logout');
|
||||
await logoutButton.click();
|
||||
},
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
@ -1,14 +1,23 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { within } from '@storybook/testing-library';
|
||||
|
||||
import {
|
||||
PageDecorator,
|
||||
type PageDecoratorArgs,
|
||||
} from '~/testing/decorators/PageDecorator';
|
||||
import { graphqlMocks } from '~/testing/graphqlMocks';
|
||||
import { getRenderWrapperForPage } from '~/testing/renderWrappers';
|
||||
|
||||
import { SettingsWorkspaceMembers } from '../SettingsWorkspaceMembers';
|
||||
|
||||
const meta: Meta<typeof SettingsWorkspaceMembers> = {
|
||||
const meta: Meta<PageDecoratorArgs> = {
|
||||
title: 'Pages/Settings/SettingsWorkspaceMembers',
|
||||
component: SettingsWorkspaceMembers,
|
||||
decorators: [PageDecorator],
|
||||
args: { currentPath: '/settings/workspace-members' },
|
||||
parameters: {
|
||||
docs: { story: 'inline', iframeHeight: '500px' },
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
@ -16,13 +25,6 @@ export default meta;
|
||||
export type Story = StoryObj<typeof SettingsWorkspaceMembers>;
|
||||
|
||||
export const Default: Story = {
|
||||
render: getRenderWrapperForPage(
|
||||
<SettingsWorkspaceMembers />,
|
||||
'/settings/workspace-members',
|
||||
),
|
||||
parameters: {
|
||||
msw: graphqlMocks,
|
||||
},
|
||||
play: async ({ canvasElement }) => {
|
||||
const canvas = within(canvasElement);
|
||||
await canvas.findByText('Copy link');
|
||||
|
||||
30
front/src/testing/decorators/PageDecorator.tsx
Normal file
30
front/src/testing/decorators/PageDecorator.tsx
Normal file
@ -0,0 +1,30 @@
|
||||
import { HotkeysProvider } from 'react-hotkeys-hook';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { Decorator } from '@storybook/react';
|
||||
|
||||
import { ClientConfigProvider } from '../../modules/client-config/components/ClientConfigProvider';
|
||||
import { INITIAL_HOTKEYS_SCOPES } from '../../modules/ui/hotkey/constants';
|
||||
import { DefaultLayout } from '../../modules/ui/layout/components/DefaultLayout';
|
||||
import { UserProvider } from '../../modules/users/components/UserProvider';
|
||||
import { FullHeightStorybookLayout } from '../FullHeightStorybookLayout';
|
||||
|
||||
export type PageDecoratorArgs = { currentPath: string };
|
||||
|
||||
export const PageDecorator: Decorator<{ currentPath: string }> = (
|
||||
Story,
|
||||
{ args },
|
||||
) => (
|
||||
<UserProvider>
|
||||
<ClientConfigProvider>
|
||||
<HotkeysProvider initiallyActiveScopes={INITIAL_HOTKEYS_SCOPES}>
|
||||
<MemoryRouter initialEntries={[args.currentPath]}>
|
||||
<FullHeightStorybookLayout>
|
||||
<DefaultLayout>
|
||||
<Story />
|
||||
</DefaultLayout>
|
||||
</FullHeightStorybookLayout>
|
||||
</MemoryRouter>
|
||||
</HotkeysProvider>
|
||||
</ClientConfigProvider>
|
||||
</UserProvider>
|
||||
);
|
||||
@ -1,55 +0,0 @@
|
||||
import React from 'react';
|
||||
import { HotkeysProvider } from 'react-hotkeys-hook';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
import { ClientConfigProvider } from '@/client-config/components/ClientConfigProvider';
|
||||
import { INITIAL_HOTKEYS_SCOPES } from '@/ui/hotkey/constants';
|
||||
import { DefaultLayout } from '@/ui/layout/components/DefaultLayout';
|
||||
import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope';
|
||||
import { HooksEntityTable } from '@/ui/table/components/HooksEntityTable';
|
||||
import { TableContext } from '@/ui/table/states/TableContext';
|
||||
import { UserProvider } from '@/users/components/UserProvider';
|
||||
import { companiesFilters } from '~/pages/companies/companies-filters';
|
||||
|
||||
import { ComponentStorybookLayout } from './ComponentStorybookLayout';
|
||||
import { FullHeightStorybookLayout } from './FullHeightStorybookLayout';
|
||||
|
||||
export function getRenderWrapperForPage(
|
||||
children: React.ReactElement,
|
||||
currentPath: string,
|
||||
) {
|
||||
return function render() {
|
||||
return (
|
||||
<UserProvider>
|
||||
<ClientConfigProvider>
|
||||
<HotkeysProvider initiallyActiveScopes={INITIAL_HOTKEYS_SCOPES}>
|
||||
<MemoryRouter initialEntries={[currentPath]}>
|
||||
<FullHeightStorybookLayout>
|
||||
<DefaultLayout>{children}</DefaultLayout>
|
||||
</FullHeightStorybookLayout>
|
||||
</MemoryRouter>
|
||||
</HotkeysProvider>
|
||||
</ClientConfigProvider>
|
||||
</UserProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
export function getRenderWrapperForEntityTableComponent(
|
||||
children: React.ReactElement,
|
||||
) {
|
||||
return function Render() {
|
||||
return (
|
||||
<RecoilScope SpecificContext={TableContext}>
|
||||
{/*
|
||||
TODO: add company mocked loader
|
||||
<CompanyEntityTableData */}
|
||||
<HooksEntityTable
|
||||
availableFilters={companiesFilters}
|
||||
numberOfColumns={5}
|
||||
/>
|
||||
<ComponentStorybookLayout>{children}</ComponentStorybookLayout>
|
||||
</RecoilScope>
|
||||
);
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user