Re-write test with storybook testing library (#150)
* Re-write test with storybook testing library * Update CI
This commit is contained in:
File diff suppressed because one or more lines are too long
@ -1,16 +0,0 @@
|
||||
import { render, waitFor } from '@testing-library/react';
|
||||
import { RegularApp } from '../__stories__/App.stories';
|
||||
|
||||
const assignMock = jest.fn();
|
||||
|
||||
delete window.location;
|
||||
window.location = { assign: assignMock };
|
||||
|
||||
it('Checks the App component renders', async () => {
|
||||
const { getByText } = render(<RegularApp />);
|
||||
|
||||
expect(getByText('Companies')).toBeDefined();
|
||||
await waitFor(() => {
|
||||
expect(getByText('Twenty')).toBeDefined();
|
||||
});
|
||||
});
|
||||
@ -10,6 +10,8 @@ import { RestLink } from 'apollo-link-rest';
|
||||
import { onError } from '@apollo/client/link/error';
|
||||
import { refreshAccessToken } from './services/auth/AuthService';
|
||||
|
||||
console.log(process.env.REACT_APP_API_URL);
|
||||
|
||||
const apiLink = createHttpLink({
|
||||
uri: `${process.env.REACT_APP_API_URL}`,
|
||||
});
|
||||
|
||||
@ -1,17 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import RequireAuth from '../RequireAuth';
|
||||
|
||||
const component = {
|
||||
title: 'RequireAuth',
|
||||
component: RequireAuth,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const RequireAuthWithHelloChild = () => (
|
||||
<MemoryRouter>
|
||||
<RequireAuth>
|
||||
<div>Hello</div>
|
||||
</RequireAuth>
|
||||
</MemoryRouter>
|
||||
);
|
||||
@ -1,9 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { RequireAuthWithHelloChild } from '../__stories__/RequireAuth.stories';
|
||||
|
||||
it('Checks the Require Auth renders', () => {
|
||||
const { getAllByText } = render(<RequireAuthWithHelloChild />);
|
||||
|
||||
expect(getAllByText('Hello')).toBeTruthy();
|
||||
});
|
||||
@ -1,26 +0,0 @@
|
||||
import CompanyChip from '../CompanyChip';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'CompanyChip',
|
||||
component: CompanyChip,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const RegularCompanyChip = () => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<CompanyChip name="selected-company-1" />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const RegularCompanyChipWithImage = () => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<CompanyChip name="selected-company-1" picture="coucou.fr" />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,26 +0,0 @@
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import PersonChip from '../PersonChip';
|
||||
|
||||
const component = {
|
||||
title: 'PersonChip',
|
||||
component: PersonChip,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const RegularPersonChip = () => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<PersonChip name="selected-company-1" />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const RegularPersonChipWithImage = () => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<PersonChip name="selected-company-1" picture="coucou.fr" />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,18 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import {
|
||||
RegularCompanyChip,
|
||||
RegularCompanyChipWithImage,
|
||||
} from '../__stories__/CompanyChip.stories';
|
||||
|
||||
it('Checks the CompanyChip renders', () => {
|
||||
const { getByText } = render(<RegularCompanyChip />);
|
||||
|
||||
expect(getByText('selected-company-1')).toBeDefined();
|
||||
});
|
||||
|
||||
it('Checks the CompanyChip img renders', () => {
|
||||
const { getByTestId } = render(<RegularCompanyChipWithImage />);
|
||||
|
||||
expect(getByTestId('company-chip-image')).toHaveAttribute('src', 'coucou.fr');
|
||||
});
|
||||
@ -1,22 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import {
|
||||
RegularPersonChip,
|
||||
RegularPersonChipWithImage,
|
||||
} from '../__stories__/PersonChip.stories';
|
||||
|
||||
it('Checks the PersonChip renders', () => {
|
||||
const { getByText, getByTestId } = render(<RegularPersonChip />);
|
||||
|
||||
expect(getByText('selected-company-1')).toBeDefined();
|
||||
expect(getByTestId('person-chip-image')).toHaveAttribute(
|
||||
'src',
|
||||
'person-placeholder.png',
|
||||
);
|
||||
});
|
||||
|
||||
it('Checks the PersonChip img renders', () => {
|
||||
const { getByTestId } = render(<RegularPersonChipWithImage />);
|
||||
|
||||
expect(getByTestId('person-chip-image')).toHaveAttribute('src', 'coucou.fr');
|
||||
});
|
||||
@ -1,33 +0,0 @@
|
||||
import EditableChip, { EditableChipProps } from '../EditableChip';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import CompanyChip from '../../chips/CompanyChip';
|
||||
|
||||
const component = {
|
||||
title: 'EditableChip',
|
||||
component: EditableChip,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const Template: StoryFn<typeof EditableChip> = (args: EditableChipProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<div data-testid="content-editable-parent">
|
||||
<EditableChip {...args} />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableChipStory = Template.bind({});
|
||||
EditableChipStory.args = {
|
||||
ChipComponent: CompanyChip,
|
||||
placeholder: 'Test',
|
||||
value: 'Test',
|
||||
picture: 'https://picsum.photos/200',
|
||||
changeHandler: () => {
|
||||
console.log('changed');
|
||||
},
|
||||
};
|
||||
@ -1,29 +0,0 @@
|
||||
import EditableDate, { EditableDateProps } from '../EditableDate';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
|
||||
const component = {
|
||||
title: 'EditableDate',
|
||||
component: EditableDate,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const Template: StoryFn<typeof EditableDate> = (args: EditableDateProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<div data-testid="content-editable-parent">
|
||||
<EditableDate {...args} />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableDateStory = Template.bind({});
|
||||
EditableDateStory.args = {
|
||||
value: new Date(),
|
||||
changeHandler: () => {
|
||||
console.log('changed');
|
||||
},
|
||||
};
|
||||
@ -1,39 +0,0 @@
|
||||
import { EditablePeopleFullName } from '../../people/EditablePeopleFullName';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const component = {
|
||||
title: 'EditableFullName',
|
||||
component: EditablePeopleFullName,
|
||||
};
|
||||
|
||||
type OwnProps = {
|
||||
firstname: string;
|
||||
lastname: string;
|
||||
onChange: (firstname: string, lastname: string) => void;
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const Template: StoryFn<typeof EditablePeopleFullName> = (args: OwnProps) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<div data-testid="content-editable-parent">
|
||||
<EditablePeopleFullName {...args} />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableFullNameStory = Template.bind({});
|
||||
EditableFullNameStory.args = {
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
onChange: () => {
|
||||
console.log('validated');
|
||||
},
|
||||
};
|
||||
@ -1,38 +0,0 @@
|
||||
import EditablePhone from '../EditablePhone';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
|
||||
const component = {
|
||||
title: 'EditablePhone',
|
||||
component: EditablePhone,
|
||||
};
|
||||
|
||||
type OwnProps = {
|
||||
value: string;
|
||||
changeHandler: (updated: string) => void;
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const Template: StoryFn<typeof EditablePhone> = (args: OwnProps) => {
|
||||
return (
|
||||
<MemoryRouter>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<div data-testid="content-editable-parent">
|
||||
<EditablePhone {...args} />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
</MemoryRouter>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditablePhoneStory = Template.bind({});
|
||||
EditablePhoneStory.args = {
|
||||
placeholder: 'Test placeholder',
|
||||
value: '+33657646543',
|
||||
changeHandler: () => {
|
||||
console.log('changed');
|
||||
},
|
||||
};
|
||||
@ -1,103 +0,0 @@
|
||||
import EditableRelation, { EditableRelationProps } from '../EditableRelation';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import CompanyChip, { CompanyChipPropsType } from '../../chips/CompanyChip';
|
||||
import {
|
||||
Company,
|
||||
mapToCompany,
|
||||
} from '../../../interfaces/entities/company.interface';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { SEARCH_COMPANY_QUERY } from '../../../services/api/search/search';
|
||||
import styled from '@emotion/styled';
|
||||
import { SearchConfigType } from '../../../interfaces/search/interface';
|
||||
import { QueryMode } from '../../../generated/graphql';
|
||||
|
||||
const component = {
|
||||
title: 'editable-cell/EditableRelation',
|
||||
component: EditableRelation,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const StyledParent = styled.div`
|
||||
height: 400px;
|
||||
`;
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: SEARCH_COMPANY_QUERY,
|
||||
variables: {
|
||||
where: undefined,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
companies: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: SEARCH_COMPANY_QUERY,
|
||||
variables: {
|
||||
where: { name: { contains: '%%', mode: QueryMode.Insensitive } },
|
||||
limit: 5,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
searchResults: [
|
||||
{ id: 'abnb', name: 'Airbnb', domain_name: 'abnb.com' },
|
||||
],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const Template: StoryFn<
|
||||
typeof EditableRelation<Company, CompanyChipPropsType>
|
||||
> = (args: EditableRelationProps<Company, CompanyChipPropsType>) => {
|
||||
return (
|
||||
<MockedProvider mocks={mocks}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<StyledParent data-testid="content-editable-parent">
|
||||
<EditableRelation<Company, CompanyChipPropsType> {...args} />
|
||||
</StyledParent>
|
||||
</ThemeProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableRelationStory = Template.bind({});
|
||||
EditableRelationStory.args = {
|
||||
relation: {
|
||||
__typename: 'companies',
|
||||
id: '123',
|
||||
name: 'Heroku',
|
||||
domain_name: 'heroku.com',
|
||||
} as Company,
|
||||
ChipComponent: CompanyChip,
|
||||
chipComponentPropsMapper: (company: Company): CompanyChipPropsType => {
|
||||
return {
|
||||
name: company.name || '',
|
||||
picture: company.domainName
|
||||
? `https://www.google.com/s2/favicons?domain=${company.domainName}&sz=256`
|
||||
: undefined,
|
||||
};
|
||||
},
|
||||
onChange: (relation: Company) => {
|
||||
console.log('changed', relation);
|
||||
},
|
||||
searchConfig: {
|
||||
query: SEARCH_COMPANY_QUERY,
|
||||
template: (searchInput: string) => ({
|
||||
name: { contains: `%${searchInput}%`, mode: QueryMode.Insensitive },
|
||||
}),
|
||||
resultMapper: (company) => ({
|
||||
render: (company) => company.name,
|
||||
value: mapToCompany(company),
|
||||
}),
|
||||
} satisfies SearchConfigType<Company>,
|
||||
};
|
||||
@ -1,35 +0,0 @@
|
||||
import EditableText from '../EditableText';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
|
||||
const component = {
|
||||
title: 'EditableText',
|
||||
component: EditableText,
|
||||
};
|
||||
|
||||
type OwnProps = {
|
||||
content: string;
|
||||
changeHandler: (updated: string) => void;
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const Template: StoryFn<typeof EditableText> = (args: OwnProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<div data-testid="content-editable-parent">
|
||||
<EditableText {...args} />
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const EditableTextStory = Template.bind({});
|
||||
EditableTextStory.args = {
|
||||
placeholder: 'Test placeholder',
|
||||
content: 'Test string',
|
||||
changeHandler: () => {
|
||||
console.log('changed');
|
||||
},
|
||||
};
|
||||
@ -1,34 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { EditableChipStory } from '../__stories__/EditableChip.stories';
|
||||
import CompanyChip from '../../chips/CompanyChip';
|
||||
|
||||
it('Checks the EditableChip editing event bubbles up', async () => {
|
||||
const func = jest.fn(() => null);
|
||||
const { getByTestId } = render(
|
||||
<EditableChipStory
|
||||
value="test"
|
||||
picture="http://"
|
||||
changeHandler={func}
|
||||
ChipComponent={CompanyChip}
|
||||
/>,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
fireEvent.click(wrapper);
|
||||
|
||||
const editableInput = parent.querySelector('input');
|
||||
|
||||
if (!editableInput) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
|
||||
fireEvent.change(editableInput, { target: { value: 'Test' } });
|
||||
expect(func).toBeCalledWith('Test');
|
||||
});
|
||||
@ -1,36 +0,0 @@
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { EditableDateStory } from '../__stories__/EditableDate.stories';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
it('Checks the EditableDate editing event bubbles up', async () => {
|
||||
const changeHandler = jest.fn(() => null);
|
||||
const { getByTestId, getByText } = render(
|
||||
<EditableDateStory
|
||||
value={new Date('2021-03-03')}
|
||||
changeHandler={changeHandler}
|
||||
/>,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Cell Wrapper not found');
|
||||
}
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(wrapper);
|
||||
const dateDisplay = parent.querySelector('div');
|
||||
if (!dateDisplay) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
});
|
||||
waitFor(() => {
|
||||
expect(getByText('March 2021')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
fireEvent.click(getByText('5'));
|
||||
expect(changeHandler).toHaveBeenCalledWith(new Date('2021-03-05'));
|
||||
});
|
||||
@ -1,37 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { EditableFullNameStory } from '../__stories__/EditableFullName.stories';
|
||||
|
||||
it('Checks the EditableFullName editing event bubbles up', async () => {
|
||||
const func = jest.fn(() => null);
|
||||
const { getByTestId } = render(
|
||||
<EditableFullNameStory firstname="Jone" lastname="Doe" onChange={func} />,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
fireEvent.click(wrapper);
|
||||
|
||||
const firstnameInput = parent.querySelector('input:first-child');
|
||||
|
||||
if (!firstnameInput) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
|
||||
fireEvent.change(firstnameInput, { target: { value: 'Jo' } });
|
||||
expect(func).toBeCalledWith('Jo', 'Doe');
|
||||
|
||||
const lastnameInput = parent.querySelector('input:last-child');
|
||||
|
||||
if (!lastnameInput) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
|
||||
fireEvent.change(lastnameInput, { target: { value: 'Do' } });
|
||||
expect(func).toBeCalledWith('Jo', 'Do');
|
||||
});
|
||||
@ -1,28 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { EditablePhoneStory } from '../__stories__/EditablePhone.stories';
|
||||
|
||||
it('Checks the EditablePhone editing event bubbles up', async () => {
|
||||
const func = jest.fn(() => null);
|
||||
const { getByTestId } = render(
|
||||
<EditablePhoneStory value="+33786405315" changeHandler={func} />,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
fireEvent.click(wrapper);
|
||||
|
||||
const editableInput = parent.querySelector('input');
|
||||
|
||||
if (!editableInput) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
|
||||
fireEvent.change(editableInput, { target: { value: '23' } });
|
||||
expect(func).toBeCalledWith('23');
|
||||
});
|
||||
@ -1,64 +0,0 @@
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { EditableRelationStory } from '../__stories__/EditableRelation.stories';
|
||||
import { CompanyChipPropsType } from '../../chips/CompanyChip';
|
||||
|
||||
import { EditableRelationProps } from '../EditableRelation';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Company } from '../../../interfaces/company.interface';
|
||||
|
||||
it('Checks the EditableRelation editing event bubbles up', async () => {
|
||||
const func = jest.fn(() => null);
|
||||
const { getByTestId, getByText } = render(
|
||||
<EditableRelationStory
|
||||
{...(EditableRelationStory.args as EditableRelationProps<
|
||||
Company,
|
||||
CompanyChipPropsType
|
||||
>)}
|
||||
onChange={func}
|
||||
/>,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Heroku')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Editable relation not found');
|
||||
}
|
||||
fireEvent.click(wrapper);
|
||||
|
||||
const input = parent.querySelector('input');
|
||||
if (!input) {
|
||||
throw new Error('Search input not found');
|
||||
}
|
||||
act(() => {
|
||||
fireEvent.change(input, { target: { value: 'Ai' } });
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Airbnb')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText('Airbnb'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(func).toBeCalledWith({
|
||||
__typename: 'companies',
|
||||
accountOwner: undefined,
|
||||
address: undefined,
|
||||
domainName: 'abnb.com',
|
||||
employees: undefined,
|
||||
creationDate: undefined,
|
||||
id: 'abnb',
|
||||
name: 'Airbnb',
|
||||
pipes: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -1,28 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { EditableTextStory } from '../__stories__/EditableText.stories';
|
||||
|
||||
it('Checks the EditableText editing event bubbles up', async () => {
|
||||
const func = jest.fn(() => null);
|
||||
const { getByTestId } = render(
|
||||
<EditableTextStory content="test" changeHandler={func} />,
|
||||
);
|
||||
|
||||
const parent = getByTestId('content-editable-parent');
|
||||
|
||||
const wrapper = parent.querySelector('div');
|
||||
|
||||
if (!wrapper) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
fireEvent.click(wrapper);
|
||||
|
||||
const editableInput = parent.querySelector('input');
|
||||
|
||||
if (!editableInput) {
|
||||
throw new Error('Editable input not found');
|
||||
}
|
||||
|
||||
fireEvent.change(editableInput, { target: { value: '23' } });
|
||||
expect(func).toBeCalledWith('23');
|
||||
});
|
||||
@ -1,18 +0,0 @@
|
||||
import Checkbox from '../Checkbox';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'Checkbox',
|
||||
component: Checkbox,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const RegularCheckbox = () => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<Checkbox name="selected-company-1" id="selected-company--1" />
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,36 +0,0 @@
|
||||
import DatePicker, { DatePickerProps } from '../DatePicker';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { StoryFn } from '@storybook/react';
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const component = {
|
||||
title: 'DatePicker',
|
||||
component: DatePicker,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const StyledContainer = styled.div`
|
||||
height: 300px;
|
||||
width: 200px;
|
||||
}`;
|
||||
|
||||
const Template: StoryFn<typeof DatePicker> = (args: DatePickerProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<StyledContainer>
|
||||
<DatePicker {...args} />
|
||||
</StyledContainer>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const DatePickerStory = Template.bind({});
|
||||
DatePickerStory.args = {
|
||||
isOpen: true,
|
||||
date: new Date(),
|
||||
onChangeHandler: () => {
|
||||
console.log('changed');
|
||||
},
|
||||
};
|
||||
@ -1,12 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { RegularCheckbox } from '../__stories__/Checkbox.stories';
|
||||
|
||||
it('Checks the Checkbox renders', () => {
|
||||
const { getByTestId } = render(<RegularCheckbox />);
|
||||
|
||||
expect(getByTestId('input-checkbox')).toHaveAttribute(
|
||||
'name',
|
||||
'selected-company-1',
|
||||
);
|
||||
});
|
||||
@ -1,27 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { DatePickerStory } from '../__stories__/Datepicker.stories';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
it('Checks the datepicker renders', async () => {
|
||||
const changeHandler = jest.fn();
|
||||
const { getByText } = render(
|
||||
<DatePickerStory
|
||||
date={new Date('2021-03-03')}
|
||||
onChangeHandler={changeHandler}
|
||||
/>,
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
expect(getByText('Mar 3, 2021')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText('Mar 3, 2021'));
|
||||
});
|
||||
expect(getByText('March 2021')).toBeInTheDocument();
|
||||
act(() => {
|
||||
fireEvent.click(getByText('5'));
|
||||
});
|
||||
expect(changeHandler).toHaveBeenCalledWith(new Date('2021-03-05'));
|
||||
});
|
||||
@ -1,102 +0,0 @@
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { FilterDropdownButton } from '../FilterDropdownButton';
|
||||
import styled from '@emotion/styled';
|
||||
import { useCallback, useState } from 'react';
|
||||
import { SEARCH_COMPANY_QUERY } from '../../../../services/api/search/search';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { availableFilters } from '../../../../pages/people/people-filters';
|
||||
import { Person } from '../../../../interfaces/entities/person.interface';
|
||||
import {
|
||||
FilterableFieldsType,
|
||||
SelectedFilterType,
|
||||
} from '../../../../interfaces/filters/interface';
|
||||
import { mockCompaniesData } from '../../../../pages/companies/__tests__/__data__/mock-data';
|
||||
import { QueryMode } from '../../../../generated/graphql';
|
||||
|
||||
const component = {
|
||||
title: 'FilterDropdownButton',
|
||||
component: FilterDropdownButton,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
type OwnProps<FilterProperties extends FilterableFieldsType> = {
|
||||
setFilter: (filters: SelectedFilterType<FilterProperties>) => void;
|
||||
};
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: SEARCH_COMPANY_QUERY,
|
||||
variables: {
|
||||
where: { name: { contains: '%%', mode: QueryMode.Insensitive } },
|
||||
limit: 5,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
searchResults: mockCompaniesData,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: SEARCH_COMPANY_QUERY,
|
||||
variables: {
|
||||
where: { name: { contains: '%Airc%', mode: QueryMode.Insensitive } },
|
||||
limit: 5,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
searchResults: mockCompaniesData.filter(
|
||||
(company) => company.name === 'Aircall',
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const StyleDiv = styled.div`
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
const InnerRegularFilterDropdownButton = ({
|
||||
setFilter: setFilters,
|
||||
}: OwnProps<Person>) => {
|
||||
const [, innerSetFilters] = useState<SelectedFilterType<Person>>();
|
||||
|
||||
const outerSetFilters = useCallback(
|
||||
(filter: SelectedFilterType<Person>) => {
|
||||
innerSetFilters(filter);
|
||||
setFilters(filter);
|
||||
},
|
||||
[setFilters],
|
||||
);
|
||||
return (
|
||||
<StyleDiv>
|
||||
<FilterDropdownButton<Person>
|
||||
availableFilters={availableFilters}
|
||||
isFilterSelected={true}
|
||||
onFilterSelect={outerSetFilters}
|
||||
onFilterRemove={(filterId) => {
|
||||
console.log(filterId);
|
||||
}}
|
||||
/>
|
||||
</StyleDiv>
|
||||
);
|
||||
};
|
||||
|
||||
export const RegularFilterDropdownButton = ({
|
||||
setFilter: setFilters,
|
||||
}: OwnProps<Person>) => {
|
||||
return (
|
||||
<MockedProvider mocks={mocks}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<InnerRegularFilterDropdownButton setFilter={setFilters} />
|
||||
</ThemeProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
@ -1,75 +0,0 @@
|
||||
import SortAndFilterBar from '../SortAndFilterBar';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { FaArrowDown } from 'react-icons/fa';
|
||||
import { Person } from '../../../../interfaces/entities/person.interface';
|
||||
import { SelectedFilterType } from '../../../../interfaces/filters/interface';
|
||||
|
||||
const component = {
|
||||
title: 'SortAndFilterBar',
|
||||
component: SortAndFilterBar,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
type OwnProps = {
|
||||
removeFunction: () => void;
|
||||
cancelFunction: () => void;
|
||||
};
|
||||
|
||||
export const RegularSortAndFilterBar = ({
|
||||
removeFunction,
|
||||
cancelFunction,
|
||||
}: OwnProps) => {
|
||||
const personFilter = {
|
||||
label: 'People',
|
||||
operand: {
|
||||
label: 'Is',
|
||||
id: 'is',
|
||||
whereTemplate: (person: Person) => {
|
||||
return { email: { equals: person.email } };
|
||||
},
|
||||
},
|
||||
key: 'test_filter',
|
||||
icon: <FaArrowDown />,
|
||||
displayValue: 'john@doedoe.com',
|
||||
value: {
|
||||
__typename: 'people',
|
||||
id: 'test',
|
||||
email: 'john@doedoe.com',
|
||||
firstname: 'John',
|
||||
lastname: 'Doe',
|
||||
phone: '123456789',
|
||||
company: null,
|
||||
creationDate: new Date(),
|
||||
pipes: null,
|
||||
city: 'Paris',
|
||||
},
|
||||
} satisfies SelectedFilterType<Person, Person>;
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<SortAndFilterBar
|
||||
sorts={[
|
||||
{
|
||||
label: 'Test sort',
|
||||
order: 'asc',
|
||||
key: 'test_sort',
|
||||
icon: <FaArrowDown />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
label: 'Test sort 2',
|
||||
order: 'desc',
|
||||
key: 'test_sort_2',
|
||||
icon: <FaArrowDown />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
]}
|
||||
onRemoveSort={removeFunction}
|
||||
onRemoveFilter={removeFunction}
|
||||
onCancelClick={cancelFunction}
|
||||
filters={[personFilter] as SelectedFilterType<Person>[]}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,88 +0,0 @@
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { SortDropdownButton } from '../SortDropdownButton';
|
||||
import styled from '@emotion/styled';
|
||||
import {
|
||||
SortOrder as Order_By,
|
||||
PersonOrderByWithRelationInput as People_Order_By,
|
||||
} from '../../../../generated/graphql';
|
||||
import { SortType } from '../../../../interfaces/sorts/interface';
|
||||
import {
|
||||
TbBuilding,
|
||||
TbCalendar,
|
||||
TbMail,
|
||||
TbMapPin,
|
||||
TbPhone,
|
||||
TbUser,
|
||||
} from 'react-icons/tb';
|
||||
|
||||
const component = {
|
||||
title: 'SortDropdownButton',
|
||||
component: SortDropdownButton,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
type OwnProps = {
|
||||
setSorts: () => void;
|
||||
};
|
||||
|
||||
const availableSorts = [
|
||||
{
|
||||
key: 'fullname',
|
||||
label: 'People',
|
||||
icon: <TbUser size={16} />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplates: [() => ({ email: Order_By.Asc })],
|
||||
},
|
||||
{
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
icon: <TbBuilding size={16} />,
|
||||
_type: 'custom_sort',
|
||||
orderByTemplates: [() => ({ email: Order_By.Asc })],
|
||||
},
|
||||
{
|
||||
key: 'email',
|
||||
label: 'Email',
|
||||
icon: <TbMail size={16} />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'phone',
|
||||
label: 'Phone',
|
||||
icon: <TbPhone size={16} />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'createdAt',
|
||||
label: 'Created at',
|
||||
icon: <TbCalendar size={16} />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
{
|
||||
key: 'city',
|
||||
label: 'City',
|
||||
icon: <TbMapPin size={16} />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
] satisfies SortType<People_Order_By>[];
|
||||
|
||||
const StyleDiv = styled.div`
|
||||
height: 200px;
|
||||
width: 200px;
|
||||
`;
|
||||
|
||||
export const RegularSortDropdownButton = ({ setSorts }: OwnProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<StyleDiv>
|
||||
<SortDropdownButton<People_Order_By>
|
||||
isSortSelected={true}
|
||||
availableSorts={availableSorts}
|
||||
onSortSelect={setSorts}
|
||||
/>
|
||||
</StyleDiv>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,43 +0,0 @@
|
||||
import SortOrFilterChip from '../SortOrFilterChip';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { FaArrowDown } from 'react-icons/fa';
|
||||
import { TbUser } from 'react-icons/tb';
|
||||
|
||||
const component = {
|
||||
title: 'SortOrFilterChip',
|
||||
component: SortOrFilterChip,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
type OwnProps = {
|
||||
removeFunction: () => void;
|
||||
};
|
||||
|
||||
export const RegularFilterChip = ({ removeFunction }: OwnProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<SortOrFilterChip
|
||||
id="test_sort"
|
||||
icon={<TbUser size={16} />}
|
||||
labelKey="Account owner"
|
||||
labelValue="is Charles"
|
||||
onRemove={removeFunction}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
|
||||
export const RegularSortChip = ({ removeFunction }: OwnProps) => {
|
||||
return (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<SortOrFilterChip
|
||||
id="test_sort"
|
||||
icon={<FaArrowDown />}
|
||||
labelValue="Created at"
|
||||
onRemove={removeFunction}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
};
|
||||
@ -1,51 +0,0 @@
|
||||
import TableHeader from '../TableHeader';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../../layout/styles/themes';
|
||||
import { SortType } from '../../../../interfaces/sorts/interface';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { EMPTY_QUERY } from '../../../../services/api/search/search';
|
||||
import { TbBuilding, TbCalendar } from 'react-icons/tb';
|
||||
|
||||
const component = {
|
||||
title: 'TableHeader',
|
||||
component: TableHeader,
|
||||
};
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: EMPTY_QUERY,
|
||||
variables: {
|
||||
where: undefined,
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
searchResults: [],
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export default component;
|
||||
|
||||
export const RegularTableHeader = () => {
|
||||
const availableSorts: Array<SortType<Record<'created_at', 'asc'>>> = [
|
||||
{
|
||||
key: 'created_at',
|
||||
label: 'Created at',
|
||||
icon: <TbCalendar size={16} />,
|
||||
_type: 'default_sort',
|
||||
},
|
||||
];
|
||||
return (
|
||||
<MockedProvider mocks={mocks}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<TableHeader
|
||||
viewName="Test"
|
||||
viewIcon={<TbBuilding size={16} />}
|
||||
availableSorts={availableSorts}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
};
|
||||
@ -1,117 +0,0 @@
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
import { RegularFilterDropdownButton } from '../__stories__/FilterDropdownButton.stories';
|
||||
|
||||
it('Checks the default top option is Is', async () => {
|
||||
const setFilters = jest.fn();
|
||||
const { getByText } = render(
|
||||
<RegularFilterDropdownButton setFilter={setFilters} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Filter');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const filterByCompany = getByText('Company');
|
||||
fireEvent.click(filterByCompany);
|
||||
|
||||
await waitFor(() => {
|
||||
const firstSearchResult = getByText('Airbnb');
|
||||
expect(firstSearchResult).toBeDefined();
|
||||
});
|
||||
|
||||
const filterByAirbnb = getByText('Airbnb');
|
||||
fireEvent.click(filterByAirbnb);
|
||||
|
||||
expect(setFilters).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
displayValue: 'Airbnb',
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('Checks the selection of top option for Is Not', async () => {
|
||||
const setFilters = jest.fn();
|
||||
const { getByText } = render(
|
||||
<RegularFilterDropdownButton setFilter={setFilters} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Filter');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const filterByCompany = getByText('Company');
|
||||
fireEvent.click(filterByCompany);
|
||||
|
||||
const openOperandOptions = getByText('Is');
|
||||
fireEvent.click(openOperandOptions);
|
||||
|
||||
const selectOperand = getByText('Is not');
|
||||
fireEvent.click(selectOperand);
|
||||
|
||||
await waitFor(() => {
|
||||
const firstSearchResult = getByText('Airbnb');
|
||||
expect(firstSearchResult).toBeDefined();
|
||||
});
|
||||
|
||||
const filterByAirbnb = getByText('Airbnb');
|
||||
fireEvent.click(filterByAirbnb);
|
||||
|
||||
expect(setFilters).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
displayValue: 'Airbnb',
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
}),
|
||||
);
|
||||
const blueSortDropdownButton = getByText('Filter');
|
||||
await waitFor(() => {
|
||||
expect(blueSortDropdownButton).toHaveAttribute('aria-selected', 'true');
|
||||
});
|
||||
});
|
||||
|
||||
it('Calls the filters when typing a new name', async () => {
|
||||
const setFilters = jest.fn();
|
||||
const { getByText, getByPlaceholderText, queryByText, getByTestId } = render(
|
||||
<RegularFilterDropdownButton setFilter={setFilters} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Filter');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const filterByCompany = getByText('Company');
|
||||
fireEvent.click(filterByCompany);
|
||||
|
||||
const filterSearch = getByPlaceholderText('Company');
|
||||
fireEvent.click(filterSearch);
|
||||
|
||||
fireEvent.change(filterSearch, { target: { value: 'Airc' } });
|
||||
|
||||
await waitFor(() => {
|
||||
const loadingDiv = getByTestId('loading-search-results');
|
||||
expect(loadingDiv).toBeDefined();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const firstSearchResult = getByText('Aircall');
|
||||
expect(firstSearchResult).toBeDefined();
|
||||
|
||||
const airbnbResult = queryByText('Airbnb');
|
||||
expect(airbnbResult).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
const filterByAircall = getByText('Aircall');
|
||||
|
||||
fireEvent.click(filterByAircall);
|
||||
|
||||
expect(setFilters).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
key: 'company_name',
|
||||
displayValue: 'Aircall',
|
||||
label: 'Company',
|
||||
}),
|
||||
);
|
||||
const blueSortDropdownButton = getByText('Filter');
|
||||
await waitFor(() => {
|
||||
expect(blueSortDropdownButton).toHaveAttribute('aria-selected', 'true');
|
||||
});
|
||||
});
|
||||
@ -1,36 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { RegularSortAndFilterBar } from '../__stories__/SortAndFilterBar.stories';
|
||||
|
||||
it('Checks the SortAndFilterBar renders', async () => {
|
||||
const removeFunction = jest.fn();
|
||||
const cancelFunction = jest.fn();
|
||||
|
||||
const { getByText, getByTestId } = render(
|
||||
<RegularSortAndFilterBar
|
||||
removeFunction={removeFunction}
|
||||
cancelFunction={cancelFunction}
|
||||
/>,
|
||||
);
|
||||
expect(getByText('Test sort')).toBeDefined();
|
||||
|
||||
const removeIcon = getByTestId('remove-icon-test_sort');
|
||||
fireEvent.click(removeIcon);
|
||||
|
||||
expect(removeFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Removes sorts when cancel is pressed', async () => {
|
||||
const removeFunction = jest.fn();
|
||||
const cancelFunction = jest.fn();
|
||||
const { getByTestId } = render(
|
||||
<RegularSortAndFilterBar
|
||||
removeFunction={removeFunction}
|
||||
cancelFunction={cancelFunction}
|
||||
/>,
|
||||
);
|
||||
const cancel = getByTestId('cancel-button');
|
||||
fireEvent.click(cancel);
|
||||
|
||||
expect(cancelFunction).toHaveBeenCalled();
|
||||
});
|
||||
@ -1,74 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
import { RegularSortDropdownButton } from '../__stories__/SortDropdownButton.stories';
|
||||
import { TbBuilding, TbMail } from 'react-icons/tb';
|
||||
|
||||
it('Checks the default top option is Ascending', async () => {
|
||||
const setSorts = jest.fn();
|
||||
const { getByText } = render(
|
||||
<RegularSortDropdownButton setSorts={setSorts} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Sort');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const sortByEmail = getByText('Email');
|
||||
fireEvent.click(sortByEmail);
|
||||
|
||||
expect(setSorts).toHaveBeenCalledWith({
|
||||
label: 'Email',
|
||||
key: 'email',
|
||||
icon: <TbMail size={16} />,
|
||||
order: 'asc',
|
||||
_type: 'default_sort',
|
||||
});
|
||||
});
|
||||
|
||||
it('Checks the selection of Descending', async () => {
|
||||
const setSorts = jest.fn();
|
||||
const { getByText } = render(
|
||||
<RegularSortDropdownButton setSorts={setSorts} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Sort');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const openTopOption = getByText('Ascending');
|
||||
fireEvent.click(openTopOption);
|
||||
|
||||
const selectDescending = getByText('Descending');
|
||||
fireEvent.click(selectDescending);
|
||||
|
||||
const sortByEmail = getByText('Email');
|
||||
fireEvent.click(sortByEmail);
|
||||
|
||||
expect(setSorts).toHaveBeenCalledWith({
|
||||
label: 'Email',
|
||||
key: 'email',
|
||||
icon: <TbMail size={16} />,
|
||||
order: 'desc',
|
||||
_type: 'default_sort',
|
||||
});
|
||||
});
|
||||
|
||||
it('Checks custom_sort is working', async () => {
|
||||
const setSorts = jest.fn();
|
||||
const { getByText } = render(
|
||||
<RegularSortDropdownButton setSorts={setSorts} />,
|
||||
);
|
||||
|
||||
const sortDropdownButton = getByText('Sort');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const sortByCompany = getByText('Company');
|
||||
fireEvent.click(sortByCompany);
|
||||
|
||||
expect(setSorts).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
key: 'company_name',
|
||||
label: 'Company',
|
||||
icon: <TbBuilding size={16} />,
|
||||
_type: 'custom_sort',
|
||||
order: 'asc',
|
||||
}),
|
||||
);
|
||||
});
|
||||
@ -1,32 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import {
|
||||
RegularFilterChip,
|
||||
RegularSortChip,
|
||||
} from '../__stories__/SortOrFilterChip.stories';
|
||||
|
||||
const removeFunction = jest.fn();
|
||||
|
||||
it('Checks the filter chip renders', async () => {
|
||||
const { getByText, getByTestId } = render(
|
||||
<RegularFilterChip removeFunction={removeFunction} />,
|
||||
);
|
||||
expect(getByText('Account owner:')).toBeDefined();
|
||||
|
||||
const removeIcon = getByTestId('remove-icon-test_sort');
|
||||
fireEvent.click(removeIcon);
|
||||
|
||||
expect(removeFunction).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('Checks the sort chip renders', async () => {
|
||||
const { getByText, getByTestId } = render(
|
||||
<RegularSortChip removeFunction={removeFunction} />,
|
||||
);
|
||||
expect(getByText('Created at')).toBeDefined();
|
||||
|
||||
const removeIcon = getByTestId('remove-icon-test_sort');
|
||||
fireEvent.click(removeIcon);
|
||||
|
||||
expect(removeFunction).toHaveBeenCalled();
|
||||
});
|
||||
@ -1,20 +0,0 @@
|
||||
import { fireEvent, render } from '@testing-library/react';
|
||||
|
||||
import { RegularTableHeader } from '../__stories__/TableHeader.stories';
|
||||
|
||||
it('Checks the TableHeader renders', async () => {
|
||||
const { getByText, queryByText } = render(<RegularTableHeader />);
|
||||
|
||||
const sortDropdownButton = getByText('Sort');
|
||||
fireEvent.click(sortDropdownButton);
|
||||
|
||||
const sortByCreatedAt = getByText('Created at');
|
||||
fireEvent.click(sortByCreatedAt);
|
||||
|
||||
expect(getByText('Created at')).toBeDefined();
|
||||
|
||||
const cancelButton = getByText('Cancel');
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
expect(queryByText('Created at')).toBeNull();
|
||||
});
|
||||
@ -1,21 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import AppLayout from '../AppLayout';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'AppLayout',
|
||||
component: AppLayout,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const AppLayoutDefault = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<AppLayout>
|
||||
<div data-testid="content">Test</div>
|
||||
</AppLayout>
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { AppLayoutDefault } from '../__stories__/AppLayout.stories';
|
||||
|
||||
it('Checks the AppLayout render', () => {
|
||||
const { getByTestId } = render(<AppLayoutDefault />);
|
||||
|
||||
const title = getByTestId('content');
|
||||
expect(title).toHaveTextContent('Test');
|
||||
});
|
||||
@ -1,34 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
|
||||
import NavItem from '../../../layout/navbar/NavItem';
|
||||
import { lightTheme } from '../../styles/themes';
|
||||
import { TbUser } from 'react-icons/tb';
|
||||
|
||||
const component = {
|
||||
title: 'NavItem',
|
||||
component: NavItem,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const NavItemDefault = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<NavItem label="Test" to="/test" icon={<TbUser size={16} />} />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
|
||||
export const NavItemActive = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter initialEntries={['/test']}>
|
||||
<NavItem
|
||||
label="Test"
|
||||
to="/test"
|
||||
active={true}
|
||||
icon={<TbUser size={16} />}
|
||||
/>
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
File diff suppressed because one or more lines are too long
@ -1,19 +0,0 @@
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
|
||||
import { NavItemDefault } from '../__stories__/NavItem.stories';
|
||||
|
||||
const mockedNavigate = jest.fn();
|
||||
jest.mock('react-router-dom', () => ({
|
||||
...jest.requireActual('react-router-dom'),
|
||||
useNavigate: () => mockedNavigate,
|
||||
}));
|
||||
|
||||
it('Checks the NavItem renders', () => {
|
||||
const { getByRole } = render(<NavItemDefault />);
|
||||
|
||||
const button = getByRole('button');
|
||||
expect(button).toHaveTextContent('Test');
|
||||
|
||||
fireEvent.click(button);
|
||||
expect(mockedNavigate).toHaveBeenCalledWith('/test');
|
||||
});
|
||||
@ -1,17 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { NavbarOnCompanies } from '../__stories__/Navbar.stories';
|
||||
|
||||
it('Checks the NavItem renders', () => {
|
||||
const { getByRole } = render(<NavbarOnCompanies />);
|
||||
|
||||
expect(getByRole('button', { name: 'Companies' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'true',
|
||||
);
|
||||
|
||||
expect(getByRole('button', { name: 'People' })).toHaveAttribute(
|
||||
'aria-selected',
|
||||
'false',
|
||||
);
|
||||
});
|
||||
@ -1,6 +1,6 @@
|
||||
import { useSetRecoilState } from 'recoil';
|
||||
import { currentRowSelectionState } from '../states/rowSelectionState';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export function useResetTableRowSelection() {
|
||||
const setCurrentRowSelectionState = useSetRecoilState(
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Callback from '../Callback';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'Callback',
|
||||
component: Callback,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const CallbackDefault = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<Callback />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
@ -1,19 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Login from '../Login';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'Login',
|
||||
component: Login,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const LoginDefault = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<Login />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { CallbackDefault } from '../__stories__/Callback.stories';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
it('Checks the Callback page render', async () => {
|
||||
await act(async () => {
|
||||
render(<CallbackDefault />);
|
||||
});
|
||||
});
|
||||
@ -1,15 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
import { LoginDefault } from '../__stories__/Login.stories';
|
||||
|
||||
const assignMock = jest.fn();
|
||||
|
||||
delete window.location;
|
||||
window.location = { assign: assignMock };
|
||||
|
||||
afterEach(() => {
|
||||
assignMock.mockClear();
|
||||
});
|
||||
|
||||
it('Checks the Login page render', () => {
|
||||
render(<LoginDefault />);
|
||||
});
|
||||
@ -1,75 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Companies from '../Companies';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
import { GET_COMPANIES } from '../../../services/api/companies';
|
||||
import { mockCompaniesData } from '../__tests__/__data__/mock-data';
|
||||
import { MockedProvider } from '@apollo/client/testing';
|
||||
import { QueryMode } from '../../../generated/graphql';
|
||||
|
||||
const component = {
|
||||
title: 'Companies',
|
||||
component: Companies,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
const mocks = [
|
||||
{
|
||||
request: {
|
||||
query: GET_COMPANIES,
|
||||
variables: {
|
||||
orderBy: [{ createdAt: 'desc' }],
|
||||
where: {},
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
companies: mockCompaniesData,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: GET_COMPANIES,
|
||||
variables: {
|
||||
orderBy: [{ createdAt: 'desc' }],
|
||||
where: {},
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
companies: mockCompaniesData,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
request: {
|
||||
query: GET_COMPANIES,
|
||||
variables: {
|
||||
orderBy: [{ createdAt: 'desc' }],
|
||||
where: {
|
||||
domainName: { contains: '%aircal%', mode: QueryMode.Insensitive },
|
||||
},
|
||||
},
|
||||
},
|
||||
result: {
|
||||
data: {
|
||||
companies: mockCompaniesData.filter(
|
||||
(company) =>
|
||||
company.domain_name && company.domain_name.includes('aircal'),
|
||||
),
|
||||
},
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
export const CompaniesDefault = () => (
|
||||
<MockedProvider mocks={mocks}>
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<Companies />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
</MockedProvider>
|
||||
);
|
||||
@ -1,169 +0,0 @@
|
||||
import { fireEvent, render, waitFor } from '@testing-library/react';
|
||||
|
||||
import { CompaniesDefault } from '../__stories__/Companies.stories';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import {
|
||||
GraphqlMutationCompany,
|
||||
GraphqlQueryCompany,
|
||||
} from '../../../interfaces/entities/company.interface';
|
||||
|
||||
jest.mock('../../../apollo', () => {
|
||||
const companyInterface = jest.requireActual(
|
||||
'../../../interfaces/entities/company.interface',
|
||||
);
|
||||
return {
|
||||
apiClient: {
|
||||
mutate: (arg: {
|
||||
mutation: unknown;
|
||||
variables: GraphqlMutationCompany;
|
||||
}) => {
|
||||
const gqlCompany = arg.variables as unknown as GraphqlQueryCompany;
|
||||
return {
|
||||
data: { updateOneCompany: companyInterface.mapToCompany(gqlCompany) },
|
||||
};
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
it('Checks company name edit is updating data', async () => {
|
||||
const { getByText, getByDisplayValue } = render(<CompaniesDefault />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Airbnb')).toBeDefined();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText('Airbnb'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByDisplayValue('Airbnb')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
const nameInput = getByDisplayValue('Airbnb');
|
||||
|
||||
if (!nameInput) {
|
||||
throw new Error('nameInput is null');
|
||||
}
|
||||
fireEvent.change(nameInput, { target: { value: 'Airbnbb' } });
|
||||
fireEvent.click(getByText('All Companies')); // Click outside
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Airbnbb')).toBeDefined();
|
||||
});
|
||||
});
|
||||
|
||||
it('Checks company url edit is updating data', async () => {
|
||||
const { getByText, getByDisplayValue } = render(<CompaniesDefault />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('airbnb.com')).toBeDefined();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText('airbnb.com'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByDisplayValue('airbnb.com')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
const urlInput = getByDisplayValue('airbnb.com');
|
||||
|
||||
if (!urlInput) {
|
||||
throw new Error('urlInput is null');
|
||||
}
|
||||
fireEvent.change(urlInput, { target: { value: 'airbnb.co' } });
|
||||
fireEvent.click(getByText('All Companies')); // Click outside
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('airbnb.co')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it.only('Checks company address edit is updating data', async () => {
|
||||
const { getByText, getByDisplayValue } = render(<CompaniesDefault />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('17 rue de clignancourt')).toBeDefined();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByText('17 rue de clignancourt'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByDisplayValue('17 rue de clignancourt')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
act(() => {
|
||||
const addressInput = getByDisplayValue('17 rue de clignancourt');
|
||||
|
||||
if (!addressInput) {
|
||||
throw new Error('addressInput is null');
|
||||
}
|
||||
fireEvent.change(addressInput, {
|
||||
target: { value: '21 rue de clignancourt' },
|
||||
});
|
||||
fireEvent.click(getByText('All Companies')); // Click outside
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('21 rue de clignancourt')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('Checks insert data is appending a new line', async () => {
|
||||
const { getByText, getByTestId, container } = render(<CompaniesDefault />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Airbnb')).toBeDefined();
|
||||
});
|
||||
const tableRows = container.querySelectorAll<HTMLElement>('table tbody tr');
|
||||
|
||||
expect(tableRows.length).toBe(6);
|
||||
|
||||
act(() => {
|
||||
fireEvent.click(getByTestId('add-button'));
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const tableRows = container.querySelectorAll<HTMLElement>('table tbody tr');
|
||||
|
||||
expect(tableRows.length).toBe(7);
|
||||
});
|
||||
});
|
||||
|
||||
it('Checks filters are working', async () => {
|
||||
const { getByText, queryByText, getByPlaceholderText } = render(
|
||||
<CompaniesDefault />,
|
||||
);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Airbnb')).toBeDefined();
|
||||
});
|
||||
|
||||
const filterDropdown = getByText('Filter');
|
||||
fireEvent.click(filterDropdown);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('Url')).toBeDefined();
|
||||
});
|
||||
|
||||
const urlFilter = getByText('Url');
|
||||
fireEvent.click(urlFilter);
|
||||
|
||||
const filterSearch = getByPlaceholderText('Url');
|
||||
fireEvent.change(filterSearch, { target: { value: 'aircal' } });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(getByText('aircall.io')).toBeDefined();
|
||||
const airbnbResult = queryByText('Airbnb');
|
||||
expect(airbnbResult).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
@ -1,19 +0,0 @@
|
||||
import { MemoryRouter } from 'react-router-dom';
|
||||
import Opportunities from '../Opportunities';
|
||||
import { ThemeProvider } from '@emotion/react';
|
||||
import { lightTheme } from '../../../layout/styles/themes';
|
||||
|
||||
const component = {
|
||||
title: 'Opportunities',
|
||||
component: Opportunities,
|
||||
};
|
||||
|
||||
export default component;
|
||||
|
||||
export const OpportunitiesDefault = () => (
|
||||
<ThemeProvider theme={lightTheme}>
|
||||
<MemoryRouter>
|
||||
<Opportunities />
|
||||
</MemoryRouter>
|
||||
</ThemeProvider>
|
||||
);
|
||||
@ -1,10 +0,0 @@
|
||||
import { render } from '@testing-library/react';
|
||||
|
||||
import { OpportunitiesDefault } from '../__stories__/Opportunities.stories';
|
||||
|
||||
it('Checks the Companies page render', () => {
|
||||
const { getByTestId } = render(<OpportunitiesDefault />);
|
||||
|
||||
const title = getByTestId('top-bar-title');
|
||||
expect(title).toHaveTextContent('Opportunities');
|
||||
});
|
||||
11
front/src/pages/people/__stories__/People.mdx
Normal file
11
front/src/pages/people/__stories__/People.mdx
Normal 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} />
|
||||
@ -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,
|
||||
},
|
||||
};
|
||||
|
||||
@ -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);
|
||||
});
|
||||
});
|
||||
16
front/src/testing/FullHeightStorybookLayout.tsx
Normal file
16
front/src/testing/FullHeightStorybookLayout.tsx
Normal file
@ -0,0 +1,16 @@
|
||||
import styled from '@emotion/styled';
|
||||
|
||||
const StyledLayout = styled.div`
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
width: calc(100vw - 32px);
|
||||
height: calc(100vh - 32px);
|
||||
`;
|
||||
|
||||
type OwnProps = {
|
||||
children: JSX.Element;
|
||||
};
|
||||
|
||||
export function FullHeightStorybookLayout({ children }: OwnProps) {
|
||||
return <StyledLayout>{children}</StyledLayout>;
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
import { GraphqlQueryCompany } from '../../../../interfaces/entities/company.interface';
|
||||
import { GraphqlQueryCompany } from '../../interfaces/entities/company.interface';
|
||||
|
||||
export const mockCompaniesData: Array<GraphqlQueryCompany> = [
|
||||
{
|
||||
@ -43,8 +43,8 @@ export const mockCompaniesData: Array<GraphqlQueryCompany> = [
|
||||
},
|
||||
{
|
||||
id: '5c21e19e-e049-4393-8c09-3e3f8fb09ecb',
|
||||
domain_name: 'bereal.com',
|
||||
name: 'BeReal',
|
||||
domain_name: 'qonto.com',
|
||||
name: 'Qonto',
|
||||
created_at: '2023-04-26T10:13:29.712485+00:00',
|
||||
address: '10 rue de la Paix',
|
||||
employees: 1,
|
||||
@ -53,8 +53,18 @@ export const mockCompaniesData: Array<GraphqlQueryCompany> = [
|
||||
},
|
||||
{
|
||||
id: '9d162de6-cfbf-4156-a790-e39854dcd4eb',
|
||||
domain_name: 'claap.com',
|
||||
name: 'Claap',
|
||||
domain_name: 'facebook.com',
|
||||
name: 'Facebook',
|
||||
created_at: '2023-04-26T10:09:25.656555+00:00',
|
||||
address: '',
|
||||
employees: 1,
|
||||
account_owner: null,
|
||||
__typename: 'companies',
|
||||
},
|
||||
{
|
||||
id: '9d162de6-cfbf-4156-a790-e39854dcd4eb',
|
||||
domain_name: 'sequoia.com',
|
||||
name: 'Sequoia',
|
||||
created_at: '2023-04-26T10:09:25.656555+00:00',
|
||||
address: '',
|
||||
employees: 1,
|
||||
98
front/src/testing/mock-data/index.ts
Normal file
98
front/src/testing/mock-data/index.ts
Normal file
@ -0,0 +1,98 @@
|
||||
import {
|
||||
CompanyOrderByWithRelationInput,
|
||||
PersonOrderByWithRelationInput,
|
||||
StringFilter,
|
||||
} from '../../generated/graphql';
|
||||
import { Company } from '../../interfaces/entities/company.interface';
|
||||
import { BoolExpType } from '../../interfaces/entities/generic.interface';
|
||||
import { Person } from '../../interfaces/entities/person.interface';
|
||||
|
||||
function filterData<DataT>(
|
||||
data: Array<DataT>,
|
||||
where: BoolExpType<Company> | BoolExpType<Person>,
|
||||
): Array<DataT> {
|
||||
return data.filter((item) => {
|
||||
// { firstname: {contains: '%string%' }}
|
||||
// { firstname: {equals: 'string' }}
|
||||
// { is: { company: { equals: 'string' }}}
|
||||
let isMatch: boolean = (
|
||||
Object.keys(where) as Array<keyof typeof where>
|
||||
).every((key) => {
|
||||
if (!['OR', 'AND', 'NOT'].includes(key)) {
|
||||
const filterElement = where[key] as StringFilter & { is?: object };
|
||||
|
||||
if (filterElement.is) {
|
||||
const nestedKey = Object.keys(filterElement.is)[0] as string;
|
||||
if (typeof item[key as keyof typeof item] === 'object') {
|
||||
const nestedItem = item[key as keyof typeof item];
|
||||
return (
|
||||
nestedItem[nestedKey as keyof typeof nestedItem] ===
|
||||
(
|
||||
filterElement.is[
|
||||
nestedKey as keyof typeof filterElement.is
|
||||
] as StringFilter
|
||||
).equals
|
||||
);
|
||||
}
|
||||
}
|
||||
if (filterElement.equals) {
|
||||
return item[key as keyof typeof item] === filterElement.equals;
|
||||
}
|
||||
if (filterElement.contains) {
|
||||
return (item[key as keyof typeof item] as string)
|
||||
.toLocaleLowerCase()
|
||||
.includes(
|
||||
filterElement.contains.replaceAll('%', '').toLocaleLowerCase(),
|
||||
);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
});
|
||||
|
||||
// { OR: [{ firstname: filter }, { lastname: filter }]
|
||||
if (where.OR && Array.isArray(where.OR)) {
|
||||
isMatch =
|
||||
isMatch ||
|
||||
where.OR.some((orFilter) =>
|
||||
filterData<DataT>(data, orFilter).includes(item),
|
||||
);
|
||||
}
|
||||
|
||||
return isMatch;
|
||||
});
|
||||
}
|
||||
|
||||
export function filterAndSortData<DataT>(
|
||||
data: Array<DataT>,
|
||||
where: BoolExpType<Company> | BoolExpType<Person>,
|
||||
orderBy: Array<
|
||||
PersonOrderByWithRelationInput & CompanyOrderByWithRelationInput
|
||||
>,
|
||||
limit: number,
|
||||
): Array<DataT> {
|
||||
let filteredData = filterData<DataT>(data, where);
|
||||
|
||||
if (orderBy) {
|
||||
const firstOrderBy = orderBy[0];
|
||||
|
||||
const key = Object.keys(firstOrderBy)[0];
|
||||
|
||||
filteredData.sort((itemA, itemB) => {
|
||||
const itemAValue = itemA[key as unknown as keyof typeof itemA];
|
||||
const itemBValue = itemB[key as unknown as keyof typeof itemB];
|
||||
if (!itemAValue || !itemBValue) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (typeof itemAValue === 'string' && typeof itemBValue === 'string') {
|
||||
return itemBValue.localeCompare(itemAValue);
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
}
|
||||
|
||||
if (limit) {
|
||||
filteredData = filteredData.slice(0, limit);
|
||||
}
|
||||
return filteredData;
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { GraphqlQueryPerson } from '../../../../interfaces/entities/person.interface';
|
||||
import { GraphqlQueryPerson } from '../../interfaces/entities/person.interface';
|
||||
|
||||
export const mockPeopleData: Array<GraphqlQueryPerson> = [
|
||||
export const mockedPeopleData: Array<GraphqlQueryPerson> = [
|
||||
{
|
||||
id: '7dfbc3f7-6e5e-4128-957e-8d86808cdf6b',
|
||||
__typename: 'Person',
|
||||
Reference in New Issue
Block a user