@scality/core-ui 0.162.0 → 0.164.0

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 (73) hide show
  1. package/dist/components/barchartv2/Barchart.component.d.ts +9 -3
  2. package/dist/components/barchartv2/Barchart.component.d.ts.map +1 -1
  3. package/dist/components/barchartv2/Barchart.component.js +22 -5
  4. package/dist/components/barchartv2/utils.d.ts +26 -3
  5. package/dist/components/barchartv2/utils.d.ts.map +1 -1
  6. package/dist/components/barchartv2/utils.js +76 -22
  7. package/dist/components/chartlegend/ChartLegend.d.ts +8 -0
  8. package/dist/components/chartlegend/ChartLegend.d.ts.map +1 -0
  9. package/dist/components/chartlegend/ChartLegend.js +65 -0
  10. package/dist/components/chartlegend/ChartLegendWrapper.d.ts +17 -0
  11. package/dist/components/chartlegend/ChartLegendWrapper.d.ts.map +1 -0
  12. package/dist/components/chartlegend/ChartLegendWrapper.js +50 -0
  13. package/dist/components/date/FormattedDateTime.d.ts +3 -1
  14. package/dist/components/date/FormattedDateTime.d.ts.map +1 -1
  15. package/dist/components/date/FormattedDateTime.js +19 -1
  16. package/dist/components/date/FormattedDateTime.spec.js +12 -0
  17. package/dist/components/icon/Icon.component.d.ts +5 -5
  18. package/dist/components/icon/Icon.component.d.ts.map +1 -1
  19. package/dist/components/icon/Icon.component.js +33 -31
  20. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts +33 -0
  21. package/dist/components/linetimeseriechart/linetimeseriechart.component.d.ts.map +1 -0
  22. package/dist/components/linetimeseriechart/linetimeseriechart.component.js +249 -0
  23. package/dist/components/selectv2/Selectv2.component.d.ts.map +1 -1
  24. package/dist/components/selectv2/Selectv2.component.js +11 -6
  25. package/dist/components/steppers/Stepper.component.d.ts.map +1 -1
  26. package/dist/components/steppers/Stepper.component.js +9 -8
  27. package/dist/components/toast/ToastProvider.d.ts.map +1 -1
  28. package/dist/components/toast/ToastProvider.js +4 -5
  29. package/dist/components/vegachartv2/SyncedCursorCharts.d.ts.map +1 -1
  30. package/dist/components/vegachartv2/SyncedCursorCharts.js +3 -5
  31. package/dist/index.d.ts +1 -0
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +1 -0
  34. package/dist/next.d.ts +2 -0
  35. package/dist/next.d.ts.map +1 -1
  36. package/dist/next.js +2 -0
  37. package/dist/style/theme.d.ts +1 -0
  38. package/dist/style/theme.d.ts.map +1 -1
  39. package/dist/style/theme.js +28 -0
  40. package/package.json +2 -2
  41. package/src/lib/components/accordion/Accordion.test.tsx +8 -16
  42. package/src/lib/components/barchartv2/Barchart.component.test.tsx +117 -111
  43. package/src/lib/components/barchartv2/Barchart.component.tsx +54 -7
  44. package/src/lib/components/barchartv2/utils.test.ts +127 -2
  45. package/src/lib/components/barchartv2/utils.ts +103 -19
  46. package/src/lib/components/chartlegend/ChartLegend.tsx +113 -0
  47. package/src/lib/components/chartlegend/ChartLegendWrapper.tsx +85 -0
  48. package/src/lib/components/date/FormattedDateTime.spec.tsx +24 -0
  49. package/src/lib/components/date/FormattedDateTime.tsx +36 -2
  50. package/src/lib/components/healthselectorv2/HealthSelector.component.test.tsx +10 -10
  51. package/src/lib/components/icon/Icon.component.tsx +48 -60
  52. package/src/lib/components/infomessage/InfoMessageUtils.test.tsx +0 -1
  53. package/src/lib/components/inlineinput/InlineInput.test.tsx +28 -22
  54. package/src/lib/components/inputlist/InputList.test.tsx +22 -21
  55. package/src/lib/components/linetemporalchart/ChartUtil.test.ts +5 -4
  56. package/src/lib/components/linetimeseriechart/linetimeseriechart.component.tsx +502 -0
  57. package/src/lib/components/searchinput/SearchInput.test.tsx +3 -7
  58. package/src/lib/components/selectv2/Selectv2.component.tsx +13 -5
  59. package/src/lib/components/selectv2/selectv2.test.tsx +70 -61
  60. package/src/lib/components/steppers/Stepper.component.tsx +10 -8
  61. package/src/lib/components/tablev2/TableSync.test.tsx +8 -12
  62. package/src/lib/components/tablev2/TableUtils.test.ts +6 -3
  63. package/src/lib/components/tablev2/Tablev2.test.tsx +38 -40
  64. package/src/lib/components/toast/ToastProvider.tsx +14 -6
  65. package/src/lib/components/toggle/Toggle.test.tsx +1 -1
  66. package/src/lib/components/vegachartv2/SyncedCursorCharts.tsx +5 -7
  67. package/src/lib/index.ts +1 -0
  68. package/src/lib/next.ts +2 -0
  69. package/src/lib/style/theme.ts +29 -0
  70. package/stories/BarChart/barchart.stories.tsx +387 -129
  71. package/stories/format.mdx +4 -2
  72. package/stories/linetimeseriechart.stories.tsx +485 -0
  73. package/tsconfig.json +0 -1
