Skip to content

Commit 2f62256

Browse files
committed
test: Simplify app content library tests
1 parent a5839e1 commit 2f62256

File tree

2 files changed

+89
-119
lines changed

2 files changed

+89
-119
lines changed

frontend/app-development/features/appContentLibrary/AppContentLibrary.test.tsx

+88-119
Original file line numberDiff line numberDiff line change
@@ -7,69 +7,48 @@ import { createQueryClientMock } from 'app-shared/mocks/queryClientMock';
77
import { QueryKey } from 'app-shared/types/QueryKey';
88
import { app, org } from '@studio/testing/testids';
99
import { queriesMock } from 'app-shared/mocks/queriesMock';
10-
import type { UserEvent } from '@testing-library/user-event';
11-
import userEvent from '@testing-library/user-event';
1210
import type { CodeList } from '@studio/components';
1311
import type { ServicesContextProps } from 'app-shared/contexts/ServicesContext';
1412
import type { OptionListData } from 'app-shared/types/OptionList';
1513
import type { QueryClient } from '@tanstack/react-query';
14+
import type {
15+
CodeListData,
16+
CodeListWithMetadata,
17+
PagesConfig,
18+
ResourceContentLibraryImpl,
19+
} from '@studio/content-library';
20+
21+
// Mocks:
22+
jest.mock('@studio/content-library', () => ({
23+
...jest.requireActual('@studio/content-library'),
24+
ResourceContentLibraryImpl: mockContentLibrary,
25+
}));
26+
27+
function mockContentLibrary(
28+
...args: ConstructorParameters<typeof ResourceContentLibraryImpl>
29+
): Partial<ResourceContentLibraryImpl> {
30+
constructor(...args);
31+
return { getContentResourceLibrary };
32+
}
33+
34+
const constructor = jest.fn();
35+
const getContentResourceLibrary = jest.fn();
1636

17-
const uploadCodeListButtonTextMock = 'Upload Code List';
18-
const updateCodeListButtonTextMock = 'Update Code List';
19-
const updateCodeListIdButtonTextMock = 'Update Code List Id';
20-
const deleteCodeListButtonTextMock = 'Delete Code List';
21-
const codeListNameMock = 'codeListNameMock';
22-
const newCodeListNameMock = 'newCodeListNameMock';
23-
const codeListMock: CodeList = [{ value: '', label: '' }];
24-
const optionListsDataMock: OptionListData[] = [{ title: codeListNameMock, data: codeListMock }];
25-
jest.mock(
26-
'../../../libs/studio-content-library/src/ContentLibrary/LibraryBody/pages/CodeListPage',
27-
() => ({
28-
CodeListPage: ({
29-
onUpdateCodeList,
30-
onUploadCodeList,
31-
onUpdateCodeListId,
32-
onDeleteCodeList,
33-
}: any) => (
34-
<div>
35-
<button
36-
onClick={() =>
37-
onUploadCodeList(
38-
new File(['test'], `${codeListNameMock}.json`, { type: 'application/json' }),
39-
)
40-
}
41-
>
42-
{uploadCodeListButtonTextMock}
43-
</button>
44-
<button
45-
onClick={() => onUpdateCodeList({ title: codeListNameMock, codeList: codeListMock })}
46-
>
47-
{updateCodeListButtonTextMock}
48-
</button>
49-
<button onClick={() => onUpdateCodeListId(codeListNameMock, newCodeListNameMock)}>
50-
{updateCodeListIdButtonTextMock}
51-
</button>
52-
<button onClick={() => onDeleteCodeList(optionListsDataMock[0].title)}>
53-
{deleteCodeListButtonTextMock}
54-
</button>
55-
</div>
56-
),
57-
}),
58-
);
37+
// Test data:
38+
const codeListName = 'codeListNameMock';
39+
const codeList: CodeList = [{ value: '', label: '' }];
40+
const codeListWithMetadata: CodeListWithMetadata = {
41+
codeList,
42+
title: codeListName,
43+
};
44+
const optionListData: OptionListData = { title: codeListName, data: codeList };
5945

