Improve tests (#871)

This commit is contained in:
Charles Bochet
2023-07-24 00:57:56 -07:00
committed by GitHub
parent 2b885f2496
commit 07180af8c0
53 changed files with 432 additions and 251 deletions

View File

@ -3,7 +3,7 @@ import { Preview } from '@storybook/react';
import { ThemeProvider } from '@emotion/react';
import { withThemeFromJSXProvider } from '@storybook/addon-styling';
import { lightTheme, darkTheme } from '../src/modules/ui/themes/themes';
import { RootDecorator } from '../src/testing/decorators';
import { RootDecorator } from '../src/testing/decorators/RootDecorator';
import 'react-loading-skeleton/dist/skeleton.css';
import { mockedUserJWT } from '../src/testing/mock-data/jwt';
initialize();

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CommentThreadActionBar } from '../../right-drawer/components/CommentThreadActionBar';
import { Comment } from '../Comment';

View File

@ -2,7 +2,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { DateTime } from 'luxon';
import { CommentThreadActionBar } from '@/activities/right-drawer/components/CommentThreadActionBar';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { avatarUrl } from '~/testing/mock-data/users';
import { CommentHeader } from '../CommentHeader';

View File

@ -26,7 +26,7 @@ export function CommentThreadCreateButton({
<Button
icon={<IconCheckbox size={theme.icon.size.sm} />}
title="Task"
soon={true}
onClick={onTaskClick}
/>
<Button
icon={<IconTimelineEvent size={theme.icon.size.sm} />}

View File

@ -213,7 +213,7 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
key={entity.id}
id={entity.id}
name={entity.name}
picture={entity.avatarUrl}
pictureUrl={entity.avatarUrl}
/>
) : (
<PersonChip key={entity.id} name={entity.name} id={entity.id} />

View File

@ -2,7 +2,7 @@ import {
DropdownButton,
DropdownOptionType,
} from '@/ui/button/components/DropdownButton';
import { IconNotes } from '@/ui/icon/index';
import { IconCheck, IconNotes } from '@/ui/icon';
import {
ActivityType,
CommentThread,
@ -17,6 +17,7 @@ export function CommentThreadTypeDropdown({ commentThread }: OwnProps) {
const [updateCommentThreadMutation] = useUpdateCommentThreadMutation();
const options: DropdownOptionType[] = [
{ label: 'Note', key: 'note', icon: <IconNotes /> },
{ label: 'Task', key: 'task', icon: <IconCheck /> },
];
function getSelectedOptionKey() {

View File

@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
import styled from '@emotion/styled';
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedCommentThreads } from '~/testing/mock-data/comment-threads';

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CommentChip } from '../CommentChip';

View File

@ -2,7 +2,7 @@ import { MemoryRouter } from 'react-router-dom';
import type { Meta, StoryObj } from '@storybook/react';
import { fireEvent, userEvent, within } from '@storybook/testing-library';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { sleep } from '~/testing/sleep';
import { CommandMenu } from '../CommandMenu';

View File

@ -1,60 +0,0 @@
import {
DropdownButton,
DropdownOptionType,
} from '@/ui/button/components/DropdownButton';
import { IconCheck, IconNotes } from '@/ui/icon';
import {
ActivityType,
CommentThread,
useUpdateCommentThreadMutation,
} from '~/generated/graphql';
type OwnProps = {
commentThread: Pick<CommentThread, 'id' | 'type'>;
};
export function CommentThreadTypeDropdown({ commentThread }: OwnProps) {
const [updateCommentThreadMutation] = useUpdateCommentThreadMutation();
const options: DropdownOptionType[] = [
{ label: 'Note', key: 'note', icon: <IconNotes /> },
{ label: 'Task', key: 'task', icon: <IconCheck /> },
];
function getSelectedOptionKey() {
if (commentThread.type === ActivityType.Note) {
return 'note';
} else if (commentThread.type === ActivityType.Task) {
return 'task';
} else {
return undefined;
}
}
const convertSelectionOptionKeyToActivityType = (key: string) => {
switch (key) {
case 'note':
return ActivityType.Note;
case 'task':
return ActivityType.Task;
default:
return undefined;
}
};
const handleSelect = (selectedOption: DropdownOptionType) => {
updateCommentThreadMutation({
variables: {
id: commentThread.id,
type: convertSelectionOptionKeyToActivityType(selectedOption.key),
},
});
};
return (
<DropdownButton
options={options}
onSelection={handleSelect}
selectedOptionKey={getSelectedOptionKey()}
/>
);
}

View File

@ -3,7 +3,7 @@ import { Meta, StoryObj } from '@storybook/react';
import { EntityBoard } from '@/pipeline/components/EntityBoard';
import { opportunitiesBoardOptions } from '~/pages/opportunities/opportunitiesBoardOptions';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { defaultPipelineProgressOrderBy } from '../../pipeline/queries';

View File

@ -3,7 +3,7 @@ import { MemoryRouter } from 'react-router-dom';
import { Meta, StoryObj } from '@storybook/react';
import { CompanyBoardCard } from '@/companies/components/CompanyBoardCard';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { mockedPipelineProgressData } from '~/testing/mock-data/pipeline-progress';

View File

@ -2,7 +2,7 @@ import { BrowserRouter } from 'react-router-dom';
import styled from '@emotion/styled';
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { CompanyChip } from '../components/CompanyChip';
@ -37,14 +37,13 @@ const TestCellContainer = styled.div`
min-width: 250px;
overflow: hidden;
text-wrap: nowrap;
`;
export const SmallName: Story = {
args: {
id: 'airbnb',
name: 'Airbnb',
picture: 'https://api.faviconkit.com/airbnb.com/144',
pictureUrl: 'https://api.faviconkit.com/airbnb.com/144',
},
};
@ -56,6 +55,6 @@ export const BigName: Story = {
args: {
id: 'google',
name: 'Google with a real big name to overflow the cell',
picture: 'https://api.faviconkit.com/google.com/144',
pictureUrl: 'https://api.faviconkit.com/google.com/144',
},
};

View File

@ -41,7 +41,7 @@ export function CompanyAccountOwnerCell({ company }: OwnProps) {
<PersonChip
id={company.accountOwner.id}
name={company.accountOwner?.displayName ?? ''}
picture={company.accountOwner?.avatarUrl ?? ''}
pictureUrl={company.accountOwner?.avatarUrl ?? ''}
/>
) : (
<></>

View File

@ -10,7 +10,6 @@ import { GET_PIPELINE_PROGRESS, GET_PIPELINES } from '@/pipeline/queries';
import { BoardCardContext } from '@/pipeline/states/BoardCardContext';
import { pipelineProgressIdScopedState } from '@/pipeline/states/pipelineProgressIdScopedState';
import { selectedBoardCardsState } from '@/pipeline/states/selectedBoardCardsState';
import { ChipVariant } from '@/ui/chip/components/EntityChip';
import { DateEditableField } from '@/ui/editable-field/variants/components/DateEditableField';
import { NumberEditableField } from '@/ui/editable-field/variants/components/NumberEditableField';
import { IconCurrencyDollar, IconProgressCheck } from '@/ui/icon';
@ -177,9 +176,8 @@ export function CompanyBoardCard() {
<CompanyChip
id={company.id}
name={company.name}
clickable
picture={getLogoUrlFromDomainName(company.domainName)}
variant={ChipVariant.transparent}
pictureUrl={getLogoUrlFromDomainName(company.domainName)}
clickable={false}
/>
<StyledCheckboxContainer className="checkbox-container">
<Checkbox

View File

@ -1,29 +1,25 @@
import { ChipVariant, EntityChip } from '@/ui/chip/components/EntityChip';
import { EntityChip } from '@/ui/chip/components/EntityChip';
type OwnProps = {
id: string;
name: string;
picture?: string;
pictureUrl?: string;
clickable?: boolean;
variant?: ChipVariant;
};
export function CompanyChip({
id,
name,
picture,
clickable,
variant = ChipVariant.opaque,
pictureUrl,
clickable = true,
}: OwnProps) {
return (
<EntityChip
entityId={id}
linkToEntity={`/companies/${id}`}
linkToEntity={clickable ? `/companies/${id}` : undefined}
name={name}
avatarType="squared"
clickable={clickable}
picture={picture}
variant={variant}
pictureUrl={pictureUrl}
/>
);
}

View File

@ -38,7 +38,7 @@ export function CompanyEditableNameChipCell({ company }: OwnProps) {
id={company.id}
name={company.name}
clickable
picture={getLogoUrlFromDomainName(company.domainName)}
pictureUrl={getLogoUrlFromDomainName(company.domainName)}
/>
}
onSubmit={() =>

View File

@ -31,7 +31,7 @@ export function CompanyAccountOwnerEditableField({ company }: OwnProps) {
<PersonChip
id={company.accountOwner.id}
name={company.accountOwner?.displayName ?? ''}
picture={company.accountOwner?.avatarUrl ?? ''}
pictureUrl={company.accountOwner?.avatarUrl ?? ''}
/>
) : (
<></>

View File

@ -58,7 +58,6 @@ export function EditablePeopleFullName({
<PersonChip
name={`${person?.firstName ?? ''} ${person?.lastName ?? ''}`}
id={person?.id ?? ''}
clickable
/>
</NoEditModeContainer>
}

View File

@ -38,7 +38,7 @@ export function PeopleCompanyCell({ people }: OwnProps) {
<CompanyChip
id={people.company?.id ?? ''}
name={people.company?.name ?? ''}
picture={getLogoUrlFromDomainName(people.company?.domainName)}
pictureUrl={getLogoUrlFromDomainName(people.company?.domainName)}
/>
}
/>

View File

@ -3,24 +3,23 @@ import { EntityChip } from '@/ui/chip/components/EntityChip';
export type PersonChipPropsType = {
id: string;
name: string;
picture?: string;
pictureUrl?: string;
clickable?: boolean;
};
export function PersonChip({
id,
name,
picture,
clickable,
pictureUrl,
clickable = true,
}: PersonChipPropsType) {
return (
<EntityChip
entityId={id}
linkToEntity={`/person/${id}`}
linkToEntity={clickable ? `/person/${id}` : undefined}
name={name}
avatarType="rounded"
clickable={clickable}
picture={picture}
pictureUrl={pictureUrl}
/>
);
}

View File

@ -2,7 +2,7 @@ import { BrowserRouter } from 'react-router-dom';
import styled from '@emotion/styled';
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { PersonChip } from '../PersonChip';
@ -15,7 +15,6 @@ const TestCellContainer = styled.div`
max-width: 250px;
min-width: 250px;
overflow: hidden;
text-wrap: nowrap;
`;
const meta: Meta<typeof PersonChip> = {

View File

@ -33,7 +33,7 @@ export function PeopleCompanyEditableField({ people }: OwnProps) {
<CompanyChip
id={people.company.id}
name={people.company.name}
picture={getLogoUrlFromDomainName(people.company.domainName)}
pictureUrl={getLogoUrlFromDomainName(people.company.domainName)}
/>
) : (
<></>

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { ActionBar } from '../ActionBar';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import {
BoardColumnEditTitleMenu,

View File

@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { IconBrandGoogle } from '@/ui/icon';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { MainButton } from '../MainButton';

View File

@ -3,7 +3,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { IconArrowRight } from '@/ui/icon';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { RoundedIconButton } from '../RoundedIconButton';

View File

@ -0,0 +1,120 @@
import * as React from 'react';
import styled from '@emotion/styled';
import { OverflowingTextWithTooltip } from '../../tooltip/OverflowingTextWithTooltip';
export enum ChipSize {
Large = 'large',
Small = 'small',
}
export enum ChipVariant {
Highlighted = 'highlighted',
Regular = 'regular',
Transparent = 'transparent',
}
type OwnProps = {
size?: ChipSize;
disabled?: boolean;
clickable?: boolean;
label: string;
maxWidth?: string;
variant?: ChipVariant;
leftComponent?: React.ReactNode;
rightComponent?: React.ReactNode;
className?: string;
};
const StyledContainer = styled.div<Partial<OwnProps>>`
align-items: center;
background-color: ${({ theme, variant }) =>
variant === ChipVariant.Highlighted
? theme.background.transparent.light
: 'transparent'};
border-radius: ${({ theme }) => theme.border.radius.sm};
color: ${({ theme, disabled }) =>
disabled ? theme.font.color.light : theme.font.color.primary};
cursor: ${({ clickable, disabled, variant }) =>
disabled || variant === ChipVariant.Transparent
? 'auto'
: clickable
? 'pointer'
: 'auto'};
display: inline-flex;
gap: ${({ theme }) => theme.spacing(1)};
height: ${({ size }) => (size === ChipSize.Large ? '16px' : '12px')};
max-width: ${({ maxWidth }) => (maxWidth ? maxWidth : '200px')};
overflow: hidden;
padding: ${({ theme }) => theme.spacing(1)};
user-select: none;
:hover {
${({ variant, theme, disabled }) => {
if (!disabled) {
return (
'background-color: ' +
(variant === ChipVariant.Highlighted
? theme.background.transparent.medium
: variant === ChipVariant.Regular
? theme.background.transparent.light
: 'transparent') +
';'
);
}
}}
}
:active {
${({ variant, theme, disabled }) => {
if (!disabled) {
return (
'background-color: ' +
(variant === ChipVariant.Highlighted
? theme.background.transparent.strong
: variant === ChipVariant.Regular
? theme.background.transparent.medium
: 'transparent') +
';'
);
}
}}
}
`;
const StyledLabel = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
export function Chip({
size = ChipSize.Small,
label,
disabled = false,
clickable = true,
variant = ChipVariant.Regular,
leftComponent,
rightComponent,
maxWidth,
className,
}: OwnProps) {
return (
<StyledContainer
data-testid="chip"
clickable={clickable}
variant={variant}
size={size}
disabled={disabled}
className={className}
>
{leftComponent}
<StyledLabel>
<OverflowingTextWithTooltip text={label} />
</StyledLabel>
{rightComponent}
</StyledContainer>
);
}

View File

@ -1,122 +1,53 @@
import * as React from 'react';
import { useNavigate } from 'react-router-dom';
import { Theme } from '@emotion/react';
import styled from '@emotion/styled';
import { Avatar, AvatarType } from '@/users/components/Avatar';
import { isNonEmptyString } from '~/utils/isNonEmptyString';
import { OverflowingTextWithTooltip } from '../../tooltip/OverflowingTextWithTooltip';
export enum ChipVariant {
opaque = 'opaque',
transparent = 'transparent',
}
const baseStyle = ({ theme }: { theme: Theme }) => `
align-items: center;
border-radius: ${theme.spacing(1)};
color: ${theme.font.color.primary};
display: inline-flex;
gap: ${theme.spacing(1)};
height: 12px;
overflow: hidden;
padding: ${theme.spacing(1)};
text-decoration: none;
img {
border-radius: ${theme.border.radius.rounded};
height: 14px;
object-fit: cover;
width: 14px;
}
white-space: nowrap;
`;
const StyledContainerLink = styled.div<{ variant: string }>`
${baseStyle}
background-color: ${({ theme, variant }) =>
variant === ChipVariant.opaque ? theme.background.tertiary : 'transparent'};
:hover {
background-color: ${({ variant, theme }) =>
variant === ChipVariant.opaque
? theme.background.quaternary
: theme.background.transparent.light};
}
`;
const StyledContainerReadOnly = styled.div`
${baseStyle}
`;
const StyledName = styled.span`
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
`;
import { Chip, ChipVariant } from './Chip';
type OwnProps = {
linkToEntity: string;
linkToEntity?: string;
entityId: string;
name: string;
picture?: string;
clickable?: boolean;
pictureUrl?: string;
avatarType?: AvatarType;
variant?: ChipVariant;
};
export function EntityChip({
linkToEntity,
entityId,
name,
picture,
clickable,
pictureUrl,
avatarType = 'rounded',
variant = ChipVariant.opaque,
}: OwnProps) {
const navigate = useNavigate();
function handleLinkClick(event: React.MouseEvent<HTMLDivElement>) {
event.preventDefault();
event.stopPropagation();
navigate(linkToEntity);
if (linkToEntity) {
navigate(linkToEntity);
}
}
return clickable && linkToEntity ? (
<StyledContainerLink
data-testid="entity-chip"
onClick={handleLinkClick}
variant={variant}
>
{isNonEmptyString(name) && (
<Avatar
avatarUrl={picture}
colorId={entityId}
placeholder={name}
size={14}
type={avatarType}
/>
)}
<StyledName>
<OverflowingTextWithTooltip text={name} />
</StyledName>
</StyledContainerLink>
return isNonEmptyString(name) ? (
<div onClick={handleLinkClick}>
<Chip
label={name}
variant={linkToEntity ? ChipVariant.Highlighted : ChipVariant.Regular}
leftComponent={
<Avatar
avatarUrl={pictureUrl}
colorId={entityId}
placeholder={name}
size={14}
type={avatarType}
/>
}
/>
</div>
) : (
<StyledContainerReadOnly data-testid="entity-chip">
{isNonEmptyString(name) && (
<Avatar
avatarUrl={picture}
colorId={entityId}
placeholder={name}
size={14}
type={avatarType}
/>
)}
<StyledName>
<OverflowingTextWithTooltip text={name} />
</StyledName>
</StyledContainerReadOnly>
<></>
);
}

View File

@ -0,0 +1,48 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { ExhaustiveComponentDecorator } from '~/testing/decorators/ExhaustiveComponentDecorator';
import { Chip, ChipSize, ChipVariant } from '../Chip';
const meta: Meta<typeof Chip> = {
title: 'UI/Chip/Chip',
component: Chip,
};
export default meta;
type Story = StoryObj<typeof Chip>;
export const Default: Story = {
args: {
label: 'Chip test',
size: ChipSize.Small,
variant: ChipVariant.Highlighted,
clickable: true,
maxWidth: '200px',
},
decorators: [ComponentDecorator],
};
export const All: Story = {
args: { size: ChipSize.Large, clickable: true, label: 'Hello' },
argTypes: {
size: { control: false },
variant: { control: false },
disabled: { control: false },
className: { control: false },
rightComponent: { control: false },
leftComponent: { control: false },
},
parameters: {
pseudo: { hover: ['.hover'], active: ['.active'] },
variants: [
ChipVariant.Highlighted,
ChipVariant.Regular,
ChipVariant.Transparent,
],
sizes: [ChipSize.Small, ChipSize.Large],
states: ['default', 'hover', 'active', 'disabled'],
},
decorators: [ExhaustiveComponentDecorator],
};

View File

@ -0,0 +1,21 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentWithRouterDecorator } from '~/testing/decorators/ComponentWithRouterDecorator';
import { EntityChip } from '../EntityChip';
const meta: Meta<typeof EntityChip> = {
title: 'UI/Chip/EntityChip',
component: EntityChip,
decorators: [ComponentWithRouterDecorator],
args: {
name: 'Entity name',
linkToEntity: '/entity-link',
avatarType: 'squared',
},
};
export default meta;
type Story = StoryObj<typeof EntityChip>;
export const Default: Story = {};

View File

@ -1,7 +1,7 @@
import styled from '@emotion/styled';
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { ColorSchemeCard } from '../ColorSchemeCard';

View File

@ -4,7 +4,7 @@ import type { Meta, StoryObj } from '@storybook/react';
import { IconPlus } from '@/ui/icon/index';
import { Avatar } from '@/users/components/Avatar';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { DropdownMenuSkeletonItem } from '../../../relation-picker/components/skeletons/DropdownMenuSkeletonItem';
import { DropdownMenu } from '../DropdownMenu';

View File

@ -1,7 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { IconCalendar } from '@tabler/icons-react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { DateEditableField } from '../DateEditableField';

View File

@ -1,7 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { IconCurrencyDollar } from '@tabler/icons-react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { NumberEditableField } from '../NumberEditableField';

View File

@ -2,7 +2,7 @@ import { BrowserRouter } from 'react-router-dom';
import type { Meta, StoryObj } from '@storybook/react';
import { IconPhone } from '@tabler/icons-react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { PhoneEditableField } from '../PhoneEditableField';

View File

@ -1,7 +1,7 @@
import type { Meta, StoryObj } from '@storybook/react';
import { IconUser } from '@tabler/icons-react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { TextEditableField } from '../TextEditableField';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { AutosizeTextInput } from '../AutosizeTextInput';

View File

@ -4,7 +4,7 @@ import { jest } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { TextInput } from '../TextInput';

View File

@ -3,7 +3,7 @@ import { expect, jest } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { PrimaryLink } from '../PrimaryLink';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { SoonPill } from '../SoonPill';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { RightDrawerTopBar } from '../RightDrawerTopBar';

View File

@ -2,10 +2,8 @@ import { expect } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within } from '@storybook/testing-library';
import {
CellPositionDecorator,
ComponentDecorator,
} from '~/testing/decorators';
import { CellPositionDecorator } from '~/testing/decorators/CellPositionDecorator';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { EditableCellText } from '../../types/EditableCellText';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { Tag } from '../Tag';

View File

@ -1,6 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react';
import { ComponentDecorator } from '~/testing/decorators';
import { ComponentDecorator } from '~/testing/decorators/ComponentDecorator';
import { avatarUrl } from '~/testing/mock-data/users';
import { Avatar } from '../Avatar';

View File

@ -194,7 +194,10 @@ export const EditRelation: Story = {
mockedPeopleData[1].company.name,
);
await userEvent.click(secondRowCompanyCell);
await userEvent.click(
secondRowCompanyCell.parentNode?.parentNode?.parentNode
?.parentElement as HTMLElement,
);
});
await step('Type "Air" in relation picker', async () => {
@ -244,7 +247,10 @@ export const SelectRelationWithKeys: Story = {
);
await sleep(25);
await userEvent.click(firstRowCompanyCell);
await userEvent.click(
firstRowCompanyCell.parentNode?.parentNode?.parentNode
?.parentElement as HTMLElement,
);
firstRowCompanyCell = await canvas.findByText(
mockedPeopleData[0].company.name,
);

View File

@ -9,6 +9,7 @@ const StyledLayout = styled.div`
flex-direction: row;
height: fit-content;
max-width: calc(100% - 40px);
min-width: 300px;
padding: 20px;
width: fit-content;

View File

@ -1,32 +0,0 @@
import { ApolloProvider } from '@apollo/client';
import { Decorator } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { RecoilScope } from '@/ui/recoil-scope/components/RecoilScope';
import { CellContext } from '@/ui/table/states/CellContext';
import { RowContext } from '@/ui/table/states/RowContext';
import { ComponentStorybookLayout } from './ComponentStorybookLayout';
import { mockedClient } from './mockedClient';
export const RootDecorator: Decorator = (Story) => (
<RecoilRoot>
<ApolloProvider client={mockedClient}>
<Story />
</ApolloProvider>
</RecoilRoot>
);
export const ComponentDecorator: Decorator = (Story) => (
<ComponentStorybookLayout>
<Story />
</ComponentStorybookLayout>
);
export const CellPositionDecorator: Decorator = (Story) => (
<RecoilScope SpecificContext={RowContext}>
<RecoilScope SpecificContext={CellContext}>
<Story />
</RecoilScope>
</RecoilScope>
);

View File

@ -0,0 +1,13 @@
import { Decorator } from '@storybook/react';
import { RecoilScope } from '../../modules/ui/recoil-scope/components/RecoilScope';
import { CellContext } from '../../modules/ui/table/states/CellContext';
import { RowContext } from '../../modules/ui/table/states/RowContext';
export const CellPositionDecorator: Decorator = (Story) => (
<RecoilScope SpecificContext={RowContext}>
<RecoilScope SpecificContext={CellContext}>
<Story />
</RecoilScope>
</RecoilScope>
);

View File

@ -0,0 +1,9 @@
import { Decorator } from '@storybook/react';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentDecorator: Decorator = (Story) => (
<ComponentStorybookLayout>
<Story />
</ComponentStorybookLayout>
);

View File

@ -0,0 +1,12 @@
import { MemoryRouter } from 'react-router-dom';
import { Decorator } from '@storybook/react';
import { ComponentStorybookLayout } from '../ComponentStorybookLayout';
export const ComponentWithRouterDecorator: Decorator = (Story) => (
<ComponentStorybookLayout>
<MemoryRouter>
<Story />
</MemoryRouter>
</ComponentStorybookLayout>
);

View File

@ -0,0 +1,110 @@
import styled from '@emotion/styled';
import { Decorator, StrictArgs } from '@storybook/react';
function stateProps(state: string) {
switch (state) {
case 'default':
return {};
case 'hover':
return { className: 'hover' };
case 'active':
return { className: 'active' };
case 'disabled':
return { disabled: true };
default:
return {};
}
}
const StyledSizeTitle = styled.h1`
font-size: ${({ theme }) => theme.font.size.lg};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
`;
const StyledVariantTitle = styled.h1`
color: ${({ theme }) => theme.font.color.tertiary};
font-size: ${({ theme }) => theme.font.size.md};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin: ${({ theme }) => theme.spacing(2)};
`;
const StyledStateTitle = styled.span`
color: ${({ theme }) => theme.font.color.light};
font-size: ${({ theme }) => theme.font.size.xs};
font-weight: ${({ theme }) => theme.font.weight.semiBold};
margin-bottom: ${({ theme }) => theme.spacing(1)};
text-align: center;
text-transform: uppercase;
`;
const StyledContainer = styled.div`
display: flex;
flex-direction: row;
`;
const StyledSizeContainer = styled.div`
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
const StyledLineContainer = styled.div`
display: flex;
flex: 1;
flex-direction: row;
gap: ${({ theme }) => theme.spacing(2)};
`;
const StyledComponentContainer = styled.div`
align-items: center;
display: flex;
flex-direction: column;
padding: ${({ theme }) => theme.spacing(2)};
`;
function renderSize(
size: string,
variants: string[],
states: string[],
args: StrictArgs,
Story: React.FC<StrictArgs>,
) {
return (
<StyledSizeContainer key={size}>
<StyledSizeTitle>{size}</StyledSizeTitle>
{variants.map((variant) => (
<div key={variant}>
<StyledVariantTitle>{variant}</StyledVariantTitle>
<StyledLineContainer>
{states.map((state) => (
<StyledComponentContainer key={`${variant}-container-${state}`}>
<StyledStateTitle>{state}</StyledStateTitle>
<Story
args={{ ...args, variant: variant, ...stateProps(state) }}
/>
</StyledComponentContainer>
))}
</StyledLineContainer>
</div>
))}
</StyledSizeContainer>
);
}
export const ExhaustiveComponentDecorator: Decorator = (Story, context) => {
const parameters = context.parameters;
return (
<StyledContainer>
{parameters.sizes.map((size: string) =>
renderSize(
size,
parameters.variants,
parameters.states,
context.args,
Story,
),
)}
</StyledContainer>
);
};

View File

@ -0,0 +1,13 @@
import { ApolloProvider } from '@apollo/client';
import { Decorator } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { mockedClient } from '../mockedClient';
export const RootDecorator: Decorator = (Story) => (
<RecoilRoot>
<ApolloProvider client={mockedClient}>
<Story />
</ApolloProvider>
</RecoilRoot>
);