@@ -1,15 +1,11 @@
1
- import { screen, render as testingRender } from '@testing-library/react';
1
+ import { act, screen, render as testingRender, waitFor } from '@testing-library/react';
2
2
  import userEvent from '@testing-library/user-event';
3
3
  import React, { useState, useRef } from 'react';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
5
4
  import { Option, Select, SelectRef } from '../selectv2/Selectv2.component';
5
+ import { GroupTypeBase, OptionTypeBase } from 'react-select';
6
6
 
7
7
  const render = (args) => {
8
- return testingRender(
9
- <QueryClientProvider client={new QueryClient()}>
10
- {args}
11
- </QueryClientProvider>,
12
- );
8
+ return testingRender(args);
13
9
  };
14
10
 
15
11
  const generateOptionsData = (n: number) =>
@@ -71,30 +67,35 @@ describe('SelectV2', () => {
71
67
  };
72
68
 
73
69
  it('should throw error if <Option/> is outside <Select/>', () => {
70
+ // mock console.error as this is the only way to silent expected error thrown by the component
71
+ const consoleErrorFn = jest.spyOn(console, 'error').mockImplementation(() => jest.fn());
74
72
  expect(() => render(<Option value="Option 1" />)).toThrowError();
73
+ consoleErrorFn.mockRestore();
75
74
  });
76
75
 
77
- it('should open/close on click', () => {
76
+ it('should open/close on click', async () => {
78
77
  render(<SelectWrapper />);
78
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
79
79
  const select = selectors.select();
80
80
  expect(select).toBeInTheDocument();
81
81
  let options = selectors.options();
82
82
  expect(options).toHaveLength(0);
83
83
 
84
84
  // should open on click
85
- userEvent.click(select);
85
+ await act(() => userEvent.click(select));
86
86
  simpleOptions.forEach((opt) => {
87
87
  const option = selectors.option(opt.props.label);
88
88
  expect(option).toBeInTheDocument();
89
89
  });
90
90
 
91
- userEvent.click(select);
91
+ await act(() => userEvent.click(select));
92
92
  options = selectors.options();
93
93
  expect(options).toHaveLength(0);
94
94
  });
95
95
 
96
- it('should open/close with keyboard', () => {
96
+ it('should open/close with keyboard', async () => {
97
97
  render(<SelectWrapper />);
98
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
98
99
  const select = selectors.select();
99
100
  expect(select).toBeInTheDocument();
100
101
  const options = selectors.options();
@@ -102,7 +103,7 @@ describe('SelectV2', () => {
102
103
 
103
104
  // should open on Enter
104
105
  userEvent.tab();
105
- userEvent.keyboard('{Enter}');
106
+ await act(() => userEvent.keyboard('{Enter}'));
106
107
  simpleOptions.forEach((opt) => {
107
108
  const option = selectors.option(opt.props.label);
108
109
  expect(option).toBeInTheDocument();
@@ -121,13 +122,14 @@ describe('SelectV2', () => {
121
122
  });
122
123
  });
123
124
 
124
- it('should display custom placeholder', () => {
125
+ it('should display custom placeholder', async () => {
125
126
  const placeholder = 'My placeholder...';
126
127
  render(<SelectWrapper placeholder={placeholder} />);
128
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
127
129
  expect(screen.getByText(placeholder)).toBeInTheDocument();
128
130
  });
129
131
 
130
- it('should be disabled', () => {
132
+ it('should be disabled', async () => {
131
133
  render(
132
134
  <SelectWrapper value="1" disabled={true}>
133
135
  {simpleOptions}
@@ -139,27 +141,29 @@ describe('SelectV2', () => {
139
141
  // use input instead of select because select will still trigger the open/close action
140
142
  // despite select container not being clickable and input being disabled
141
143
  const input = selectors.input();
142
- userEvent.click(input);
144
+ await act(() => userEvent.click(input));
143
145
  const options = selectors.options();
144
146
  expect(options).toHaveLength(0);
145
147
  });
146
148
 
147
- it('should display no option', () => {
149
+ it('should display no option', async () => {
148
150
  render(
149
151
  <SelectWrapper>
150
152
  <></>
151
153
  </SelectWrapper>,
152
154
  );
155
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
153
156
  const select = selectors.select();
154
- userEvent.click(select);
157
+ await act(() => userEvent.click(select));
155
158
  const noOptions = selectors.noOptions();
156
159
  expect(noOptions).toBeInTheDocument();
157
160
  });
158
161
 
159
- it('should filter and highlight on search', () => {
162
+ it('should filter and highlight on search', async () => {
160
163
  render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
164
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
161
165
  const select = selectors.select(true);
162
- userEvent.click(select);
166
+ await act(() => userEvent.click(select));
163
167
  const input = selectors.input();
164
168
 
165
169
  userEvent.type(input, '2');
@@ -169,25 +173,26 @@ describe('SelectV2', () => {
169
173
  expect(searchedText).toHaveTextContent('2');
170
174
  });
171
175
 
172
- it('should unfocus the search input when the select is closed', () => {
176
+ it('should unfocus the search input when the select is closed', async () => {
173
177
  render(<SelectWrapper>{optionsWithScrollSearchBar} </SelectWrapper>);
178
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
174
179
  const select = selectors.select(true);
175
- userEvent.click(select);
180
+ await act(() => userEvent.click(select));
176
181
  let input = selectors.input();
177
182
  expect(input).toHaveFocus();
178
183
  const option = selectors.option(/Item 1/);
179
- userEvent.click(option);
184
+ await act(() => userEvent.click(option));
180
185
  input = selectors.input();
181
186
  expect(input).not.toHaveFocus();
182
187
  });
183
188
 
184
- it('should be possible to use searchbar when option is selected', () => {
189
+ it('should be possible to use searchbar when option is selected', async () => {
185
190
  render(
186
191
  <SelectWrapper value="1">{optionsWithScrollSearchBar}</SelectWrapper>,
187
192
  );
188
193
  expect(screen.getByText(/Item 1/)).toBeVisible();
189
194
  const select = selectors.select(true);
190
- userEvent.click(select);
195
+ await act(() => userEvent.click(select));
191
196
  const input = selectors.input();
192
197
  userEvent.type(input, '2');
193
198
  expect(screen.queryByText(/Item 1/)).not.toBeInTheDocument();
@@ -195,47 +200,48 @@ describe('SelectV2', () => {
195
200
  expect(options).toHaveLength(1);
196
201
  });
197
202
 
198
- it('should select/unselect option with keyboard', () => {
203
+ it('should select/unselect option with keyboard', async () => {
199
204
  render(<SelectWrapper />);
205
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
200
206
  const select = selectors.select();
201
207
  userEvent.tab();
202
- userEvent.keyboard('{ArrowDown}');
208
+ act(() => userEvent.keyboard('{ArrowDown}'));
203
209
 
204
210
  // should select first option
205
- userEvent.keyboard('{Enter}');
211
+ await act(() => userEvent.keyboard('{Enter}'));
206
212
  expect(select).toHaveTextContent('Item 0');
207
213
 
208
214
  // should select second option
209
215
  userEvent.tab();
210
- userEvent.keyboard('{ArrowDown}');
211
- userEvent.keyboard('{ArrowDown}');
216
+ await act(() => userEvent.keyboard('{ArrowDown}'));
217
+ await act(() => userEvent.keyboard('{ArrowDown}'));
212
218
 
213
- userEvent.keyboard('{Enter}');
219
+ await act(() => userEvent.keyboard('{Enter}'));
214
220
  expect(select).toHaveTextContent('Item 1');
215
221
  });
216
222
 
217
- it('should scroll to selected value when opening select', () => {
223
+ it('should scroll to selected value when opening select', async () => {
218
224
  render(
219
225
  <SelectWrapper value={optionsWithScrollSearchBar[9].props.value}>
220
226
  {optionsWithScrollSearchBar}
221
227
  </SelectWrapper>,
222
228
  );
223
229
  const select = selectors.select(true);
224
- userEvent.click(select);
230
+ await act(() => userEvent.click(select));
225
231
  const option = selectors.option(/Item 9/);
226
232
  expect(screen.queryByRole('option', { name: /Item 1/i })).toBeNull();
227
233
  expect(option).toBeVisible();
228
234
  });
229
235
 
230
- it('should be able to reset the value', () => {
236
+ it('should be able to reset the value', async () => {
231
237
  render(<SelectReset>{simpleOptions}</SelectReset>);
232
238
  const button = screen.getByText(/reset/);
233
- userEvent.click(button);
239
+ await act(() => userEvent.click(button));
234
240
  const select = selectors.select();
235
241
  expect(select).toHaveTextContent('Select...');
236
242
  });
237
243
 
238
- it('should not be possible to select an option if it is disabled', () => {
244
+ it('should not be possible to select an option if it is disabled', async () => {
239
245
  render(
240
246
  <SelectWrapper>
241
247
  <Option value="1" disabled>
@@ -245,15 +251,15 @@ describe('SelectV2', () => {
245
251
  </SelectWrapper>,
246
252
  );
247
253
  const select = selectors.select();
248
- userEvent.click(select);
254
+ await act(() => userEvent.click(select));
249
255
  const option = selectors.option(/Item 1/);
250
256
 
251
- userEvent.click(option);
257
+ await act(() => userEvent.click(option));
252
258
  const option2 = selectors.option(/Item 2/);
253
259
  expect(option2).toBeVisible();
254
260
  });
255
261
 
256
- it('should display a tooltip if the option is disabled with a reason', () => {
262
+ it('should display a tooltip if the option is disabled with a reason', async () => {
257
263
  render(
258
264
  <SelectWrapper>
259
265
  <Option value="1" disabled disabledReason="This option is disabled">
@@ -262,10 +268,10 @@ describe('SelectV2', () => {
262
268
  </SelectWrapper>,
263
269
  );
264
270
  const select = selectors.select();
265
- userEvent.click(select);
271
+ await act(() => userEvent.click(select));
266
272
  const option = selectors.option(/Item 1/);
267
273
  expect(option).toHaveAttribute('aria-disabled', 'true');
268
- userEvent.hover(option);
274
+ await act(() => userEvent.hover(option));
269
275
  const tooltip = screen.getByText(/This option is disabled/);
270
276
  expect(tooltip).toBeInTheDocument();
271
277
  });
@@ -309,9 +315,9 @@ describe('SelectV2', () => {
309
315
  // It's not our case here, so it makes thing difficult to select the right select
310
316
  // I workaround this by using setting the aria-label to the select container (cf: test below)
311
317
  const singleSelect = screen.getByRole('listbox');
312
- await userEvent.click(singleSelect);
318
+ await act(() => userEvent.click(singleSelect));
313
319
 
314
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
320
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
315
321
  });
316
322
 
317
323
  it('should be testable if we have several select', async () => {
@@ -372,13 +378,13 @@ describe('SelectV2', () => {
372
378
 
373
379
  render(<MyWrapperWith2Select />);
374
380
 
375
- await userEvent.click(screen.getByLabelText(/select account/i));
381
+ await act(() => userEvent.click(screen.getByLabelText(/select account/i)));
376
382
 
377
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
383
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
378
384
 
379
- await userEvent.click(screen.getByLabelText(/select user/i));
385
+ await act(() => userEvent.click(screen.getByLabelText(/select user/i)));
380
386
 
381
- await userEvent.click(screen.getByRole('option', { name: /user 1/i }));
387
+ await act(() => userEvent.click(screen.getByRole('option', { name: /user 1/i })));
382
388
  });
383
389
 
384
390
  it('should be testable even if we have several select with the same value, the placeholder should be different', async () => {
@@ -439,8 +445,8 @@ describe('SelectV2', () => {
439
445
 
440
446
  render(<MyWrapperWith2Select />);
441
447
 
442
- await userEvent.click(screen.getByLabelText(/select account/i));
443
- await userEvent.click(screen.getByLabelText(/Select Second Account/i));
448
+ await act(() => userEvent.click(screen.getByLabelText(/select account/i)));
449
+ await act(() => userEvent.click(screen.getByLabelText(/Select Second Account/i)));
444
450
 
445
451
  /**
446
452
  * This is possible because only 1 select can be open at a time
@@ -450,13 +456,13 @@ describe('SelectV2', () => {
450
456
  * const selectContainer = select?.parentElement?.parentElement;
451
457
  * const option = within(selectContainer).getByRole('option', { name: /account 1/i });
452
458
  */
453
- await userEvent.click(screen.getByRole('option', { name: /account 1/i }));
459
+ await act(() => userEvent.click(screen.getByRole('option', { name: /account 1/i })));
454
460
  });
455
461
 
456
462
  describe('Ref API', () => {
457
463
  it('should expose focus method via ref', async () => {
458
464
  const RefTestComponent = () => {
459
- const selectRef = useRef<SelectRef>(null);
465
+ const selectRef = useRef<SelectRef<OptionTypeBase, boolean, GroupTypeBase<OptionTypeBase>>>(null);
460
466
  const [value, setValue] = useState<string>('');
461
467
 
462
468
  return (
@@ -478,13 +484,13 @@ describe('SelectV2', () => {
478
484
  render(<RefTestComponent />);
479
485
  expect(selectors.input()).not.toHaveFocus();
480
486
 
481
- userEvent.click(screen.getByRole('button', { name: /Focus/i }));
487
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Focus/i })));
482
488
  expect(selectors.input()).toHaveFocus();
483
489
  });
484
490
 
485
491
  it('should expose openMenu and closeMenu methods via ref', async () => {
486
492
  const RefTestComponent = () => {
487
- const selectRef = useRef<SelectRef>(null);
493
+ const selectRef = useRef<SelectRef<OptionTypeBase, boolean, GroupTypeBase<OptionTypeBase>>>(null);
488
494
  const [value, setValue] = useState<string>('');
489
495
 
490
496
  return (
@@ -511,14 +517,14 @@ describe('SelectV2', () => {
511
517
  render(<RefTestComponent />);
512
518
  expect(selectors.options()).toHaveLength(0);
513
519
 
514
- userEvent.click(screen.getByRole('button', { name: /Open Menu/i }));
520
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Open Menu/i })));
515
521
  expect(selectors.options().length).toBeGreaterThan(0);
516
522
  simpleOptions.forEach((opt) => {
517
523
  const option = selectors.option(opt.props.label);
518
524
  expect(option).toBeInTheDocument();
519
525
  });
520
526
 
521
- userEvent.click(screen.getByRole('button', { name: /Close Menu/i }));
527
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Close Menu/i })));
522
528
  expect(selectors.options()).toHaveLength(0);
523
529
  });
524
530
 
@@ -527,7 +533,7 @@ describe('SelectV2', () => {
527
533
 
528
534
  const RefTestComponent = () => {
529
535
  const [value, setValue] = useState('');
530
- const selectRef = useRef<SelectRef>(null);
536
+ const selectRef = useRef<SelectRef<OptionTypeBase, boolean, GroupTypeBase<OptionTypeBase>>>(null);
531
537
 
532
538
  return (
533
539
  <div>
@@ -565,19 +571,22 @@ describe('SelectV2', () => {
565
571
 
566
572
  render(<RefTestComponent />);
567
573
 
568
- const select = selectors.select();
574
+ let select;
575
+ await act(() => {
576
+ select = selectors.select();
577
+ });
569
578
  expect(select).toHaveTextContent('Select with ref');
570
579
 
571
- userEvent.click(screen.getByRole('button', { name: /Set Value/i }));
580
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Set Value/i })));
572
581
  expect(select).toHaveTextContent('Item 0');
573
582
 
574
- userEvent.click(screen.getByRole('button', { name: /Clear/i }));
583
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Clear/i })));
575
584
  expect(select).toHaveTextContent('Select with ref');
576
585
  });
577
586
 
578
587
  it('should expose blur method via ref', async () => {
579
588
  const RefTestComponent = () => {
580
- const selectRef = useRef<SelectRef>(null);
589
+ const selectRef = useRef<SelectRef<OptionTypeBase, boolean, GroupTypeBase<OptionTypeBase>>>(null);
581
590
  const [value, setValue] = useState<string>('');
582
591
 
583
592
  return (
@@ -599,10 +608,10 @@ describe('SelectV2', () => {
599
608
 
600
609
  render(<RefTestComponent />);
601
610
 
602
- userEvent.click(screen.getByRole('button', { name: /Focus/i }));
611
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Focus/i })));
603
612
  expect(selectors.input()).toHaveFocus();
604
613
 
605
- userEvent.click(screen.getByRole('button', { name: /Blur/i }));
614
+ await act(() => userEvent.click(screen.getByRole('button', { name: /Blur/i })));
606
615
  expect(selectors.input()).not.toHaveFocus();
607
616
  });
608
617
  });
@@ -1,5 +1,5 @@
1
1
  /// <reference path="./Stepper.component.d.ts" />
2
- import { createContext, useContext, useState } from 'react';
2
+ import { createContext, useContext, useState, useCallback, useMemo } from 'react';
3
3
  import { Steppers } from './Steppers.component';
4
4
  import { Box } from '../box/Box';
5
5
  export interface StepperContextType {
@@ -33,19 +33,21 @@ export const Stepper: Stepper = ({ steps }) => {
33
33
  props: Record<string, unknown>;
34
34
  }>({ step: 0, props: {} });
35
35
 
36
- const next = (props: Record<string, unknown>) => {
37
- setStepProps({ step: stepProps.step + 1, props });
38
- };
36
+ const next = useCallback((props: Record<string, unknown>) => {
37
+ setStepProps(current => ({ step: current.step + 1, props }));
38
+ }, []);
39
39
 
40
- const prev = (props: Record<string, unknown>) => {
41
- setStepProps({ step: stepProps.step - 1, props });
42
- };
40
+ const prev = useCallback((props: Record<string, unknown>) => {
41
+ setStepProps(current => ({ step: current.step - 1, props }));
42
+ }, []);
43
43
 
44
44
  const { Component } = steps[stepProps.step];
45
45
  const StepperContext = window.StepperContext;
46
46
 
47
+ const stepperValue = useMemo(() => ({ next, prev }), [next, prev]);
48
+
47
49
  return (
48
- <StepperContext.Provider value={{ next, prev }}>
50
+ <StepperContext.Provider value={stepperValue}>
49
51
  <Box display="flex" gap={32} flex={1} height="100%">
50
52
  <Steppers
51
53
  activeStep={stepProps.step}
@@ -1,31 +1,27 @@
1
- import { fireEvent, render, screen } from '@testing-library/react';
2
- import React from 'react';
1
+ import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
3
2
  import { TableSync } from './TableSync';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
5
3
 
6
4
  describe('TableSync', () => {
7
- it('should render correctly', () => {
5
+ it('should render correctly', async () => {
8
6
  const onSync = jest.fn();
9
7
  render(
10
- <QueryClientProvider client={new QueryClient()}>
11
- <TableSync onSync={onSync} />
12
- </QueryClientProvider>,
8
+ <TableSync onSync={onSync} tooltipOverlay='sync' />
13
9
  );
10
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
14
11
 
15
12
  const button = screen.getByRole('button');
16
13
  expect(button).toBeInTheDocument();
17
14
  });
18
15
 
19
- it('should call onSync when clicked', () => {
16
+ it('should call onSync when clicked', async () => {
20
17
  const onSync = jest.fn();
21
18
  render(
22
- <QueryClientProvider client={new QueryClient()}>
23
- <TableSync onSync={onSync} />
24
- </QueryClientProvider>,
19
+ <TableSync onSync={onSync} tooltipOverlay='sync' />
25
20
  );
21
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
26
22
 
27
23
  const button = screen.getByRole('button');
28
- fireEvent.click(button);
24
+ await act(() => fireEvent.click(button));
29
25
  expect(onSync).toHaveBeenCalledTimes(1);
30
26
  });
31
27
  });
@@ -9,9 +9,12 @@ it('should return -1 or 1 to sort the status', () => {
9
9
  expect(result).toEqual(1);
10
10
  expect(result2).toEqual(-1);
11
11
  });
12
- it('should return undefine for the unknown status', () => {
13
- const result = compareHealth('invalidStatus', 'healthy');
14
- const result2 = compareHealth('none', 'invalidStatus');
12
+ it('should return undefined for the unknown status', () => {
13
+ const consoleErrorMockHandle = jest.spyOn(console, 'error').mockImplementation(() => {});
14
+ const result = compareHealth('invalidStatus' as any, 'healthy');
15
+ const result2 = compareHealth('none', 'invalidStatus' as any);
16
+ expect(consoleErrorMockHandle).toHaveBeenCalled();
17
+ consoleErrorMockHandle.mockRestore();
15
18
  expect(result).toEqual(undefined);
16
19
  expect(result2).toEqual(undefined);
17
20
  });
@@ -1,7 +1,5 @@
1
- import { Table } from './Tablev2.component';
2
- import React from 'react';
3
- import { render } from '@testing-library/react';
4
- import { QueryClient, QueryClientProvider } from 'react-query';
1
+ import { Table, TableProps } from './Tablev2.component';
2
+ import { render, screen, waitFor } from '@testing-library/react';
5
3
 
6
4
  jest.mock('./TableUtils', () => ({
7
5
  ...jest.requireActual('./TableUtils'),
@@ -43,7 +41,7 @@ const data = [
43
41
  health: 'healthy',
44
42
  },
45
43
  ];
46
- const columns = [
44
+ const columns: TableProps['columns'] = [
47
45
  {
48
46
  Header: 'First Name',
49
47
  accessor: 'firstName',
@@ -66,17 +64,17 @@ const columns = [
66
64
  describe('TableV2', () => {
67
65
  test('it should display all the data', async () => {
68
66
  const { getAllByRole } = render(
69
- <QueryClientProvider client={new QueryClient()}>
70
- <div>
71
- <Table columns={columns} data={data} defaultSortingKey={'health'}>
72
- <Table.SingleSelectableContent
73
- rowHeight="h40"
74
- separationLineVariant="backgroundLevel3"
75
- />
76
- </Table>
77
- </div>
78
- </QueryClientProvider>,
67
+ <div>
68
+ <Table columns={columns} data={data} defaultSortingKey={'health'}>
69
+ <Table.SingleSelectableContent
70
+ rowHeight="h40"
71
+ separationLineVariant="backgroundLevel3"
72
+ />
73
+ </Table>
74
+ </div>
79
75
  );
76
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
77
+
80
78
  // we check that the table is displaying all the data
81
79
  const rows = getAllByRole('row');
82
80
  expect(rows[4]).toHaveTextContent(/Ninette/i);
@@ -85,17 +83,17 @@ describe('TableV2', () => {
85
83
  });
86
84
  test('it should sort by defaultSortingKey', async () => {
87
85
  const { getAllByRole } = render(
88
- <QueryClientProvider client={new QueryClient()}>
89
- <div>
90
- <Table columns={columns} data={data} defaultSortingKey={'firstName'}>
91
- <Table.SingleSelectableContent
92
- rowHeight="h40"
93
- separationLineVariant="backgroundLevel3"
94
- />
95
- </Table>
96
- </div>
97
- </QueryClientProvider>,
86
+ <div>
87
+ <Table columns={columns} data={data} defaultSortingKey={'firstName'}>
88
+ <Table.SingleSelectableContent
89
+ rowHeight="h40"
90
+ separationLineVariant="backgroundLevel3"
91
+ />
92
+ </Table>
93
+ </div>
98
94
  );
95
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
96
+
99
97
  // we check that the table is displaying all the data
100
98
  const rows = getAllByRole('row');
101
99
  expect(rows[1]).toHaveTextContent(/ninette/i);
@@ -104,22 +102,22 @@ describe('TableV2', () => {
104
102
  });
105
103
  test('it should filterGlobally', async () => {
106
104
  const { getAllByRole } = render(
107
- <QueryClientProvider client={new QueryClient()}>
108
- <div>
109
- <Table
110
- columns={columns}
111
- data={data}
112
- defaultSortingKey={'firstName'}
113
- globalFilter="an"
114
- >
115
- <Table.SingleSelectableContent
116
- rowHeight="h40"
117
- separationLineVariant="backgroundLevel3"
118
- />
119
- </Table>
120
- </div>
121
- </QueryClientProvider>,
105
+ <div>
106
+ <Table
107
+ columns={columns}
108
+ data={data}
109
+ defaultSortingKey={'firstName'}
110
+ globalFilter="an"
111
+ >
112
+ <Table.SingleSelectableContent
113
+ rowHeight="h40"
114
+ separationLineVariant="backgroundLevel3"
115
+ />
116
+ </Table>
117
+ </div>
122
118
  );
119
+ await waitFor(() => screen.queryAllByRole('img', { hidden: true }));
120
+
123
121
  // we check that the table is displaying all the data
124
122
  const rows = getAllByRole('row');
125
123
  expect(rows[1]).toHaveTextContent(/an/i); //first name yoh-an-n
@@ -1,4 +1,4 @@
1
- import { ReactNode, createContext, useContext, useState } from 'react';
1
+ import { ReactNode, createContext, useCallback, useContext, useMemo, useState } from 'react';
2
2
  import { Toast, ToastProps } from './Toast.component';
3
3
 
4
4
  export type ToastContextState = Omit<ToastProps, 'onClose'>;
@@ -14,20 +14,27 @@ export const ToastContext = createContext<ToastContextType | undefined>(
14
14
  interface ToastProviderProps {
15
15
  children: ReactNode;
16
16
  }
17
+
17
18
  export const ToastProvider: React.FC<
18
19
  React.PropsWithChildren<ToastProviderProps>
19
20
  > = ({ children }) => {
20
21
  const [toastProps, setToastProps] = useState<ToastContextState | null>(null);
21
22
 
22
- const showToast = (toastProps: ToastContextState) => {
23
- setToastProps(toastProps);
24
- };
23
+ const toastCtxValue = useMemo(
24
+ () => ({ showToast: setToastProps }),
25
+ [],
26
+ );
27
+
28
+ const closeToast = useCallback(
29
+ () => setToastProps(null),
30
+ []
31
+ );
25
32
 
26
33
  return (
27
- <ToastContext.Provider value={{ showToast }}>
34
+ <ToastContext.Provider value={toastCtxValue}>
28
35
  {children}
29
36
  {toastProps && (
30
- <Toast {...toastProps} onClose={() => setToastProps(null)} />
37
+ <Toast {...toastProps} onClose={closeToast} />
31
38
  )}
32
39
  </ToastContext.Provider>
33
40
  );
@@ -38,5 +45,6 @@ export const useToast = () => {
38
45
  if (!context) {
39
46
  throw new Error('useToast must be used within a ToastProvider');
40
47
  }
48
+
41
49
  return context;
42
50
  };
@@ -1,5 +1,5 @@
1
1
  import { render, screen } from '@testing-library/react';
2
- import React, { useState } from 'react';
2
+ import { useState } from 'react';
3
3
  import { Props, Toggle } from './Toggle.component';
4
4
  import userEvent from '@testing-library/user-event';
5
5
 
@@ -1,4 +1,4 @@
1
- import { useState, createContext, useContext } from 'react';
1
+ import { useState, createContext, useContext, useMemo, useCallback } from 'react';
2
2
  export const SyncedCursorChartsContext = createContext<{
3
3
  cursorX: number;
4
4
  setCursorX: (cursorX: number) => void;
@@ -17,13 +17,11 @@ export const useCursorX = (): {
17
17
  };
18
18
  export function SyncedCursorCharts({ children }: { children: JSX.Element }) {
19
19
  const [cursorX, setCursorX] = useState(0);
20
+
21
+ const contextValue = useMemo(() => ({cursorX, setCursorX}), [cursorX]);
22
+
20
23
  return (
21
- <SyncedCursorChartsContext.Provider
22
- value={{
23
- cursorX,
24
- setCursorX,
25
- }}
26
- >
24
+ <SyncedCursorChartsContext.Provider value={contextValue}>
27
25
  {children}
28
26
  </SyncedCursorChartsContext.Provider>
29
27
  );