Skip to content

Commit

Permalink
test(@leav/ui): add tests on explorer
Browse files Browse the repository at this point in the history
  • Loading branch information
TdyP committed Nov 19, 2024
1 parent 31a99b6 commit 3d13092
Show file tree
Hide file tree
Showing 6 changed files with 257 additions and 6 deletions.
3 changes: 2 additions & 1 deletion libs/ui/src/_gqlTypes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1356,7 +1356,7 @@ export type ExplorerLibraryDataQueryVariables = Exact<{
}>;


export type ExplorerLibraryDataQuery = { libraries?: { list: Array<{ label?: any | null }> } | null };
export type ExplorerLibraryDataQuery = { libraries?: { list: Array<{ id: string, label?: any | null }> } | null };

export const RecordIdentityFragmentDoc = gql`
fragment RecordIdentity on Record {
Expand Down Expand Up @@ -4013,6 +4013,7 @@ export const ExplorerLibraryDataDocument = gql`
query ExplorerLibraryData($libraryId: ID!) {
libraries(filters: {id: [$libraryId]}) {
list {
id
label
}
}
Expand Down
4 changes: 2 additions & 2 deletions libs/ui/src/components/Explorer/DataView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ export const DataView: FunctionComponent<IDataViewProps> = ({

return isLessThanFourActions ? (
<KitSpace>
{actions.map(({label, icon, isDanger, callback}) => (
<KitButton title={label} icon={icon} onClick={callback} danger={isDanger}>
{actions.map(({label, icon, isDanger, callback}, index) => (
<KitButton title={label} icon={icon} onClick={callback} danger={isDanger} key={index}>
{label}
</KitButton>
))}
Expand Down
249 changes: 249 additions & 0 deletions libs/ui/src/components/Explorer/Explorer.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
// Copyright LEAV Solutions 2017 until 2023/11/05, Copyright Aristid from 2023/11/06
// This file is released under LGPL V3
// License text available at https://www.gnu.org/licenses/lgpl-3.0.txt
import {render, screen, within} from '_ui/_tests/testUtils';
import {Explorer} from '_ui/index';
import * as gqlTypes from '_ui/_gqlTypes';
import {Mockify} from '@leav/utils';
import userEvent from '@testing-library/user-event';
import {Fa500Px, FaAccessibleIcon, FaBeer, FaJs, FaXbox} from 'react-icons/fa';
import {mockRecord} from '_ui/__mocks__/common/record';
import {IItemAction} from './_types';

jest.mock('_ui/components/RecordEdition/EditRecordModal', () => ({
EditRecordModal: () => <div>EditRecordModal</div>
}));

describe('Explorer', () => {
const mockExplorerQueryResult: Mockify<typeof gqlTypes.useExplorerQuery> = {
loading: false,
called: true,
data: {
records: {
list: [
{
id: '613982168',
whoAmI: {
id: '613982168',
label: 'Halloween 2025',
subLabel: 'Du mercredi 6 novembre 2024 au lundi 9 décembre 2024',
color: null,
library: {
id: 'campaigns',
label: {
en: 'Campaigns',
fr: 'Campagnes'
}
},
preview: null
},
properties: [
{
attributeId: 'id',
values: [
{
attribute: {
type: 'simple'
},
valuePayload: '613982168'
}
]
}
]
},
{
id: '612694174',
whoAmI: {
id: '612694174',
label: 'Foire aux vins 2024 - semaine 1',
subLabel: 'Du mercredi 30 octobre 2024 au lundi 25 novembre 2024',
color: null,
library: {
id: 'campaigns',
label: {
en: 'Campaigns',
fr: 'Campagnes'
}
},
preview: null
},
properties: [
{
attributeId: 'id',
values: [
{
attribute: {
type: 'simple'
},
valuePayload: '612694174'
}
]
}
]
}
]
}
}
};

const mockLibraryDataQueryResult: Mockify<typeof gqlTypes.useExplorerLibraryDataQuery> = {
loading: false,
called: true,
data: {
libraries: {
list: [
{
id: 'campaigns',
label: {
en: 'Campaigns',
fr: 'Campagnes'
}
}
]
}
}
};

beforeAll(() => {
jest.spyOn(gqlTypes, 'useExplorerQuery').mockImplementation(
() => mockExplorerQueryResult as gqlTypes.ExplorerQueryResult
);

jest.spyOn(gqlTypes, 'useExplorerLibraryDataQuery').mockImplementation(
() => mockLibraryDataQueryResult as gqlTypes.ExplorerLibraryDataQueryResult
);
});

let user;
beforeEach(() => {
user = userEvent.setup();
});

test('Should display library label as title', () => {
render(<Explorer library="campaigns" />);

expect(screen.getByText('Campagnes')).toBeInTheDocument();
});

test('Should display custom title', () => {
render(<Explorer library="campaigns" title="Here's my explorer!" />);

expect(screen.getByText("Here's my explorer!")).toBeInTheDocument();
});

test('Should display the list of records in a table', async () => {
render(<Explorer library="campaigns" />);

expect(screen.getByRole('table')).toBeVisible();
expect(screen.getAllByRole('row')).toHaveLength(3); // 1 header row + 2 records
expect(screen.getByText('Halloween 2025')).toBeInTheDocument();
expect(screen.getByText('Foire aux vins 2024 - semaine 1')).toBeInTheDocument();
});

test('Should be able to deactivate a record with default actions', async () => {
const mockDeactivateMutation = jest.fn().mockReturnValue({
data: {
deactivateRecords: [
{
id: 42,
whoAmI: mockRecord
}
]
}
});

jest.spyOn(gqlTypes, 'useDeactivateRecordsMutation').mockImplementation(() => [
mockDeactivateMutation,
{loading: false, called: false, client: {} as any, reset: jest.fn()}
]);

render(<Explorer library="campaigns" />);

const firstRecordRow = screen.getAllByRole('row')[1];
await user.click(within(firstRecordRow).getByRole('button', {name: /deactivate/}));

expect(await screen.findByText('records_deactivation.confirm_one')).toBeVisible();
await user.click(screen.getByText(/submit/));

expect(mockDeactivateMutation).toHaveBeenCalled();
});

test('Should be able to edit a record with default actions', async () => {
render(<Explorer library="campaigns" />);

const firstRecordRow = screen.getAllByRole('row')[1];
user.click(within(firstRecordRow).getByRole('button', {name: /edit-item/}));
expect(await screen.findByText('EditRecordModal')).toBeVisible();
});

test('Should display the list of records with custom actions', async () => {
const customActionCb = jest.fn();
const customActions: IItemAction[] = [
{
icon: <Fa500Px />,
label: 'Custom action',
callback: customActionCb
}
];
render(<Explorer library="campaigns" itemActions={customActions} />);

const firstRecordRow = screen.getAllByRole('row')[1];

await user.click(within(firstRecordRow).queryByRole('button', {name: /Custom action/}));

expect(customActionCb).toHaveBeenCalled();
});

test('Should display the list of records with a lot of custom actions', async () => {
const customActions: IItemAction[] = [
{
label: 'Test 1',
icon: <FaBeer />,
callback: jest.fn()
},
{
label: 'Test 2',
icon: <FaAccessibleIcon />,
callback: jest.fn()
},
{
label: 'Test 3',
icon: <FaXbox />,
callback: jest.fn()
},
{
label: 'Test 4',
icon: <FaJs />,
callback: jest.fn()
}
];
render(<Explorer library="campaigns" itemActions={customActions} />);

const firstRecordRow = screen.getAllByRole('row')[1];
await user.hover(within(firstRecordRow).getByRole('button', {name: /more-actions/}));

expect(await screen.findByRole('menuitem', {name: /Test 1/})).toBeVisible();
expect(await screen.findByRole('menuitem', {name: /Test 2/})).toBeVisible();
expect(await screen.findByRole('menuitem', {name: /Test 3/})).toBeVisible();
expect(await screen.findByRole('menuitem', {name: /Test 4/})).toBeVisible();

await user.click(screen.getByRole('menuitem', {name: /Test 1/}));

expect(customActions[0].callback).toHaveBeenCalled();
});

test('Should display the list of records with no actions', () => {
render(<Explorer library="campaigns" defaultActionsForItem={[]} />);

const firstRecordRow = screen.getAllByRole('row')[1];
expect(within(firstRecordRow).queryByRole('button')).not.toBeInTheDocument();
});

test('Should be able to create a new record', async () => {
render(<Explorer library="campaigns" />);

user.click(screen.getByRole('button', {name: /create/}));

expect(await screen.findByText('EditRecordModal')).toBeVisible();
});
});
4 changes: 2 additions & 2 deletions libs/ui/src/components/Explorer/Explorer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {ExplorerTitle} from './ExplorerTitle';

interface IExplorerProps {
library: string;
itemActions: IItemAction[];
itemActions?: IItemAction[];
title?: string;
defaultActionsForItem?:
| []
Expand Down Expand Up @@ -81,7 +81,7 @@ export const Explorer: FunctionComponent<IExplorerProps> = ({
<DataView
dataGroupedFilteredSorted={data ?? []}
attributesToDisplay={[currentAttribute, 'whoAmI']}
itemActions={[editAction, deactivateAction, ...itemActions].filter(Boolean)}
itemActions={[editAction, deactivateAction, ...(itemActions ?? [])].filter(Boolean)}
/>
</>
)}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
query ExplorerLibraryData($libraryId: ID!) {
libraries(filters: {id: [$libraryId]} ) {
list {
id
label
}
}
Expand Down
2 changes: 1 addition & 1 deletion libs/ui/src/components/Explorer/useEditAction.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import {useState} from 'react';
import {FaPen} from 'react-icons/fa';
import {useSharedTranslation} from '_ui/hooks/useSharedTranslation';
import {EditRecordModal} from '_ui/components';
import {EditRecordModal} from '_ui/components/RecordEdition/EditRecordModal';
import {RecordFilterCondition, useExplorerLazyQuery} from '_ui/_gqlTypes';
import {ActionHook, IItemAction, IItemData} from './_types';

Expand Down

0 comments on commit 3d13092

Please sign in to comment.