Re-write test with storybook testing library (#150)

* Re-write test with storybook testing library

* Update CI
This commit is contained in:
Charles Bochet
2023-05-29 11:02:38 +02:00
committed by GitHub
parent 8f88605f32
commit f935a6b723
65 changed files with 8085 additions and 5164 deletions

View File

@ -0,0 +1,11 @@
{ /* People.mdx */ }
import { Canvas, Meta } from '@storybook/blocks';
import * as People from './People.stories';
<Meta of={People} />
# People View
<Canvas of={People.Default} />

View File

@ -1,73 +1,113 @@
import { MemoryRouter } from 'react-router-dom';
import People from '../People';
import { expect } from '@storybook/jest';
import type { Meta, StoryObj } from '@storybook/react';
import { RecoilRoot } from 'recoil';
import { ThemeProvider } from '@emotion/react';
import { lightTheme } from '../../../layout/styles/themes';
import { MockedProvider } from '@apollo/client/testing';
import { mockPeopleData } from '../__tests__/__data__/mock-data';
import { GET_PEOPLE } from '../../../services/api/people';
import { SEARCH_PEOPLE_QUERY } from '../../../services/api/search/search';
import {
GraphqlMutationPerson,
GraphqlQueryPerson,
} from '../../../interfaces/entities/person.interface';
import { MemoryRouter } from 'react-router-dom';
import { graphql } from 'msw';
import { ApolloClient, ApolloProvider, InMemoryCache } from '@apollo/client';
import { userEvent, within } from '@storybook/testing-library';
const component = {
title: 'People',
import People from '../People';
import { lightTheme } from '../../../layout/styles/themes';
import { FullHeightStorybookLayout } from '../../../testing/FullHeightStorybookLayout';
import { filterAndSortData } from '../../../testing/mock-data';
import { GraphqlQueryPerson } from '../../../interfaces/entities/person.interface';
import { mockedPeopleData } from '../../../testing/mock-data/people';
import { GraphqlQueryCompany } from '../../../interfaces/entities/company.interface';
import { mockCompaniesData } from '../../../testing/mock-data/companies';
const meta: Meta<typeof People> = {
title: 'Pages/People',
component: People,
};
export default component;
const mockedClient = new ApolloClient({
uri: process.env.REACT_APP_API_URL,
cache: new InMemoryCache(),
defaultOptions: {
watchQuery: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
query: {
fetchPolicy: 'no-cache',
errorPolicy: 'all',
},
},
});
const mocks = [
{
request: {
query: GET_PEOPLE,
variables: {
orderBy: [{ createdAt: 'desc' }],
where: {},
},
},
result: {
data: {
people: mockPeopleData,
},
},
},
{
request: {
query: GET_PEOPLE,
variables: {
orderBy: [{ createdAt: 'desc' }],
where: {},
},
},
result: {
data: {
people: mockPeopleData,
},
},
},
{
request: {
query: SEARCH_PEOPLE_QUERY, // TODO this should not be called for empty filters
variables: {
where: undefined,
},
},
result: {
data: {
people: [],
},
},
},
export default meta;
type Story = StoryObj<typeof People>;
const render = () => (
<RecoilRoot>
<ApolloProvider client={mockedClient}>
<ThemeProvider theme={lightTheme}>
<MemoryRouter>
<FullHeightStorybookLayout>
<People />
</FullHeightStorybookLayout>
</MemoryRouter>
</ThemeProvider>
</ApolloProvider>
</RecoilRoot>
);
const defaultMocks = [
graphql.query('GetPeople', (req, res, ctx) => {
const returnedMockedData = filterAndSortData<GraphqlQueryPerson>(
mockedPeopleData,
req.variables.where,
req.variables.orderBy,
req.variables.limit,
);
return res(
ctx.data({
people: returnedMockedData,
}),
);
}),
graphql.query('SearchQuery', (req, res, ctx) => {
const returnedMockedData = filterAndSortData<GraphqlQueryCompany>(
mockCompaniesData,
req.variables.where,
req.variables.orderBy,
req.variables.limit,
);
return res(
ctx.data({
searchResults: returnedMockedData,
}),
);
}),
];
export const PeopleDefault = () => (
<MockedProvider mocks={mocks}>
<ThemeProvider theme={lightTheme}>
<MemoryRouter>
<People />
</MemoryRouter>
</ThemeProvider>
</MockedProvider>
);
export const Default: Story = {
render,
parameters: {
msw: defaultMocks,
},
};
export const FilterByEmail: Story = {
render,
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const filterButton = canvas.getByText('Filter');
await userEvent.click(filterButton);
const emailFilterButton = canvas.getByText('Email', { selector: 'li' });
await userEvent.click(emailFilterButton);
const emailInput = canvas.getByPlaceholderText('Email');
await userEvent.type(emailInput, 'al', {
delay: 200,
});
await expect(canvas.queryAllByText('John')).toStrictEqual([]);
},
parameters: {
msw: defaultMocks,
},
};

View File

@ -1,109 +0,0 @@
import { fireEvent, render, waitFor } from '@testing-library/react';
import { PeopleDefault } from '../__stories__/People.stories';
import { act } from 'react-dom/test-utils';
import {
GraphqlMutationPerson,
GraphqlQueryPerson,
} from '../../../interfaces/entities/person.interface';
jest.mock('../../../apollo', () => {
const personInterface = jest.requireActual(
'../../../interfaces/entities/person.interface',
);
return {
apiClient: {
mutate: (arg: {
mutation: unknown;
variables: GraphqlMutationPerson;
}) => {
const gqlPerson = arg.variables as unknown as GraphqlQueryPerson;
return {
data: { updateOnePerson: personInterface.mapToPerson(gqlPerson) },
};
},
},
};
});
it('Checks people full name edit is updating data', async () => {
const { getByText, getByDisplayValue } = render(<PeopleDefault />);
await waitFor(() => {
expect(getByText('John Doe')).toBeDefined();
});
act(() => {
fireEvent.click(getByText('John Doe'));
});
await waitFor(() => {
expect(getByDisplayValue('John')).toBeInTheDocument();
});
act(() => {
const nameInput = getByDisplayValue('John');
if (!nameInput) {
throw new Error('firstNameInput is null');
}
fireEvent.change(nameInput, { target: { value: 'Jo' } });
expect(nameInput).toHaveValue('Jo');
fireEvent.click(getByText('All People')); // Click outside
});
await waitFor(() => {
expect(getByText('John Doe')).toBeInTheDocument();
});
});
it('Checks people email edit is updating data', async () => {
const { getByText, getByDisplayValue } = render(<PeopleDefault />);
await waitFor(() => {
expect(getByText('john@linkedin.com')).toBeDefined();
});
act(() => {
fireEvent.click(getByText('john@linkedin.com'));
});
await waitFor(() => {
expect(getByDisplayValue('john@linkedin.com')).toBeInTheDocument();
});
act(() => {
const emailInput = getByDisplayValue('john@linkedin.com');
if (!emailInput) {
throw new Error('emailInput is null');
}
fireEvent.change(emailInput, { target: { value: 'john@linkedin.c' } });
fireEvent.click(getByText('All People')); // Click outside
});
await waitFor(() => {
expect(getByText('john@linkedin.c')).toBeInTheDocument();
});
});
it('Checks insert data is appending a new line', async () => {
const { getByText, getByTestId, container } = render(<PeopleDefault />);
await waitFor(() => {
expect(getByText('John Doe')).toBeDefined();
});
const tableRows = container.querySelectorAll<HTMLElement>('table tbody tr');
expect(tableRows.length).toBe(4);
act(() => {
fireEvent.click(getByTestId('add-button'));
});
await waitFor(() => {
const tableRows = container.querySelectorAll<HTMLElement>('table tbody tr');
expect(tableRows.length).toBe(5);
});
});

View File

@ -1,73 +0,0 @@
import { GraphqlQueryPerson } from '../../../../interfaces/entities/person.interface';
export const mockPeopleData: Array<GraphqlQueryPerson> = [
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
__typename: 'Person',
firstname: 'Alexandre',
lastname: 'Prot',
email: 'alexandre@qonto.com',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6c',
name: 'Qonto',
domain_name: 'qonto.com',
__typename: 'Company',
},
phone: '06 12 34 56 78',
created_at: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6d',
__typename: 'Person',
firstname: 'John',
lastname: 'Doe',
email: 'john@linkedin.com',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6e',
name: 'LinkedIn',
domain_name: 'linkedin.com',
__typename: 'Company',
},
phone: '06 12 34 56 78',
created_at: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6f',
__typename: 'Person',
firstname: 'Jane',
lastname: 'Doe',
email: 'jane@sequoiacap.com',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6g',
name: 'Sequoia',
domain_name: 'sequoiacap.com',
__typename: 'Company',
},
phone: '06 12 34 56 78',
created_at: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
{
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6h',
__typename: 'Person',
firstname: 'Janice',
lastname: 'Dane',
email: 'janice@facebook.com',
company: {
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6i',
name: 'Facebook',
domain_name: 'facebook.com',
__typename: 'Company',
},
phone: '06 12 34 56 78',
created_at: '2023-04-20T13:20:09.158312+00:00',
city: 'Paris',
},
];