Improve test coverage (#6244)

This commit is contained in:
Charles Bochet
2024-07-13 17:57:13 +02:00
committed by GitHub
parent 1e48fe2b74
commit dc6e27e388
7 changed files with 153 additions and 17 deletions

View File

@ -49,6 +49,6 @@ export const Elipsis: Story = {
export const Performance = getProfilingStory({
componentName: 'AddressFieldDisplay',
averageThresholdInMs: 0.15,
numberOfRuns: 50,
numberOfTestsPerRun: 100,
numberOfRuns: 30,
numberOfTestsPerRun: 50,
});

View File

@ -1,8 +1,8 @@
import React from 'react';
import { Link } from 'react-router-dom';
import isPropValid from '@emotion/is-prop-valid';
import { css, useTheme } from '@emotion/react';
import styled from '@emotion/styled';
import React from 'react';
import { Link } from 'react-router-dom';
import { IconComponent, Pill } from 'twenty-ui';
export type ButtonSize = 'medium' | 'small';
@ -27,6 +27,7 @@ export type ButtonProps = {
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void;
to?: string;
target?: string;
dataTestId?: string;
} & React.ComponentProps<'button'>;
const StyledButton = styled('button', {
@ -374,6 +375,7 @@ export const Button = ({
onClick,
to,
target,
dataTestId,
}: ButtonProps) => {
const theme = useTheme();
@ -393,6 +395,7 @@ export const Button = ({
to={to}
as={to ? Link : 'button'}
target={target}
data-testid={dataTestId}
>
{Icon && <Icon size={theme.icon.size.sm} />}
{title}

View File

@ -1,6 +1,6 @@
import { ReactNode, useState } from 'react';
import styled from '@emotion/styled';
import { AnimatePresence, LayoutGroup } from 'framer-motion';
import { ReactNode, useState } from 'react';
import { H1Title, H1TitleFontColor } from 'twenty-ui';
import { useDebouncedCallback } from 'use-debounce';
@ -130,6 +130,7 @@ export const ConfirmationModal = ({
title={deleteButtonText}
disabled={!isValidValue}
fullWidth
dataTestId="confirmation-modal-confirm-button"
/>
</StyledConfirmationModal>
</LayoutGroup>

View File

@ -1,4 +1,4 @@
import React, { useEffect, useRef } from 'react';
import { useEffect, useRef } from 'react';
import { Key } from 'ts-key-enum';
import {
@ -7,11 +7,8 @@ import {
} from '@/ui/layout/modal/components/ModalLayout';
import { usePreviousHotkeyScope } from '@/ui/utilities/hotkey/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/ui/utilities/hotkey/hooks/useScopedHotkeys';
import {
ClickOutsideMode,
useListenClickOutside,
} from '@/ui/utilities/pointer-event/hooks/useListenClickOutside';
import { useListenClickOutsideV2 } from '@/ui/utilities/pointer-event/hooks/useListenClickOutsideV2';
import { ModalHotkeyScope } from './types/ModalHotkeyScope';
type ModalProps = ModalLayoutProps & {
@ -68,10 +65,10 @@ export const Modal = ({
const modalRef = useRef<HTMLDivElement>(null);
useListenClickOutside({
useListenClickOutsideV2({
refs: [modalRef],
listenerId: 'MODAL_CLICK_OUTSIDE_LISTENER_ID',
callback: () => onClose?.(),
mode: ClickOutsideMode.comparePixels,
});
return isOpen ? (

View File

@ -0,0 +1,84 @@
import { getOperationName } from '@apollo/client/utilities';
import { Meta, StoryObj } from '@storybook/react';
import { fireEvent, within } from '@storybook/test';
import { HttpResponse, graphql } from 'msw';
import { AppPath } from '@/types/AppPath';
import { GET_CURRENT_USER } from '@/users/graphql/queries/getCurrentUser';
import { GET_WORKSPACE_FROM_INVITE_HASH } from '@/workspace/graphql/queries/getWorkspaceFromInviteHash';
import {
PageDecorator,
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { Invite } from '../Invite';
const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Auth/Invite',
component: Invite,
decorators: [PageDecorator],
args: {
routePath: AppPath.Invite,
routeParams: { ':workspaceInviteHash': 'my-hash' },
},
parameters: {
msw: {
handlers: [
graphql.query(
getOperationName(GET_WORKSPACE_FROM_INVITE_HASH) ?? '',
() => {
return HttpResponse.json({
data: {
findWorkspaceFromInviteHash: {
__typename: 'Workspace',
id: '20202020-91f0-46d0-acab-cb5afef3cc3b',
displayName: 'Twenty dev',
logo: null,
allowImpersonation: false,
},
},
});
},
),
graphql.query(getOperationName(GET_CURRENT_USER) ?? '', () => {
return HttpResponse.json({
data: null,
errors: [
{
message: 'Unauthorized',
extensions: {
code: 'UNAUTHENTICATED',
response: {
statusCode: 401,
message: 'Unauthorized',
},
},
},
],
});
}),
graphqlMocks.handlers,
],
},
cookie: '',
},
};
export default meta;
export type Story = StoryObj<typeof Invite>;
export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await canvas.findByText('Join Twenty dev team');
const continueWithEmailButton = await canvas.findByText(
'Continue With Email',
);
await fireEvent.click(continueWithEmailButton);
},
};

View File

@ -1,6 +1,6 @@
import { Meta, StoryObj } from '@storybook/react';
import { within } from '@storybook/test';
import { graphql, HttpResponse } from 'msw';
import { userEvent, within } from '@storybook/test';
import { HttpResponse, graphql } from 'msw';
import { SettingsDevelopersApiKeyDetail } from '~/pages/settings/developers/api-keys/SettingsDevelopersApiKeyDetail';
import {
@ -8,6 +8,7 @@ import {
PageDecoratorArgs,
} from '~/testing/decorators/PageDecorator';
import { graphqlMocks } from '~/testing/graphqlMocks';
import { sleep } from '~/utils/sleep';
const meta: Meta<PageDecoratorArgs> = {
title: 'Pages/Settings/Developers/ApiKeys/SettingsDevelopersApiKeyDetail',
@ -50,6 +51,56 @@ export const Default: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await canvas.findByText('Settings');
await canvas.findByText('Regenerate an Api key');
await canvas.findByText('sfsfdsf API Key');
},
};
export const RegenerateApiKey: Story = {
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await canvas.findByText('Settings');
await userEvent.click(canvas.getByText('Regenerate Key'));
await canvas.findByText('Cancel');
const confirmationInput = await canvas.findByPlaceholderText('yes');
await userEvent.click(confirmationInput);
await userEvent.keyboard('y');
await userEvent.keyboard('e');
await userEvent.keyboard('s');
const confirmButton = await canvas.findByTestId(
'confirmation-modal-confirm-button',
);
await step('Click on confirm button', async () => {
await sleep(1000);
await userEvent.click(confirmButton);
});
},
};
export const DeleteApiKey: Story = {
play: async ({ canvasElement, step }) => {
const canvas = within(canvasElement);
await canvas.findByText('Settings');
await userEvent.click(canvas.getByText('Delete'));
await canvas.findByText('Cancel');
const confirmationInput = await canvas.findByPlaceholderText('yes');
await userEvent.click(confirmationInput);
await userEvent.keyboard('y');
await userEvent.keyboard('e');
await userEvent.keyboard('s');
const confirmButton = await canvas.findByTestId(
'confirmation-modal-confirm-button',
);
await step('Click on confirm button', async () => {
await sleep(1000);
await userEvent.click(confirmButton);
});
},
};

View File

@ -1,8 +1,8 @@
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import styled from '@emotion/styled';
import { isNonEmptyString } from '@sniptt/guards';
import { DateTime } from 'luxon';
import { useEffect, useState } from 'react';
import { useNavigate, useParams } from 'react-router-dom';
import { useRecoilState } from 'recoil';
import { H2Title, IconRepeat, IconSettings, IconTrash } from 'twenty-ui';