@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.
Files changed (56) hide show
  1. package/package.json +6 -3
  2. package/public/mockServiceWorker.js +31 -8
  3. package/src/Dashboard/Dashboard.browser.test.tsx +107 -0
  4. package/src/Form/Form.browser.test.tsx +445 -0
  5. package/src/Form/Inputs/ExclusiveCheckboxGroup.browser.test.tsx +304 -0
  6. package/src/Form/Inputs/SegmentedButtons.browser.test.tsx +113 -0
  7. package/src/InputField/Number/Number.browser.test.tsx +109 -0
  8. package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.browser.test.tsx +250 -0
  9. package/src/Listing/Listing.browser.test.tsx +476 -0
  10. package/src/Module/Module.browser.test.tsx +145 -0
  11. package/src/Pagination/Pagination.browser.test.tsx +184 -0
  12. package/src/RichTextEditor/RichTextEditor.browser.test.tsx +567 -0
  13. package/src/RichTextEditor/plugins/FloatingLinkEditorPlugin.tsx +3 -1
  14. package/src/TimePeriods/ResolutionTimePeriod.browser.test.tsx +143 -0
  15. package/src/TimePeriods/TimePeriods.browser.test.tsx +468 -0
  16. package/src/Typography/FluidTypography/FluidTypography.browser.test.tsx +54 -0
  17. package/src/api/useMutationQuery/useMutationQuery.browser.test.tsx +154 -0
  18. package/src/components/CollapsibleItem/CollapsibleItem.browser.test.tsx +120 -0
  19. package/src/components/CopyCommand/CopyCommand.browser.test.tsx +287 -0
  20. package/src/components/CrudPage/CrudPage.browser.test.tsx +659 -0
  21. package/src/components/DataTable/DataTable.browser.test.tsx +257 -0
  22. package/src/components/Form/AccessRights/AccessRights.browser.test.tsx +527 -0
  23. package/src/components/ItemComposition/ItemComposition.browser.test.tsx +172 -0
  24. package/src/components/Layout/PageLayout.browser.test.tsx +114 -0
  25. package/src/components/Modal/ConfirmationModal/ConfirmationModal.browser.test.tsx +237 -0
  26. package/src/components/SortableEntriesList/SortableEntriesList.browser.test.tsx +981 -0
  27. package/src/components/Tabs/Tabs.browser.test.tsx +115 -0
  28. package/src/utils/useFullscreen/Fullscreen.browser.test.tsx +176 -0
  29. package/src/utils/useLocale/useLocale.browser.test.tsx +49 -0
  30. package/src/utils/useLocaleTimezoneDate/{LocaleTimezoneDate.cypress.spec.tsx → LocaleTimezoneDate.browser.test.tsx} +24 -11
  31. package/src/Dashboard/Dashboard.cypress.spec.tsx +0 -71
  32. package/src/Form/Form.cypress.spec.tsx +0 -306
  33. package/src/Form/Inputs/ExclusiveCheckboxGroup.cypress.spec.tsx +0 -236
  34. package/src/Form/Inputs/SegmentedButtons.cypress.spec.tsx +0 -101
  35. package/src/InputField/Number/Number.cypress.spec.tsx +0 -89
  36. package/src/InputField/Select/Autocomplete/Connected/Multi/MultiConnectedAutocompleteField.cypress.spec.tsx +0 -182
  37. package/src/Listing/Listing.cypress.spec.tsx +0 -349
  38. package/src/Module/Module.cypress.spec.tsx +0 -127
  39. package/src/Pagination/Pagination.cypress.spec.tsx +0 -140
  40. package/src/RichTextEditor/RichTextEditor.cypress.spec.tsx +0 -408
  41. package/src/TimePeriods/ResolutionTimePeriod.cypress.spec.tsx +0 -74
  42. package/src/TimePeriods/TimePeriods.cypress.spec.tsx +0 -488
  43. package/src/Typography/FluidTypography/FluidTypography.cypress.spec.tsx +0 -27
  44. package/src/api/useMutationQuery/useMutationQuery.cypress.spec.tsx +0 -93
  45. package/src/components/CollapsibleItem/CollapsibleItem.cypress.spec.tsx +0 -76
  46. package/src/components/CopyCommand/CopyCommand.cypress.spec.tsx +0 -167
  47. package/src/components/CrudPage/CrudPage.cypress.spec.tsx +0 -561
  48. package/src/components/DataTable/DataTable.cypress.spec.tsx +0 -174
  49. package/src/components/Form/AccessRights/AccessRights.cypress.spec.tsx +0 -376
  50. package/src/components/ItemComposition/ItemComposition.cypress.spec.tsx +0 -112
  51. package/src/components/Layout/PageLayout.cypress.spec.tsx +0 -64
  52. package/src/components/Modal/ConfirmationModal/ConfirmationModal.cypress.spec.tsx +0 -171
  53. package/src/components/SortableEntriesList/SortableEntriesList.cypress.spec.tsx +0 -792
  54. package/src/components/Tabs/Tabs.cypress.spec.tsx +0 -69
  55. package/src/utils/useFullscreen/Fullscreen.cypress.spec.tsx +0 -130
  56. package/src/utils/useLocale/useLocale.cypress.spec.tsx +0 -40