6046
describe('AppContentLibrary', () => {
6147
afterEach(jest.clearAllMocks);
6248

63-
it('renders the AppContentLibrary with codeLists and images resources available in the content menu', () => {
49+
it('Renders the content library', async () => {
6450
renderAppContentLibraryWithOptionLists();
65-
const libraryTitle = screen.getByRole('heading', {
66-
name: textMock('app_content_library.landing_page.title'),
67-
});
68-
const codeListMenuElement = getLibraryPageTile('code_lists');
69-
const imagesMenuElement = getLibraryPageTile('images');
70-
expect(libraryTitle).toBeInTheDocument();
71-
expect(codeListMenuElement).toBeInTheDocument();
72-
expect(imagesMenuElement).toBeInTheDocument();
51+
expect(getContentResourceLibrary).toHaveBeenCalledTimes(1);
7352
});
7453

7554
it('renders a spinner when waiting for option lists', () => {
@@ -86,96 +65,82 @@ describe('AppContentLibrary', () => {
8665
expect(errorMessage).toBeInTheDocument();
8766
});
8867

89-
it('calls onUploadOptionList when onUploadCodeList is triggered', async () => {
90-
const user = userEvent.setup();
68+
it('Renders with the given code lists', () => {
9169
renderAppContentLibraryWithOptionLists();
92-
await goToLibraryPage(user, 'code_lists');
93-
const uploadCodeListButton = screen.getByRole('button', { name: uploadCodeListButtonTextMock });
94-
await user.click(uploadCodeListButton);
95-
expect(queriesMock.uploadOptionList).toHaveBeenCalledTimes(1);
96-
expect(queriesMock.uploadOptionList).toHaveBeenCalledWith(org, app, expect.any(FormData));
70+
const codeListDataList = retrieveConfig().codeList.props.codeListsData;
71+
const expectedData: CodeListData[] = [{ title: codeListName, data: codeList }];
72+
expect(codeListDataList).toEqual(expectedData);
73+
});
74+
75+
it('calls uploadOptionList with correct data when onUploadCodeList is triggered', async () => {
76+
const uploadOptionList = jest.fn();
77+
const file = new File([''], 'list.json');
78+
renderAppContentLibraryWithOptionLists({ queries: { uploadOptionList } });
79+
80+
retrieveConfig().codeList.props.onUploadCodeList(file);
81+
await waitFor(expect(uploadOptionList).toHaveBeenCalled);
82+
83+
expect(uploadOptionList).toHaveBeenCalledTimes(1);
84+
expect(uploadOptionList).toHaveBeenCalledWith(org, app, expect.any(FormData));
85+
const formData: FormData = uploadOptionList.mock.calls[0][2];
86+
expect(formData.get('file')).toBe(file);
9787
});
9888

9989
it('renders success toast when onUploadOptionList is called successfully', async () => {
100-
const user = userEvent.setup();
10190
renderAppContentLibraryWithOptionLists();
102-
await goToLibraryPage(user, 'code_lists');
103-
const uploadCodeListButton = screen.getByRole('button', { name: uploadCodeListButtonTextMock });
104-
await user.click(uploadCodeListButton);
105-
const successToastMessage = screen.getByText(
106-
textMock('ux_editor.modal_properties_code_list_upload_success'),
107-
);
108-
expect(successToastMessage).toBeInTheDocument();
91+
const file = new File([''], 'list.json');
92+
93+
retrieveConfig().codeList.props.onUploadCodeList(file);
94+
await waitFor(expect(queriesMock.uploadOptionList).toHaveBeenCalled);
95+
96+
const successMessage = textMock('ux_editor.modal_properties_code_list_upload_success');
97+
expect(screen.getByText(successMessage)).toBeInTheDocument();
10998
});
11099

111100
it('renders error toast when onUploadOptionList is rejected with unknown error code', async () => {
112-
const user = userEvent.setup();
113101
const uploadOptionList = jest.fn().mockImplementation(() => Promise.reject({ response: {} }));
102+
const file = new File([''], 'list.json');
114103
renderAppContentLibraryWithOptionLists({ queries: { uploadOptionList } });
115-
await goToLibraryPage(user, 'code_lists');
116-
const uploadCodeListButton = screen.getByRole('button', { name: uploadCodeListButtonTextMock });
117-
await user.click(uploadCodeListButton);
118-
const errorToastMessage = screen.getByText(
119-
textMock('ux_editor.modal_properties_code_list_upload_generic_error'),
120-
);
121-
expect(errorToastMessage).toBeInTheDocument();
104+
105+
retrieveConfig().codeList.props.onUploadCodeList(file);
106+
await waitFor(expect(uploadOptionList).toHaveBeenCalled);
107+
108+
const errorMessage = textMock('ux_editor.modal_properties_code_list_upload_generic_error');
109+
expect(screen.getByText(errorMessage)).toBeInTheDocument();
122110
});
123111

124-
it('calls onUpdateOptionList when onUpdateCodeList is triggered', async () => {
125-
const user = userEvent.setup();
112+
it('calls updateOptionList with correct data when onUpdateCodeList is triggered', async () => {
126113
renderAppContentLibraryWithOptionLists();
127-
await goToLibraryPage(user, 'code_lists');
128-
const updateCodeListButton = screen.getByRole('button', { name: updateCodeListButtonTextMock });
129-
await user.click(updateCodeListButton);
114+
115+
retrieveConfig().codeList.props.onUpdateCodeList(codeListWithMetadata);
116+
await waitFor(expect(queriesMock.updateOptionList).toHaveBeenCalled);
117+
130118
expect(queriesMock.updateOptionList).toHaveBeenCalledTimes(1);
131-
expect(queriesMock.updateOptionList).toHaveBeenCalledWith(
132-
org,
133-
app,
134-
codeListNameMock,
135-
codeListMock,
136-
);
119+
expect(queriesMock.updateOptionList).toHaveBeenCalledWith(org, app, codeListName, codeList);
137120
});
138121

139-
it('calls onUpdateOptionListId when onUpdateCodeListId is triggered', async () => {
140-
const user = userEvent.setup();
122+
it('calls updateOptionListId with correct data when onUpdateCodeListId is triggered', async () => {
123+
const newName = 'newName';
141124
renderAppContentLibraryWithOptionLists();
142-
await goToLibraryPage(user, 'code_lists');
143-
const updateCodeListIdButton = screen.getByRole('button', {
144-
name: updateCodeListIdButtonTextMock,
145-
});
146-
await user.click(updateCodeListIdButton);
125+
126+
retrieveConfig().codeList.props.onUpdateCodeListId(codeListName, newName);
127+
await waitFor(expect(queriesMock.updateOptionListId).toHaveBeenCalled);
128+
147129
expect(queriesMock.updateOptionListId).toHaveBeenCalledTimes(1);
148-
expect(queriesMock.updateOptionListId).toHaveBeenCalledWith(
149-
org,
150-
app,
151-
codeListNameMock,
152-
newCodeListNameMock,
153-
);
130+
expect(queriesMock.updateOptionListId).toHaveBeenCalledWith(org, app, codeListName, newName);
154131
});
155132

156-
it('calls deleteOptionList when onDeleteCodeList is triggered', async () => {
157-
const user = userEvent.setup();
133+
it('calls deleteOptionList with correct data when onDeleteCodeList is triggered', async () => {
158134
renderAppContentLibraryWithOptionLists();
159-
await goToLibraryPage(user, 'code_lists');
160-
const deleteCodeListButton = screen.getByRole('button', { name: deleteCodeListButtonTextMock });
161-
await user.click(deleteCodeListButton);
135+
136+
retrieveConfig().codeList.props.onDeleteCodeList(codeListName);
137+
await waitFor(expect(queriesMock.deleteOptionList).toHaveBeenCalled);
138+
162139
expect(queriesMock.deleteOptionList).toHaveBeenCalledTimes(1);
163-
expect(queriesMock.deleteOptionList).toHaveBeenCalledWith(
164-
org,
165-
app,
166-
optionListsDataMock[0].title,
167-
);
140+
expect(queriesMock.deleteOptionList).toHaveBeenCalledWith(org, app, codeListName);
168141
});
169142
});
170143

171-
const getLibraryPageTile = (libraryPage: string) =>
172-
screen.getByText(textMock(`app_content_library.${libraryPage}.page_name`));
173-
174-
const goToLibraryPage = async (user: UserEvent, libraryPage: string) => {
175-
const libraryPageNavTile = getLibraryPageTile(libraryPage);
176-
await user.click(libraryPageNavTile);
177-
};
178-
179144
type RenderAppContentLibraryProps = {
180145
queries?: Partial<ServicesContextProps>;
181146
queryClient?: QueryClient;
@@ -191,7 +156,7 @@ const renderAppContentLibrary = ({
191156
function renderAppContentLibraryWithOptionLists(
192157
props?: Omit<RenderAppContentLibraryProps, 'queryClient'>,
193158
): void {
194-
const queryClient = createQueryClientWithOptionsDataList(optionListsDataMock);
159+
const queryClient = createQueryClientWithOptionsDataList([optionListData]);
195160
renderAppContentLibrary({ ...props, queryClient });
196161
}
197162

@@ -203,3 +168,7 @@ function createQueryClientWithOptionsDataList(
203168
queryClient.setQueryData([QueryKey.OptionListsUsage, org, app], []);
204169
return queryClient;
205170
}
171+
172+
function retrieveConfig(): PagesConfig {
173+
return constructor.mock.calls[0][0].pages;
174+
}

frontend/libs/studio-content-library/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,4 @@ export type {
55
CodeListIdSource,
66
CodeListReference,
77
} from './ContentLibrary/LibraryBody/pages';
8+
export type { PagesConfig } from './types/PagesProps';

0 commit comments

Comments
 (0)