Skip to content

Commit 81a8b22

Browse files
committed
test: add tests
1 parent a9cfa6b commit 81a8b22

4 files changed

Lines changed: 136 additions & 32 deletions

File tree

src/library-authoring/components/ComponentRemover.tsx

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -43,31 +43,38 @@ const ComponentRemover = ({ usageKey, index, close }: Props) => {
4343
return null;
4444
}
4545

46-
const removeFromContainer = () => {
46+
const restoreComponent = () => {
4747
if (!childrenUsageIds) {
4848
return;
4949
}
50-
const restoreComponent = () => {
51-
updateContainerChildrenMutation.mutateAsync(childrenUsageIds).then(() => {
52-
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastSuccess));
53-
}).catch(() => {
54-
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastFailed));
55-
});
56-
};
50+
updateContainerChildrenMutation.mutateAsync(childrenUsageIds).then(() => {
51+
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastSuccess));
52+
}).catch(() => {
53+
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastFailed));
54+
});
55+
};
56+
57+
const showSuccessToast = () => {
58+
showToast(
59+
intl.formatMessage(messages.removeComponentFromContainerSuccess),
60+
{
61+
label: intl.formatMessage(messages.undoRemoveComponentFromContainerToastAction),
62+
onClick: restoreComponent,
63+
},
64+
);
65+
};
66+
67+
const showFailureToast = () => showToast(intl.formatMessage(messages.removeComponentFromContainerFailure));
68+
69+
const removeFromContainer = () => {
5770
removeContainerItemMutation.mutateAsync([usageKey]).then(() => {
5871
if (sidebarItemInfo?.id === usageKey) {
5972
// Close sidebar if current component is open
6073
closeLibrarySidebar();
6174
}
62-
showToast(
63-
intl.formatMessage(messages.removeComponentFromContainerSuccess),
64-
{
65-
label: intl.formatMessage(messages.undoRemoveComponentFromContainerToastAction),
66-
onClick: restoreComponent,
67-
},
68-
);
75+
showSuccessToast();
6976
}).catch(() => {
70-
showToast(intl.formatMessage(messages.removeComponentFromContainerFailure));
77+
showFailureToast();
7178
});
7279

7380
close();
@@ -78,27 +85,18 @@ const ComponentRemover = ({ usageKey, index, close }: Props) => {
7885
return;
7986
}
8087
const updatedKeys = childrenUsageIds.filter((childId, idx) => childId !== usageKey || idx !== index);
81-
const restoreComponent = () => {
82-
updateContainerChildrenMutation.mutateAsync(childrenUsageIds).then(() => {
83-
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastSuccess));
84-
}).catch(() => {
85-
showToast(intl.formatMessage(messages.undoRemoveComponentFromContainerToastFailed));
86-
});
87-
};
8888
updateContainerChildrenMutation.mutateAsync(updatedKeys).then(() => {
8989
if (sidebarItemInfo?.id === usageKey && sidebarItemInfo?.index === index) {
9090
// Close sidebar if current component is open
9191
closeLibrarySidebar();
9292
}
93-
showToast(
94-
intl.formatMessage(messages.removeComponentFromContainerSuccess),
95-
{
96-
label: intl.formatMessage(messages.undoRemoveComponentFromContainerToastAction),
97-
onClick: restoreComponent,
98-
},
99-
);
93+
// Already tested as part of removeFromContainer
94+
// istanbul ignore next
95+
showSuccessToast();
10096
}).catch(() => {
101-
showToast(intl.formatMessage(messages.removeComponentFromContainerFailure));
97+
// Already tested as part of removeFromContainer
98+
// istanbul ignore next
99+
showFailureToast();
102100
});
103101