@@ -0,0 +1,115 @@
1
+ import { Typography } from '@mui/material';
2
+
3
+ import { render } from '@test-setup/render';
4
+ import { screen, waitFor } from '@testing-library/react';
5
+ import userEvent from '@testing-library/user-event';
6
+
7
+ import { Tabs } from '.';
8
+ import { TabPanel } from './TabPanel';
9
+
10
+ const initialize = (withTabListProps = false): void => {
11
+ render(
12
+ <Tabs
13
+ defaultTab="tab 0"
14
+ tabList={
15
+ withTabListProps
16
+ ? {
17
+ variant: 'fullWidth'
18
+ }
19
+ : undefined
20
+ }
21
+ tabs={[
22
+ { label: 'Tab 0', value: 'tab 0' },
23
+ { label: 'Tab 1', value: 'tab 1' }
24
+ ]}
25
+ >
26
+ <TabPanel value="tab 0">
27
+ <Typography>Tab 0</Typography>
28
+ </TabPanel>
29
+ <TabPanel value="tab 1">
30
+ <Typography>Tab 1</Typography>
31
+ </TabPanel>
32
+ </Tabs>
33
+ );
34
+ };
35
+
36
+ const getTabPanel = (value: string): HTMLElement =>
37
+ document.querySelector(`[data-TabPanel="${value}"]`) as HTMLElement;
38
+
39
+ const getFontWeight = (element: HTMLElement): string =>
40
+ getComputedStyle(element).fontWeight;
41
+
42
+ describe('Tabs', () => {
43
+ beforeEach(() => {
44
+ expect.hasAssertions();
45
+ });
46
+
47
+ it('displays tabs and their content when a tab is selected', async () => {
48
+ initialize();
49
+
50
+ await waitFor(() => {
51
+ expect(getTabPanel('tab 0')).not.toHaveAttribute('hidden');
52
+ });
53
+ expect(getTabPanel('tab 1')).toHaveAttribute('hidden');
54
+ expect(screen.getByLabelText('Tab 0')).toHaveAttribute(
55
+ 'aria-selected',
56
+ 'true'
57
+ );
58
+ expect(screen.getByLabelText('Tab 1')).toHaveAttribute(
59
+ 'aria-selected',
60
+ 'false'
61
+ );
62
+
63
+ await userEvent.click(screen.getByRole('tab', { name: 'Tab 1' }));
64
+
65
+ await waitFor(() => {
66
+ expect(getTabPanel('tab 0')).toHaveAttribute('hidden');
67
+ });
68
+ expect(getTabPanel('tab 1')).not.toHaveAttribute('hidden');
69
+ expect(screen.getByLabelText('Tab 0')).toHaveAttribute(
70
+ 'aria-selected',
71
+ 'false'
72
+ );
73
+ expect(screen.getByLabelText('Tab 1')).toHaveAttribute(
74
+ 'aria-selected',
75
+ 'true'
76
+ );
77
+
78
+ // The selected tab in bold, the other one not, and the content of the
79
+ // selected panel only.
80
+ expect(getFontWeight(screen.getByLabelText('Tab 1'))).toBe('700');
81
+ expect(getFontWeight(screen.getByLabelText('Tab 0'))).toBe('400');
82
+ expect(getTabPanel('tab 1')).toHaveTextContent(/^Tab 1$/);
83
+ expect(getTabPanel('tab 1')).toBeVisible();
84
+ expect(getTabPanel('tab 0')).not.toBeVisible();
85
+ });
86
+
87
+ it('displays tabs when tabList props are set', async () => {
88
+ initialize(true);
89
+
90
+ await waitFor(() => {
91
+ expect(getTabPanel('tab 0')).not.toHaveAttribute('hidden');
92
+ });
93
+ expect(getTabPanel('tab 1')).toHaveAttribute('hidden');
94
+
95
+ // The first tab selected, in bold, and the two tabs sharing the full
96
+ // width of the page.
97
+ const firstTab = screen.getByLabelText('Tab 0');
98
+ const secondTab = screen.getByLabelText('Tab 1');
99
+
100
+ expect(firstTab).toHaveAttribute('aria-selected', 'true');
101
+ expect(getFontWeight(firstTab)).toBe('700');
102
+ expect(getFontWeight(secondTab)).toBe('400');
103
+ expect(getTabPanel('tab 0')).toHaveTextContent(/^Tab 0$/);
104
+
105
+ const tabList = screen.getByRole('tablist');
106
+ const tabListWidth = tabList.getBoundingClientRect().width;
107
+ const firstTabWidth = firstTab.getBoundingClientRect().width;
108
+
109
+ expect(firstTabWidth).toBeGreaterThan(tabListWidth / 2 - 32);
110
+ expect(secondTab.getBoundingClientRect().width).toBeCloseTo(
111
+ firstTabWidth,
112
+ 0
113
+ );
114
+ });
115
+ });
@@ -0,0 +1,176 @@
1
+ import { Button } from '@mui/material';
2
+
3
+ import { rs } from '@rstest/core';
4
+ import { render } from '@test-setup/render';
5
+ import { screen, waitFor } from '@testing-library/react';
6
+ import userEvent from '@testing-library/user-event';
7
+ import { createStore, Provider } from 'jotai';
8
+ import { BrowserRouter } from 'react-router';
9
+
10
+ import { useFullscreen } from './useFullscreen';
11
+ import { router, useFullscreenListener } from './useFullscreenListener';
12
+
13
+ const labelEnterFullscreen = 'Enter fullscreen';
14
+ const labelExitFullscreen = 'Exit fullscreen';
15
+
16
+ const ChildComponent = (): JSX.Element => {
17
+ const { toggleFullscreen, fullscreenEnabled, isFullscreenActivated } =
18
+ useFullscreen();
19
+
20
+ return (
21
+ <div
22
+ data-fullscreenActivated={isFullscreenActivated}
23
+ data-fullscreenEnabled={fullscreenEnabled}
24
+ id="test"
25
+ >
26
+ <Button onClick={() => toggleFullscreen(document.body)}>
27
+ {isFullscreenActivated ? labelExitFullscreen : labelEnterFullscreen}
28
+ </Button>
29
+ <input id="input" />
30
+ <textarea id="textarea" />
31
+ </div>
32
+ );
33
+ };
34
+
35
+ const TestComponent = (): JSX.Element => {
36
+ useFullscreenListener();
37
+
38
+ return <ChildComponent />;
39
+ };
40
+
41
+ // The real Fullscreen API is shared by the whole browser: with test files
42
+ // running in parallel pages, a request can be refused or exited by another
43
+ // page. It is faked here, with the same contract: the promises resolve, the
44
+ // fullscreen element is set and cleared, and `fullscreenchange` is fired.
45
+ const fakeFullscreenApi = (): void => {
46
+ let fullscreenElement: Element | null = null;
47
+
48
+ const changeFullscreenElement = (element: Element | null): Promise<void> => {
49
+ fullscreenElement = element;
50
+ document.dispatchEvent(new Event('fullscreenchange'));
51
+
52
+ return Promise.resolve();
53
+ };
54
+
55
+ rs.spyOn(Document.prototype, 'fullscreenElement', 'get').mockImplementation(
56
+ () => fullscreenElement
57
+ );
58
+ rs.spyOn(Document.prototype, 'fullscreenEnabled', 'get').mockReturnValue(
59
+ true
60
+ );
61
+ rs.spyOn(Element.prototype, 'requestFullscreen').mockImplementation(function (
62
+ this: Element
63
+ ) {
64
+ return changeFullscreenElement(this);
65
+ });
66
+ rs.spyOn(Document.prototype, 'exitFullscreen').mockImplementation(() =>
67
+ changeFullscreenElement(null)
68
+ );
69
+ };
70
+
71
+ const initialize = (): void => {
72
+ fakeFullscreenApi();
73
+
74
+ const store = createStore();
75
+
76
+ const queryParameters = new Map();
77
+
78
+ rs.spyOn(router, 'useSearchParams').mockImplementation(
79
+ () =>
80
+ queryParameters as unknown as ReturnType<typeof router.useSearchParams>
81
+ );
82
+
83
+ render(
84
+ <BrowserRouter>
85
+ <Provider store={store}>
86
+ <TestComponent />
87
+ </Provider>
88
+ </BrowserRouter>
89
+ );
90
+ };
91
+
92
+ const getTestElement = (): HTMLElement =>
93
+ document.querySelector('#test') as HTMLElement;
94
+
95
+ const expectFullscreen = async (activated: boolean): Promise<void> => {
96
+ await waitFor(() => {
97
+ expect(getTestElement()).toHaveAttribute(
98
+ 'data-fullscreenActivated',
99
+ `${activated}`
100
+ );
101
+ });
102
+ expect(getTestElement()).toHaveAttribute('data-fullscreenEnabled', 'true');
103
+ };
104
+
105
+ describe('Fullscreen', () => {
106
+ beforeEach(() => {
107
+ expect.hasAssertions();
108
+ });
109
+
110
+ afterEach(() => {
111
+ rs.restoreAllMocks();
112
+ });
113
+
114
+ it('enters fullscreen mode when the button is clicked', async () => {
115
+ initialize();
116
+
117
+ await expectFullscreen(false);
118
+
119
+ await userEvent.click(screen.getByText(labelEnterFullscreen));
120
+
121
+ await expectFullscreen(true);
122
+
123
+ await userEvent.click(screen.getByText(labelExitFullscreen));
124
+ });
125
+
126
+ it('exits fullscreen mode when the button is clicked', async () => {
127
+ initialize();
128
+
129
+ await expectFullscreen(false);
130
+
131
+ await userEvent.click(screen.getByText(labelEnterFullscreen));
132
+
133
+ await expectFullscreen(true);
134
+
135
+ await userEvent.click(screen.getByText(labelExitFullscreen));
136
+
137
+ await expectFullscreen(false);
138
+ });
139
+
140
+ it('toggles fullscreen mode when the corresponding shortcut is clicked', async () => {
141
+ initialize();
142
+
143
+ await expectFullscreen(false);
144
+
145
+ await userEvent.keyboard('F');
146
+
147
+ await expectFullscreen(true);
148
+
149
+ await userEvent.keyboard('F');
150
+
151
+ await expectFullscreen(false);
152
+ });
153
+
154
+ ['input', 'textarea'].forEach((tag) => {
155
+ it(`cannot toggle fullscreen feature using the shortcut when ${tag === 'input' ? 'an' : 'a'} ${tag} is focused`, async () => {
156
+ initialize();
157
+
158
+ await expectFullscreen(false);
159
+
160
+ // The spies (which call through) tell that the shortcut did not even
161
+ // ask for a change.
162
+ const requestFullscreen = rs.spyOn(document.body, 'requestFullscreen');
163
+ const exitFullscreen = rs.spyOn(document, 'exitFullscreen');
164
+ const field = document.querySelector(`#${tag}`) as HTMLInputElement;
165
+
166
+ field.focus();
167
+
168
+ await userEvent.keyboard('F');
169
+
170
+ await expectFullscreen(false);
171
+ expect(field).toHaveValue('F');
172
+ expect(requestFullscreen).not.toHaveBeenCalled();
173
+ expect(exitFullscreen).not.toHaveBeenCalled();
174
+ });
175
+ });
176
+ });
@@ -0,0 +1,49 @@
1
+ import { browserLocaleAtom, type User, userAtom } from '@centreon/ui-context';
2
+
3
+ import { render } from '@test-setup/render';
4
+ import { screen } from '@testing-library/react';
5
+ import { createStore, Provider } from 'jotai';
6
+
7
+ import { useLocale } from '.';
8
+
9
+ const TestComponent = () => {
10
+ const locale = useLocale();
11
+
12
+ return <p>{locale}</p>;
13
+ };
14
+
15
+ interface InitializeProps {
16
+ browserLocale: string;
17
+ userLocale: string | null;
18
+ }
19
+
20
+ const initialize = ({ userLocale, browserLocale }: InitializeProps): void => {
21
+ const store = createStore();
22
+
23
+ store.set(userAtom, { locale: userLocale } as User);
24
+ store.set(browserLocaleAtom, browserLocale);
25
+
26
+ render(
27
+ <Provider store={store}>
28
+ <TestComponent />
29
+ </Provider>
30
+ );
31
+ };
32
+
33
+ describe('useLocale', () => {
34
+ beforeEach(() => {
35
+ expect.hasAssertions();
36
+ });
37
+
38
+ it('displays the user locale when the corresponding atom is set', async () => {
39
+ initialize({ browserLocale: 'en', userLocale: 'fi' });
40
+
41
+ expect(await screen.findByText('fi')).toBeVisible();
42
+ });
43
+
44
+ it('displays the browser locale when the user locale is not set', async () => {
45
+ initialize({ browserLocale: 'de', userLocale: null });
46
+
47
+ expect(await screen.findByText('de')).toBeVisible();
48
+ });
49
+ });
@@ -9,6 +9,9 @@ import 'dayjs/locale/en';
9
9
  import 'dayjs/locale/es';
