@centreon/ui 26.12.1 → 26.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +6 -3
- package/public/mockServiceWorker.js +31 -8
- package/src/Dashboard/Dashboard.browser.test.tsx +107 -0
- package/src/Form/Form.browser.test.tsx +445 -0
- package/src/Form/Inputs/ExclusiveCheckboxGroup.browser.test.tsx +304 -0
- package/src/Form/Inputs/SegmentedButtons.browser.test.tsx +113 -0
- package/src/InputField/Number/Number.browser.test.tsx +109 -0
- package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.browser.test.tsx +250 -0
- package/src/Listing/Listing.browser.test.tsx +476 -0
- package/src/Module/Module.browser.test.tsx +145 -0
- package/src/Pagination/Pagination.browser.test.tsx +184 -0
- package/src/RichTextEditor/RichTextEditor.browser.test.tsx +567 -0
- package/src/RichTextEditor/plugins/FloatingLinkEditorPlugin.tsx +3 -1
- package/src/TimePeriods/ResolutionTimePeriod.browser.test.tsx +143 -0
- package/src/TimePeriods/TimePeriods.browser.test.tsx +468 -0
- package/src/Typography/FluidTypography/FluidTypography.browser.test.tsx +54 -0
- package/src/api/useMutationQuery/useMutationQuery.browser.test.tsx +154 -0
- package/src/components/CollapsibleItem/CollapsibleItem.browser.test.tsx +120 -0
- package/src/components/CopyCommand/CopyCommand.browser.test.tsx +287 -0
- package/src/components/CrudPage/CrudPage.browser.test.tsx +659 -0
- package/src/components/DataTable/DataTable.browser.test.tsx +257 -0
- package/src/components/Form/AccessRights/AccessRights.browser.test.tsx +527 -0
- package/src/components/ItemComposition/ItemComposition.browser.test.tsx +172 -0
- package/src/components/Layout/PageLayout.browser.test.tsx +114 -0
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.browser.test.tsx +237 -0
- package/src/components/SortableEntriesList/SortableEntriesList.browser.test.tsx +981 -0
- package/src/components/Tabs/Tabs.browser.test.tsx +115 -0
- package/src/utils/useFullscreen/Fullscreen.browser.test.tsx +176 -0
- package/src/utils/useLocale/useLocale.browser.test.tsx +49 -0
- package/src/utils/useLocaleTimezoneDate/{LocaleTimezoneDate.cypress.spec.tsx → LocaleTimezoneDate.browser.test.tsx} +24 -11
- package/src/Dashboard/Dashboard.cypress.spec.tsx +0 -71
- package/src/Form/Form.cypress.spec.tsx +0 -306
- package/src/Form/Inputs/ExclusiveCheckboxGroup.cypress.spec.tsx +0 -236
- package/src/Form/Inputs/SegmentedButtons.cypress.spec.tsx +0 -101
- package/src/InputField/Number/Number.cypress.spec.tsx +0 -89
- package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.cypress.spec.tsx +0 -182
- package/src/Listing/Listing.cypress.spec.tsx +0 -349
- package/src/Module/Module.cypress.spec.tsx +0 -127
- package/src/Pagination/Pagination.cypress.spec.tsx +0 -140
- package/src/RichTextEditor/RichTextEditor.cypress.spec.tsx +0 -408
- package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +0 -74
- package/src/TimePeriods/TimePeriods.cypress.spec.tsx +0 -488
- package/src/Typography/FluidTypography/FluidTypography.cypress.spec.tsx +0 -27
- package/src/api/useMutationQuery/useMutationQuery.cypress.spec.tsx +0 -93
- package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +0 -76
- package/src/components/CopyCommand/CopyCommand.cypress.spec.tsx +0 -167
- package/src/components/CrudPage/CrudPage.cypress.spec.tsx +0 -561
- package/src/components/DataTable/DataTable.cypress.spec.tsx +0 -174
- package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +0 -376
- package/src/components/ItemComposition/ItemComposition.cypress.spec.tsx +0 -112
- package/src/components/Layout/PageLayout.cypress.spec.tsx +0 -64
- package/src/components/Modal/ConfirmationModal/ConfirmationModal.cypress.spec.tsx +0 -171
- package/src/components/SortableEntriesList/SortableEntriesList.cypress.spec.tsx +0 -792
- package/src/components/Tabs/Tabs.cypress.spec.tsx +0 -69
- package/src/utils/useFullscreen/Fullscreen.cypress.spec.tsx +0 -130
- package/src/utils/useLocale/useLocale.cypress.spec.tsx +0 -40
|
@@ -0,0 +1,476 @@
|
|
|
1
|
+
import { Button, Typography } from '@mui/material';
|
|
2
|
+
|
|
3
|
+
import { ListingVariant } from '@centreon/ui-context';
|
|
4
|
+
|
|
5
|
+
import { rs } from '@rstest/core';
|
|
6
|
+
import { render } from '@test-setup/render';
|
|
7
|
+
import { screen, waitFor, within } from '@testing-library/react';
|
|
8
|
+
import userEvent from '@testing-library/user-event';
|
|
9
|
+
import { useState } from 'react';
|
|
10
|
+
|
|
11
|
+
import Listing from '.';
|
|
12
|
+
import {
|
|
13
|
+
type Column,
|
|
14
|
+
ColumnType,
|
|
15
|
+
type ComponentColumnProps,
|
|
16
|
+
type RowRecord
|
|
17
|
+
} from './models';
|
|
18
|
+
|
|
19
|
+
interface NamedRow {
|
|
20
|
+
name: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
const getName = (row: RowRecord): string => (row as unknown as NamedRow).name;
|
|
24
|
+
|
|
25
|
+
const ButtonColumn = ({ row }: ComponentColumnProps): JSX.Element => (
|
|
26
|
+
<Button size="small">Click to reveal details about {getName(row)}</Button>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
const CheckboxColumn = ({ row }: ComponentColumnProps): JSX.Element => {
|
|
30
|
+
const [checked, setChecked] = useState(false);
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<input
|
|
34
|
+
aria-label={`Toggle ${getName(row)}`}
|
|
35
|
+
checked={checked}
|
|
36
|
+
onChange={(event) => setChecked(event.target.checked)}
|
|
37
|
+
type="checkbox"
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const LargeText = (): JSX.Element => (
|
|
43
|
+
<Typography sx={{ whiteSpace: 'normal' }}>
|
|
44
|
+
This is a large text that fills the content
|
|
45
|
+
</Typography>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
interface Item {
|
|
49
|
+
active: boolean;
|
|
50
|
+
description: string;
|
|
51
|
+
disableCheckbox: boolean;
|
|
52
|
+
disableRow: boolean;
|
|
53
|
+
id: number;
|
|
54
|
+
name: string;
|
|
55
|
+
selected: boolean;
|
|
56
|
+
subItems?: Array<Item>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const tenElements = new Array(10).fill(0);
|
|
60
|
+
|
|
61
|
+
const generateSubItems = (): Array<Item> => {
|
|
62
|
+
return tenElements.map((_, subIndex) => ({
|
|
63
|
+
active: false,
|
|
64
|
+
description: `Sub item ${subIndex * 10} description`,
|
|
65
|
+
disableCheckbox: false,
|
|
66
|
+
disableRow: false,
|
|
67
|
+
id: subIndex * 10,
|
|
68
|
+
name: `Sub Item ${subIndex * 10}`,
|
|
69
|
+
selected: false
|
|
70
|
+
}));
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
const listingWithSubItems: Array<Item> = tenElements.map((_, index) => ({
|
|
74
|
+
active: false,
|
|
75
|
+
description: `Entity ${index}`,
|
|
76
|
+
disableCheckbox: false,
|
|
77
|
+
disableRow: false,
|
|
78
|
+
id: index,
|
|
79
|
+
name: `E${index}`,
|
|
80
|
+
selected: false,
|
|
81
|
+
subItems: index % 2 === 0 ? generateSubItems() : undefined
|
|
82
|
+
}));
|
|
83
|
+
|
|
84
|
+
const listingWithSubItems3Rows: Array<Item> = Array(3)
|
|
85
|
+
.fill(0)
|
|
86
|
+
.map((_, index) => ({
|
|
87
|
+
active: false,
|
|
88
|
+
description: `Entity ${index}`,
|
|
89
|
+
disableCheckbox: false,
|
|
90
|
+
disableRow: false,
|
|
91
|
+
id: index,
|
|
92
|
+
name: `E${index}`,
|
|
93
|
+
selected: false,
|
|
94
|
+
subItems: index % 2 === 0 ? generateSubItems() : undefined
|
|
95
|
+
}));
|
|
96
|
+
|
|
97
|
+
const defaultColumn: Array<Column> = [
|
|
98
|
+
{
|
|
99
|
+
getFormattedString: getName,
|
|
100
|
+
id: 'name',
|
|
101
|
+
label: 'Name',
|
|
102
|
+
type: ColumnType.string
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
getFormattedString: (row: RowRecord): string =>
|
|
106
|
+
(row as unknown as Item).description,
|
|
107
|
+
id: 'description',
|
|
108
|
+
label: 'Description',
|
|
109
|
+
type: ColumnType.string
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
Component: LargeText,
|
|
113
|
+
id: '#',
|
|
114
|
+
label: 'Custom',
|
|
115
|
+
type: ColumnType.component,
|
|
116
|
+
width: '100px'
|
|
117
|
+
}
|
|
118
|
+
];
|
|
119
|
+
|
|
120
|
+
const columnsWithSubItems: Array<Column> = [
|
|
121
|
+
{
|
|
122
|
+
getFormattedString: getName,
|
|
123
|
+
id: 'name',
|
|
124
|
+
label: 'Name',
|
|
125
|
+
type: ColumnType.string
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
getFormattedString: (row: RowRecord): string =>
|
|
129
|
+
(row as unknown as Item).description,
|
|
130
|
+
id: 'description',
|
|
131
|
+
label: 'Description',
|
|
132
|
+
type: ColumnType.string
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
Component: ButtonColumn,
|
|
136
|
+
displaySubItemsCaret: true,
|
|
137
|
+
id: '#',
|
|
138
|
+
label: 'Custom',
|
|
139
|
+
type: ColumnType.component,
|
|
140
|
+
width: '350px'
|
|
141
|
+
}
|
|
142
|
+
];
|
|
143
|
+
|
|
144
|
+
const expandedItems = [0, 8];
|
|
145
|
+
|
|
146
|
+
// Rendered in the 1280px-wide rstest viewport.
|
|
147
|
+
const mountListingResponsive = (listingVariant: ListingVariant): void => {
|
|
148
|
+
render(
|
|
149
|
+
<div style={{ height: '100vh' }}>
|
|
150
|
+
<Listing
|
|
151
|
+
columns={defaultColumn}
|
|
152
|
+
currentPage={1}
|
|
153
|
+
isResponsive
|
|
154
|
+
limit={10}
|
|
155
|
+
listingVariant={listingVariant}
|
|
156
|
+
rows={listingWithSubItems}
|
|
157
|
+
totalRows={10}
|
|
158
|
+
/>
|
|
159
|
+
</div>
|
|
160
|
+
);
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
interface TestComponentProps {
|
|
164
|
+
canCheckSubItems?: boolean;
|
|
165
|
+
isSmallListing?: boolean;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
const TestComponent = ({
|
|
169
|
+
isSmallListing = false,
|
|
170
|
+
canCheckSubItems = false
|
|
171
|
+
}: TestComponentProps): JSX.Element => {
|
|
172
|
+
const [selectedRows, setSelectedRows] = useState<Array<Item>>([]);
|
|
173
|
+
|
|
174
|
+
return (
|
|
175
|
+
<Listing
|
|
176
|
+
checkable
|
|
177
|
+
columns={columnsWithSubItems}
|
|
178
|
+
currentPage={1}
|
|
179
|
+
limit={10}
|
|
180
|
+
onSelectRows={setSelectedRows}
|
|
181
|
+
rows={isSmallListing ? listingWithSubItems3Rows : listingWithSubItems}
|
|
182
|
+
selectedRows={selectedRows}
|
|
183
|
+
subItems={{
|
|
184
|
+
canCheckSubItems,
|
|
185
|
+
enable: true,
|
|
186
|
+
getRowProperty: () => 'subItems',
|
|
187
|
+
labelCollapse: 'Collapse',
|
|
188
|
+
labelExpand: 'Expand'
|
|
189
|
+
}}
|
|
190
|
+
totalRows={10}
|
|
191
|
+
/>
|
|
192
|
+
);
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
const mountListingForSubItems = ({
|
|
196
|
+
isSmallListing = false,
|
|
197
|
+
canCheckSubItems = false
|
|
198
|
+
}: TestComponentProps): void => {
|
|
199
|
+
render(
|
|
200
|
+
<div style={{ height: '100vh' }}>
|
|
201
|
+
<TestComponent
|
|
202
|
+
canCheckSubItems={canCheckSubItems}
|
|
203
|
+
isSmallListing={isSmallListing}
|
|
204
|
+
/>
|
|
205
|
+
</div>
|
|
206
|
+
);
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
// Every row collapsed: the headers, the ten rows in order, an expand caret on
|
|
210
|
+
// the rows with sub items only, and no sub item.
|
|
211
|
+
const expectCollapsedListing = (): void => {
|
|
212
|
+
['Name', 'Description', 'Custom'].forEach((label) => {
|
|
213
|
+
expect(screen.getByText(label)).toBeVisible();
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
listingWithSubItems.forEach(({ id, name, description, subItems }) => {
|
|
217
|
+
expect(screen.getByText(name)).toBeVisible();
|
|
218
|
+
expect(screen.getByText(description)).toBeVisible();
|
|
219
|
+
expect(
|
|
220
|
+
screen.getByText(`Click to reveal details about ${name}`)
|
|
221
|
+
).toBeVisible();
|
|
222
|
+
|
|
223
|
+
if (subItems) {
|
|
224
|
+
expect(screen.getByLabelText(`Expand ${id}`)).toBeVisible();
|
|
225
|
+
} else {
|
|
226
|
+
expect(screen.queryByLabelText(`Expand ${id}`)).not.toBeInTheDocument();
|
|
227
|
+
}
|
|
228
|
+
expect(screen.queryByLabelText(`Collapse ${id}`)).not.toBeInTheDocument();
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
expect(screen.queryByText(/^Sub Item/)).not.toBeInTheDocument();
|
|
232
|
+
expect(screen.queryByText(/^Sub item/)).not.toBeInTheDocument();
|
|
233
|
+
|
|
234
|
+
const names = screen
|
|
235
|
+
.getAllByText(/^E\d$/)
|
|
236
|
+
.map((element) => element.textContent);
|
|
237
|
+
|
|
238
|
+
expect(names).toEqual(listingWithSubItems.map(({ name }) => name));
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
// The headers, the rows in order and the large text of the last column on
|
|
242
|
+
// each row.
|
|
243
|
+
const expectResponsiveListing = (): void => {
|
|
244
|
+
['Name', 'Description', 'Custom'].forEach((label) => {
|
|
245
|
+
expect(screen.getByText(label)).toBeVisible();
|
|
246
|
+
});
|
|
247
|
+
expect(
|
|
248
|
+
screen.getAllByText('This is a large text that fills the content')
|
|
249
|
+
).toHaveLength(10);
|
|
250
|
+
|
|
251
|
+
const names = screen
|
|
252
|
+
.getAllByText(/^E\d$/)
|
|
253
|
+
.map((element) => element.textContent);
|
|
254
|
+
|
|
255
|
+
expect(names).toEqual(listingWithSubItems.map(({ name }) => name));
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// The header row keeps the variant's height; the rows grow to fit the large
|
|
259
|
+
// text, which wraps onto several lines. How many lines depends on the
|
|
260
|
+
// platform's text metrics, so the rows are not compared to a fixed height.
|
|
261
|
+
const expectLastColumnOnSeveralLines = async (
|
|
262
|
+
headerHeight: number
|
|
263
|
+
): Promise<void> => {
|
|
264
|
+
await waitFor(() => {
|
|
265
|
+
const [header, ...rows] = getComputedStyle(getTable())
|
|
266
|
+
.gridTemplateRows.split(' ')
|
|
267
|
+
.map(Number.parseFloat);
|
|
268
|
+
|
|
269
|
+
expect(header).toBe(headerHeight);
|
|
270
|
+
expect(rows).toHaveLength(10);
|
|
271
|
+
rows.forEach((row) => {
|
|
272
|
+
expect(row).toBe(rows[0]);
|
|
273
|
+
expect(row).toBeGreaterThan(headerHeight);
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
screen
|
|
278
|
+
.getAllByText('This is a large text that fills the content')
|
|
279
|
+
.forEach((text) => {
|
|
280
|
+
const lineHeight = Number.parseFloat(getComputedStyle(text).lineHeight);
|
|
281
|
+
|
|
282
|
+
expect(text.getBoundingClientRect().height).toBeGreaterThanOrEqual(
|
|
283
|
+
2 * lineHeight
|
|
284
|
+
);
|
|
285
|
+
});
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const getTable = (): HTMLElement => {
|
|
289
|
+
const table = document.querySelector<HTMLElement>('.MuiTable-root');
|
|
290
|
+
|
|
291
|
+
if (!table) {
|
|
292
|
+
throw new Error('No table');
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
return table;
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
describe('Listing', () => {
|
|
299
|
+
beforeEach(() => {
|
|
300
|
+
expect.hasAssertions();
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
describe('Sub items', () => {
|
|
304
|
+
it('expands the row when the corresponding icon is clicked', async () => {
|
|
305
|
+
mountListingForSubItems({});
|
|
306
|
+
|
|
307
|
+
expect(await screen.findByText('E0')).toBeVisible();
|
|
308
|
+
|
|
309
|
+
for (const index of expandedItems) {
|
|
310
|
+
const subItems = generateSubItems();
|
|
311
|
+
|
|
312
|
+
await userEvent.click(screen.getByLabelText(`Expand ${index}`));
|
|
313
|
+
|
|
314
|
+
expect(
|
|
315
|
+
await screen.findByLabelText(`Collapse ${index}`)
|
|
316
|
+
).toBeInTheDocument();
|
|
317
|
+
|
|
318
|
+
for (const { name, description } of subItems) {
|
|
319
|
+
expect(await screen.findByText(name)).toBeInTheDocument();
|
|
320
|
+
expect(screen.getByText(description)).toBeInTheDocument();
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
await userEvent.click(screen.getByLabelText(`Collapse ${index}`));
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
await waitFor(() => {
|
|
327
|
+
expect(screen.queryByText('Sub Item 0')).not.toBeInTheDocument();
|
|
328
|
+
});
|
|
329
|
+
expectCollapsedListing();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
it('collapses the row when the corresponding icon is clicked', async () => {
|
|
333
|
+
mountListingForSubItems({});
|
|
334
|
+
|
|
335
|
+
await userEvent.click(await screen.findByLabelText('Expand 0'));
|
|
336
|
+
|
|
337
|
+
expect(await screen.findByText('Sub item 10 description')).toBeVisible();
|
|
338
|
+
|
|
339
|
+
await userEvent.click(screen.getByLabelText('Collapse 0'));
|
|
340
|
+
|
|
341
|
+
await waitFor(() => {
|
|
342
|
+
expect(screen.queryByText(/Sub item 10/)).not.toBeInTheDocument();
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
expectCollapsedListing();
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('displays only one row as hovered when mutilple rows are expanded and a sub item row is hovered', async () => {
|
|
349
|
+
mountListingForSubItems({ isSmallListing: true });
|
|
350
|
+
|
|
351
|
+
await userEvent.click(await screen.findByLabelText('Expand 2'));
|
|
352
|
+
await userEvent.click(await screen.findByLabelText('Expand 0'));
|
|
353
|
+
|
|
354
|
+
expect(await screen.findByLabelText('Collapse 0')).toBeVisible();
|
|
355
|
+
expect(await screen.findByLabelText('Collapse 2')).toBeVisible();
|
|
356
|
+
|
|
357
|
+
await userEvent.hover(screen.getAllByText('Sub Item 0')[0]);
|
|
358
|
+
|
|
359
|
+
await waitFor(() => {
|
|
360
|
+
expect(
|
|
361
|
+
document.querySelectorAll('[data-is-hovered="true"]')
|
|
362
|
+
).toHaveLength(1);
|
|
363
|
+
});
|
|
364
|
+
const hoveredRow = document.querySelector<HTMLElement>(
|
|
365
|
+
'[data-is-hovered="true"]'
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
expect(
|
|
369
|
+
within(hoveredRow as HTMLElement).getByText('Sub Item 0')
|
|
370
|
+
).toBeInTheDocument();
|
|
371
|
+
|
|
372
|
+
await userEvent.click(screen.getByLabelText('Collapse 0'));
|
|
373
|
+
await userEvent.click(screen.getByLabelText('Collapse 2'));
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('selects displayed rows when a row is selected and another row is selected with the shift key', async () => {
|
|
377
|
+
const user = userEvent.setup();
|
|
378
|
+
|
|
379
|
+
mountListingForSubItems({ canCheckSubItems: true, isSmallListing: true });
|
|
380
|
+
|
|
381
|
+
await user.click(await screen.findByLabelText('Expand 2'));
|
|
382
|
+
|
|
383
|
+
expect(await screen.findByLabelText('Collapse 2')).toBeVisible();
|
|
384
|
+
|
|
385
|
+
await user.click(screen.getAllByLabelText('Select row 2')[0]);
|
|
386
|
+
await user.keyboard('{Shift>}');
|
|
387
|
+
await user.click(screen.getByLabelText('Select row 50'));
|
|
388
|
+
await user.keyboard('{/Shift}');
|
|
389
|
+
|
|
390
|
+
await waitFor(() => {
|
|
391
|
+
expect(screen.getByLabelText('Select row 40')).toBeChecked();
|
|
392
|
+
});
|
|
393
|
+
expect(screen.getAllByLabelText('Select row 2')[0]).toBeChecked();
|
|
394
|
+
expect(screen.getByLabelText('Select row 10')).toBeChecked();
|
|
395
|
+
expect(screen.getByLabelText('Select row 20')).toBeChecked();
|
|
396
|
+
expect(screen.getByLabelText('Select row 30')).toBeChecked();
|
|
397
|
+
expect(screen.getByLabelText('Select row 40')).toBeChecked();
|
|
398
|
+
|
|
399
|
+
await user.click(screen.getByLabelText('Collapse 2'));
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
it('selects displayed rows when the corresponding checkbox is clicked', async () => {
|
|
403
|
+
mountListingForSubItems({ canCheckSubItems: true, isSmallListing: true });
|
|
404
|
+
|
|
405
|
+
await userEvent.click(await screen.findByLabelText('Expand 2'));
|
|
406
|
+
|
|
407
|
+
expect(await screen.findByLabelText('Collapse 2')).toBeVisible();
|
|
408
|
+
|
|
409
|
+
await userEvent.click(screen.getAllByLabelText('Select all')[0]);
|
|
410
|
+
|
|
411
|
+
await waitFor(() => {
|
|
412
|
+
expect(screen.getAllByLabelText('Select row 2')[0]).toBeChecked();
|
|
413
|
+
});
|
|
414
|
+
tenElements.forEach((_, index) => {
|
|
415
|
+
if (index === 0) {
|
|
416
|
+
expect(screen.getAllByLabelText('Select row 0')[1]).toBeChecked();
|
|
417
|
+
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
expect(screen.getByLabelText(`Select row ${index * 10}`)).toBeChecked();
|
|
421
|
+
});
|
|
422
|
+
expect(screen.getByLabelText('Select row 1')).toBeChecked();
|
|
423
|
+
expect(screen.getByLabelText('Select row 2')).toBeChecked();
|
|
424
|
+
|
|
425
|
+
await userEvent.click(screen.getByLabelText('Collapse 2'));
|
|
426
|
+
});
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
it('displays the last column on several lines in compact mode when the isResponsive prop is set', async () => {
|
|
430
|
+
mountListingResponsive(ListingVariant.compact);
|
|
431
|
+
|
|
432
|
+
await expectLastColumnOnSeveralLines(30);
|
|
433
|
+
|
|
434
|
+
expectResponsiveListing();
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
it('displays the last column on several lines in extended mode when the isResponsive prop is set', async () => {
|
|
438
|
+
mountListingResponsive(ListingVariant.extended);
|
|
439
|
+
|
|
440
|
+
await expectLastColumnOnSeveralLines(38);
|
|
441
|
+
|
|
442
|
+
expectResponsiveListing();
|
|
443
|
+
});
|
|
444
|
+
|
|
445
|
+
it('toggles a checkbox in a clickable column without clicking the row', async () => {
|
|
446
|
+
const onRowClick = rs.fn();
|
|
447
|
+
|
|
448
|
+
render(
|
|
449
|
+
<div style={{ height: '100vh' }}>
|
|
450
|
+
<Listing
|
|
451
|
+
columns={[
|
|
452
|
+
{
|
|
453
|
+
Component: CheckboxColumn,
|
|
454
|
+
clickable: true,
|
|
455
|
+
id: 'toggle',
|
|
456
|
+
label: 'Toggle',
|
|
457
|
+
type: ColumnType.component
|
|
458
|
+
}
|
|
459
|
+
]}
|
|
460
|
+
currentPage={1}
|
|
461
|
+
limit={10}
|
|
462
|
+
onRowClick={onRowClick}
|
|
463
|
+
rows={[{ id: 0, name: 'E0' }]}
|
|
464
|
+
totalRows={1}
|
|
465
|
+
/>
|
|
466
|
+
</div>
|
|
467
|
+
);
|
|
468
|
+
|
|
469
|
+
await userEvent.click(await screen.findByLabelText('Toggle E0'));
|
|
470
|
+
|
|
471
|
+
await waitFor(() => {
|
|
472
|
+
expect(screen.getByLabelText('Toggle E0')).toBeChecked();
|
|
473
|
+
});
|
|
474
|
+
expect(onRowClick).not.toHaveBeenCalled();
|
|
475
|
+
});
|
|
476
|
+
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { interceptAPIRequest, waitForRequest } from '@test-setup/api';
|
|
2
|
+
import { render } from '@test-setup/render';
|
|
3
|
+
import { screen, waitFor } from '@testing-library/react';
|
|
4
|
+
import { createStore } from 'jotai';
|
|
5
|
+
|
|
6
|
+
import { Method } from '..';
|
|
7
|
+
import Module from '.';
|
|
8
|
+
import LicensedModule from './LicensedModule';
|
|
9
|
+
|
|
10
|
+
const initializeModule = (): void => {
|
|
11
|
+
render(
|
|
12
|
+
<Module seedName="seed" store={createStore()}>
|
|
13
|
+
<p>Module</p>
|
|
14
|
+
</Module>
|
|
15
|
+
);
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
const initializeModuleWithValidLicense = (
|
|
19
|
+
isFederatedComponent = false
|
|
20
|
+
): void => {
|
|
21
|
+
interceptAPIRequest({
|
|
22
|
+
alias: 'getValidLicense',
|
|
23
|
+
method: Method.GET,
|
|
24
|
+
path: './api/internal.php?object=centreon_license_manager&action=licenseValid&productName=valid',
|
|
25
|
+
response: {
|
|
26
|
+
success: true
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
render(
|
|
31
|
+
<div style={{ height: '100vh' }}>
|
|
32
|
+
<LicensedModule
|
|
33
|
+
isFederatedComponent={isFederatedComponent}
|
|
34
|
+
moduleName="valid"
|
|
35
|
+
seedName="seed"
|
|
36
|
+
store={createStore()}
|
|
37
|
+
>
|
|
38
|
+
<p>Module</p>
|
|
39
|
+
</LicensedModule>
|
|
40
|
+
</div>
|
|
41
|
+
);
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const initializeModuleWithInvalidLicense = (
|
|
45
|
+
isFederatedComponent = false
|
|
46
|
+
): void => {
|
|
47
|
+
interceptAPIRequest({
|
|
48
|
+
alias: 'getInvalidLicense',
|
|
49
|
+
method: Method.GET,
|
|
50
|
+
path: './api/internal.php?object=centreon_license_manager&action=licenseValid&productName=invalid',
|
|
51
|
+
response: {
|
|
52
|
+
success: false
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
render(
|
|
57
|
+
<div style={{ height: '100vh' }}>
|
|
58
|
+
<LicensedModule
|
|
59
|
+
isFederatedComponent={isFederatedComponent}
|
|
60
|
+
moduleName="invalid"
|
|
61
|
+
seedName="seed"
|
|
62
|
+
store={createStore()}
|
|
63
|
+
>
|
|
64
|
+
<p>Module</p>
|
|
65
|
+
</LicensedModule>
|
|
66
|
+
</div>
|
|
67
|
+
);
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
describe('Module', () => {
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
expect.hasAssertions();
|
|
73
|
+
});
|
|
74
|
+
beforeEach(() => {
|
|
75
|
+
initializeModule();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('displays the content of the module', async () => {
|
|
79
|
+
expect(await screen.findByText('Module')).toBeVisible();
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('Valid license module', () => {
|
|
84
|
+
beforeEach(() => {
|
|
85
|
+
expect.hasAssertions();
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
it('displays the content of the page when the license is valid license', async () => {
|
|
89
|
+
initializeModuleWithValidLicense();
|
|
90
|
+
const { request } = await waitForRequest('@getValidLicense');
|
|
91
|
+
|
|
92
|
+
expect(await screen.findByText('Module')).toBeVisible();
|
|
93
|
+
|
|
94
|
+
// The license is checked for the module given.
|
|
95
|
+
expect(request.url.searchParams.get('productName')).toBe('valid');
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it('displays the content of the component when the license is valid license', async () => {
|
|
99
|
+
initializeModuleWithValidLicense(true);
|
|
100
|
+
|
|
101
|
+
expect(await screen.findByText('Module')).toBeVisible();
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe('Invalid license module', () => {
|
|
106
|
+
beforeEach(() => {
|
|
107
|
+
expect.hasAssertions();
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('displays the content of the page when the license is invalid license', async () => {
|
|
111
|
+
initializeModuleWithInvalidLicense();
|
|
112
|
+
await waitForRequest('@getInvalidLicense');
|
|
113
|
+
|
|
114
|
+
expect(await screen.findByText('Oops !')).toBeVisible();
|
|
115
|
+
expect(screen.queryByText('Module')).not.toBeInTheDocument();
|
|
116
|
+
|
|
117
|
+
expect(screen.getByText('License invalid or expired !')).toBeVisible();
|
|
118
|
+
expect(
|
|
119
|
+
screen.getByText('Please contact your administrator.')
|
|
120
|
+
).toBeVisible();
|
|
121
|
+
// The images are shown once loaded.
|
|
122
|
+
await waitFor(() => {
|
|
123
|
+
expect(
|
|
124
|
+
document.querySelector('img[alt="License invalid or expired !"]')
|
|
125
|
+
).toBeVisible();
|
|
126
|
+
});
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(document.querySelector('img[alt="Centreon Logo"]')).toBeVisible();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('displays the content of the module when the license is invalid license', async () => {
|
|
133
|
+
initializeModuleWithInvalidLicense(true);
|
|
134
|
+
// No request to wait for: the previous test left the license of this
|
|
135
|
+
// module in the shared query cache. Once no skeleton is left, the page is
|
|
136
|
+
// empty: neither the fallback page nor a skeleton.
|
|
137
|
+
await waitFor(() => {
|
|
138
|
+
expect(
|
|
139
|
+
document.querySelector('.MuiSkeleton-root')
|
|
140
|
+
).not.toBeInTheDocument();
|
|
141
|
+
});
|
|
142
|
+
expect(screen.queryByText('Module')).not.toBeInTheDocument();
|
|
143
|
+
expect(screen.queryByText('Oops !')).not.toBeInTheDocument();
|
|
144
|
+
});
|
|
145
|
+
});
|