104102
close();
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
import userEvent from '@testing-library/user-event';
2+
import type MockAdapter from 'axios-mock-adapter';
3+
import { QueryClient } from '@tanstack/react-query';
4+
5+
import { act } from 'react';
6+
import {
7+
initializeMocks,
8+
fireEvent,
9+
render,
10+
screen,
11+
waitFor,
12+
} from '../../testUtils';
13+
import {
14+
getLibraryContainerApiUrl,
15+
getLibraryContainerChildrenApiUrl,
16+
getLibraryContainersApiUrl,
17+
} from '../data/api';
18+
import {
19+
mockContentLibrary,
20+
mockXBlockFields,
21+
mockGetContainerMetadata,
22+
mockGetContainerChildren,
23+
mockLibraryBlockMetadata,
24+
} from '../data/api.mocks';
25+
import { mockContentSearchConfig, mockGetBlockTypes, mockSearchResult } from '../../search-manager/data/api.mock';
26+
import { mockClipboardEmpty } from '../../generic/data/api.mock';
27+
import LibraryLayout from '../LibraryLayout';
28+
import { ToastActionData, ToastProvider } from '../../generic/toast-context';
29+
import mockResult from '../__mocks__/subsection-single.json';
30+
import { ContainerType } from '../../generic/key-utils';
31+
import ContainerRemover from './ContainerRemover';
32+
import { LibraryProvider } from '../common/context/LibraryContext';
33+
34+
const path = '/library/:libraryId/*';
35+
const libraryTitle = mockContentLibrary.libraryData.title;
36+
37+
let axiosMock: MockAdapter;
38+
let queryClient: QueryClient;
39+
let mockShowToast: (message: string, action?: ToastActionData | undefined) => void;
40+
41+
mockClipboardEmpty.applyMock();
42+
mockGetContainerMetadata.applyMock();
43+
mockGetContainerChildren.applyMock();
44+
mockContentSearchConfig.applyMock();
45+
mockGetBlockTypes.applyMock();
46+
mockContentLibrary.applyMock();
47+
mockXBlockFields.applyMock();
48+
mockLibraryBlockMetadata.applyMock();
49+
50+
const mockClose = jest.fn();
51+
52+
const { libraryId } = mockContentLibrary;
53+
const renderModal = (element: React.ReactNode) => {
54+
render(
55+
<ToastProvider>
56+
<LibraryProvider libraryId={libraryId}>
57+
{element}
58+
</LibraryProvider>
59+
</ToastProvider>,
60+
)
61+
}
62+
63+
jest.mock('react-router-dom', () => ({
64+
...jest.requireActual('react-router-dom'),
65+
useParams: jest.fn().mockImplementation(() => ({
66+
containerId: mockGetContainerChildren.unitIdWithDuplicate,
67+
})),
68+
}));
69+
70+
describe('<ContainerRemover />', () => {
71+
beforeEach(() => {
72+
({ axiosMock, mockShowToast, queryClient } = initializeMocks());
73+
});
74+
75+
afterEach(() => {
76+
jest.clearAllMocks();
77+
axiosMock.restore();
78+
});
79+
80+
it('triggers update container children api call when duplicates are present', async () => {
81+
const user = userEvent.setup();
82+
const url = getLibraryContainerChildrenApiUrl(mockGetContainerChildren.unitIdWithDuplicate);
83+
axiosMock.onPatch(url).reply(200);
84+
const result = await mockGetContainerChildren(mockGetContainerChildren.unitIdWithDuplicate);
85+
const resultIds = result.map((obj) => obj.id);
86+
renderModal(<ContainerRemover
87+
close={mockClose}
88+
containerKey={result[0].id}
89+
displayName="Title"
90+
index={0}
91+
/>)
92+
const btn = await screen.findByRole('button', { name: 'Remove' });
93+
await user.click(btn);
94+
95+
await waitFor(() => {
96+
expect(axiosMock.history.patch[0].url).toEqual(url);
97+
// Only the first element is removed even though the last element has the same id.
98+
expect(JSON.parse(axiosMock.history.patch[0].data).usage_keys).toEqual(resultIds.slice(1));
99+
});
100+
expect(mockClose).toHaveBeenCalled();
101+
});
102+
});

src/library-authoring/containers/ContainerRemover.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,16 @@ const ContainerRemover = ({
8181
}, [
8282
containerKey,
8383
removeContainerMutation,
84+
updateContainerChildrenMutation,
8485
sidebarItemInfo,
8586
closeLibrarySidebar,
8687
showToast,
8788
removeSuccess,
8889
removeError,
8990
close,
91+
hasDuplicates,
92+
childrenUsageIds,
93+
index,
9094
]);
9195

9296
// istanbul ignore if: loading state

src/library-authoring/units/LibraryUnitPage.test.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ describe('<LibraryUnitPage />', () => {
390390
expect(mockShowToast).toHaveBeenCalledWith('Undo successful');
391391
});
392392

393-
it('should remove only one instance of component even if it is present multiple times in library', async () => {
393+
it('should remove only one instance of component even if it is present multiple times in this page', async () => {
394394
const user = userEvent.setup();
395395
const url = getLibraryContainerChildrenApiUrl(mockGetContainerChildren.unitIdWithDuplicate);
396396
axiosMock.onPatch(url).reply(200);

0 commit comments

Comments
 (0)