10
10
  import 'dayjs/locale/pt';
11
11
 
12
+ import { render } from '@test-setup/render';
13
+ import { screen } from '@testing-library/react';
14
+
12
15
  import { type Props, useLocaleTimezoneDate } from './useLocaleTimezoneDate';
13
16
 
14
17
  dayjs.extend(localizedFormat);
@@ -27,10 +30,12 @@ const Test = ({
27
30
  return <p>{formatDate({ date, format, locale, timezone })}</p>;
28
31
  };
29
32
 
30
- const initialize = ({ timezone, locale, format }): void => {
31
- cy.mount({
32
- Component: <Test format={format} locale={locale} timezone={timezone} />
33
- });
33
+ const initialize = ({
34
+ timezone,
35
+ locale,
36
+ format
37
+ }: Omit<Props, 'date'>): void => {
38
+ render(<Test format={format} locale={locale} timezone={timezone} />);
34
39
  };
35
40
 
36
41
  const locales = [undefined, 'en-GB', 'fr-FR', 'de-DE'];
@@ -83,16 +88,24 @@ const resultsDE = [
83
88
  ];
84
89
 
85
90
  const results = [...resultsEN, ...resultsEN, ...resultsFR, ...resultsDE];
86
- let index = 0;
87
91
 
88
- locales.forEach((locale) => {
89
- timezones.forEach((timezone) => {
90
- formats.forEach((format) => {
91
- it(`displays the date with the locale ${locale}, the timezone ${timezone} and the format ${format}`, () => {
92
+ beforeEach(() => {
93
+ expect.hasAssertions();
94
+ });
95
+
96
+ locales.forEach((locale, localeIndex) => {
97
+ timezones.forEach((timezone, timezoneIndex) => {
98
+ formats.forEach((format, formatIndex) => {
99
+ // The expected result of this combination, independent of the order the
100
+ // tests run in.
101
+ const index =
102
+ (localeIndex * timezones.length + timezoneIndex) * formats.length +
103
+ formatIndex;
104
+
105
+ it(`displays the date with the locale ${locale}, the timezone ${timezone} and the format ${format}`, async () => {
92
106
  initialize({ format, locale, timezone });
93
107
 
94
- cy.contains(results[index]).should('be.visible');
95
- index += 1;
108
+ expect(await screen.findByText(results[index])).toBeVisible();
96
109
  });
97
110
  });
98
111
  });
@@ -1,71 +0,0 @@
1
- import { Typography } from '@mui/material';
2
-
3
- import { DashboardLayout } from '.';
4
-
5
- const dashboardLayout: Array<CustomLayout> = [
6
- {
7
- content: 'Panel 1',
8
- h: 4,
9
- i: 'a',
10
- shouldUseFluidTypography: false,
11
- w: 6,
12
- x: 0,
13
- y: 0
14
- },
15
- {
16
- content: 'Panel 2',
17
- h: 3,
18
- i: 'b',
19
- minW: 2,
20
- w: 7,
21
- x: 1,
22
- y: 7
23
- },
24
- {
25
- content: 'Panel 3',
26
- h: 7,
27
- i: 'c',
28
- w: 6,
29
- x: 6,
30
- y: 6
31
- },
32
- {
33
- content: 'Panel 4',
34
- h: 3,
35
- i: 'd',
36
- minW: 2,
37
- w: 5,
38
- x: 4,
39
- y: 10
40
- }
41
- ];
42
-
43
- const initialize = (): void => {
44
- cy.adjustViewport();
45
-
46
- cy.mount({
47
- Component: (
48
- <DashboardLayout.Layout layout={dashboardLayout}>
49
- {dashboardLayout.map(({ i, content }) => (
50
- <DashboardLayout.Item header={<div>header</div>} id={i} key={i}>
51
- <Typography>{content}</Typography>
52
- </DashboardLayout.Item>
53
- ))}
54
- </DashboardLayout.Layout>
55
- )
56
- });
57
-
58
- cy.viewport('macbook-13');
59
- };
60
-
61
- describe('Dashboard', () => {
62
- it('displays placeholder when panels is out of viewport', () => {
63
- initialize();
64
-
65
- cy.get('[data-widget-skeleton="a"]').should('not.exist');
66
- cy.get('[data-widget-skeleton="b"]').should('not.exist');
67
- cy.get('[data-widget-skeleton="c"]').should('not.exist');
68
-
69
- cy.makeSnapshot();
70
- });
71
- });