@loadsmart/loadsmart-ui 5.10.1 → 5.11.1

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 (141) hide show
  1. package/dist/components/Calendar/Calendar.stories.d.ts +2 -7
  2. package/dist/components/Calendar/Date.helper.d.ts +47 -12
  3. package/dist/components/Dropdown/Dropdown.stories.d.ts +4 -1
  4. package/dist/components/Loaders/LoadingBar.stories.d.ts +1 -1
  5. package/dist/index.js +445 -295
  6. package/dist/index.js.map +1 -1
  7. package/dist/testing/SelectEvent/SelectEvent.d.ts +2 -0
  8. package/dist/testing/index.js +1 -1
  9. package/dist/testing/index.js.map +1 -1
  10. package/dist/tests/generator.d.ts +35 -0
  11. package/dist/tests/renderer.d.ts +10 -0
  12. package/package.json +8 -7
  13. package/src/common/CloseButton/CloseButton.tsx +11 -7
  14. package/src/common/SelectionWrapper.tsx +7 -7
  15. package/src/components/Accordion/Accordion.stories.tsx +1 -1
  16. package/src/components/Accordion/Accordion.test.tsx +2 -2
  17. package/src/components/Accordion/Accordion.tsx +28 -22
  18. package/src/components/Banner/Banner.test.tsx +2 -2
  19. package/src/components/Banner/Banner.tsx +2 -2
  20. package/src/components/Breadcrumbs/Breadbrumbs.test.tsx +2 -2
  21. package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -2
  22. package/src/components/Breadcrumbs/Breadcrumbs.tsx +1 -1
  23. package/src/components/Button/Button.test.tsx +2 -2
  24. package/src/components/Button/Button.tsx +20 -17
  25. package/src/components/Calendar/Calendar.stories.tsx +4 -2
  26. package/src/components/Calendar/Calendar.test.tsx +3 -3
  27. package/src/components/Calendar/Calendar.tsx +8 -4
  28. package/src/components/Calendar/Date.helper.test.ts +463 -15
  29. package/src/components/Calendar/Date.helper.ts +106 -45
  30. package/src/components/Calendar/PickerModeToggle.tsx +6 -3
  31. package/src/components/Calendar/Pickers/DayPicker.test.tsx +2 -2
  32. package/src/components/Calendar/Pickers/DayPicker.tsx +1 -1
  33. package/src/components/Calendar/Pickers/MonthPicker.test.tsx +2 -2
  34. package/src/components/Calendar/Pickers/MonthPicker.tsx +1 -1
  35. package/src/components/Calendar/Pickers/PickerButton.tsx +39 -29
  36. package/src/components/Calendar/Pickers/YearPicker.test.tsx +9 -7
  37. package/src/components/Calendar/Pickers/YearPicker.tsx +1 -1
  38. package/src/components/Card/Card.stories.tsx +1 -1
  39. package/src/components/Card/Card.test.tsx +2 -2
  40. package/src/components/Card/Card.tsx +9 -6
  41. package/src/components/Card/CardTitle.tsx +3 -4
  42. package/src/components/Checkbox/Checkbox.test.tsx +2 -2
  43. package/src/components/Checkbox/Checkbox.tsx +26 -14
  44. package/src/components/DatePicker/DatePicker.test.tsx +2 -2
  45. package/src/components/DatePicker/DateRangePicker.stories.tsx +6 -1
  46. package/src/components/DatePicker/DateRangePicker.test.tsx +2 -2
  47. package/src/components/Dialog/Dialog.test.tsx +2 -2
  48. package/src/components/Dialog/Dialog.tsx +5 -5
  49. package/src/components/DragDropFile/components/DropZone.test.tsx +1 -1
  50. package/src/components/DragDropFile/styles.tsx +11 -6
  51. package/src/components/Drawer/Drawer.test.tsx +1 -1
  52. package/src/components/Drawer/Drawer.tsx +6 -6
  53. package/src/components/Dropdown/Dropdown.stories.tsx +10 -5
  54. package/src/components/Dropdown/Dropdown.test.tsx +14 -16
  55. package/src/components/Dropdown/DropdownMenu.tsx +28 -15
  56. package/src/components/Dropdown/DropdownTrigger.tsx +34 -24
  57. package/src/components/EmptyState/EmptyState.test.tsx +1 -1
  58. package/src/components/ErrorMessage/ErrorMessage.test.tsx +1 -1
  59. package/src/components/HighlightMatch/HighlightMatch.test.tsx +1 -1
  60. package/src/components/HighlightMatch/HighlightMatch.tsx +1 -2
  61. package/src/components/IconFactory/IconFactory.test.tsx +2 -2
  62. package/src/components/Label/Label.test.tsx +2 -2
  63. package/src/components/Label/Label.tsx +3 -3
  64. package/src/components/Link/Link.test.tsx +2 -2
  65. package/src/components/Link/Link.tsx +13 -9
  66. package/src/components/Loaders/LoadingBar.stories.tsx +2 -2
  67. package/src/components/Loaders/LoadingBar.test.tsx +1 -1
  68. package/src/components/Loaders/LoadingBar.tsx +2 -2
  69. package/src/components/Loaders/LoadingDots.test.tsx +1 -1
  70. package/src/components/Loaders/Spinner.test.tsx +2 -2
  71. package/src/components/Modal/Modal.test.tsx +2 -2
  72. package/src/components/Modal/Modal.tsx +12 -7
  73. package/src/components/Pagination/Pagination.test.tsx +1 -1
  74. package/src/components/Popover/Popover.test.tsx +2 -2
  75. package/src/components/ProgressBar/ProgressBar.test.tsx +1 -1
  76. package/src/components/ProgressBar/ProgressBar.tsx +6 -4
  77. package/src/components/Radio/Radio.test.tsx +2 -2
  78. package/src/components/Radio/Radio.tsx +19 -11
  79. package/src/components/Section/Section.test.tsx +2 -2
  80. package/src/components/Section/Section.tsx +8 -6
  81. package/src/components/Section/Sections.stories.tsx +1 -1
  82. package/src/components/Select/Select.fixtures.ts +1 -1
  83. package/src/components/Select/Select.stories.tsx +2 -2
  84. package/src/components/Select/Select.test.tsx +162 -155
  85. package/src/components/Select/SelectEmpty.tsx +5 -4
  86. package/src/components/Select/SelectTrigger.tsx +11 -6
  87. package/src/components/Select/useSelect.helpers.test.ts +1 -1
  88. package/src/components/SideNavigation/Logo/Logo.test.tsx +2 -2
  89. package/src/components/SideNavigation/Menu/Menu.test.tsx +2 -2
  90. package/src/components/SideNavigation/Menu/Menu.tsx +3 -3
  91. package/src/components/SideNavigation/Menu/MenuBaseItem.tsx +5 -4
  92. package/src/components/SideNavigation/Menu/MenuExpandable.tsx +3 -2
  93. package/src/components/SideNavigation/Separator/Separator.test.tsx +1 -1
  94. package/src/components/SideNavigation/SideNavigation.test.tsx +2 -2
  95. package/src/components/Steps/ProgressSteps/ProgressStep.tsx +39 -31
  96. package/src/components/Steps/Steps.fixtures.ts +1 -1
  97. package/src/components/Steps/Steps.test.tsx +2 -2
  98. package/src/components/Steps/useStep.test.tsx +1 -1
  99. package/src/components/Switch/Switch.test.tsx +1 -1
  100. package/src/components/Switch/Switch.tsx +18 -6
  101. package/src/components/Table/Table.fixtures.ts +1 -1
  102. package/src/components/Table/Table.test.tsx +1 -1
  103. package/src/components/Table/Table.tsx +2 -2
  104. package/src/components/TablePagination/TablePagination.test.tsx +1 -1
  105. package/src/components/Tabs/Tabs.test.tsx +1 -1
  106. package/src/components/Tabs/Tabs.tsx +32 -26
  107. package/src/components/Tag/Tag.stories.tsx +1 -1
  108. package/src/components/Tag/Tag.test.tsx +2 -2
  109. package/src/components/Tag/Tag.tsx +44 -35
  110. package/src/components/Text/Text.test.tsx +2 -2
  111. package/src/components/TextField/TextField.test.tsx +1 -1
  112. package/src/components/TextField/TextField.tsx +22 -15
  113. package/src/components/Textarea/Textarea.test.tsx +1 -1
  114. package/src/components/Textarea/Textarea.tsx +22 -17
  115. package/src/components/Toast/Toast.test.tsx +2 -2
  116. package/src/components/Toast/Toast.tsx +3 -3
  117. package/src/components/ToggleGroup/Toggle.test.tsx +2 -2
  118. package/src/components/ToggleGroup/Toggle.tsx +7 -7
  119. package/src/components/ToggleGroup/ToggleGroup.stories.tsx +14 -12
  120. package/src/components/ToggleGroup/ToggleGroup.test.tsx +2 -2
  121. package/src/components/Tooltip/Tooltip.test.tsx +2 -2
  122. package/src/components/Tooltip/Tooltip.tsx +22 -20
  123. package/src/components/TopNavigation/Logo/Logo.test.tsx +2 -2
  124. package/src/components/TopNavigation/Menu/Menu.test.tsx +1 -1
  125. package/src/components/TopNavigation/Menu/MenuItemDropdown.tsx +1 -1
  126. package/src/components/TopNavigation/OpenSideNavButton/OpenSideNavButton.tsx +1 -1
  127. package/src/components/VisuallyHidden/VisuallyHidden.test.tsx +1 -1
  128. package/src/hooks/useClickOutside/useClickOutside.test.tsx +1 -1
  129. package/src/hooks/useDidMount/useDidMount.test.tsx +1 -1
  130. package/src/hooks/useFocusTrap/useFocusTrap.test.tsx +1 -1
  131. package/src/hooks/useFocusWithin/useFocusWithin.test.tsx +1 -1
  132. package/src/hooks/useHeightExpansionToggler/useHeightExpansionToggler.test.tsx +1 -1
  133. package/src/hooks/useSelectable/SelectableStrategy.test.ts +1 -1
  134. package/src/hooks/useSelectable/useSelectable.test.ts +1 -1
  135. package/src/styles/font.tsx +3 -3
  136. package/src/testing/SelectEvent/SelectEvent.test.tsx +2 -2
  137. package/src/testing/SelectEvent/SelectEvent.ts +87 -45
  138. package/src/tests/generator.ts +127 -0
  139. package/src/tests/renderer.tsx +39 -0
  140. package/src/tools/conditional.test.ts +1 -1
  141. package/src/utils/toolset/interleave.test.ts +1 -1
@@ -5,8 +5,8 @@ import { render } from '@testing-library/react'
5
5
 
6
6
  import { SelectableKeyTypeOptions, Fruit, FRUITS, USERS } from './Select.fixtures'
7
7
  import * as stories from './Select.stories'
8
- import generator from '../../../tests/generator'
9
- import renderer, { screen, fire, waitFor } from '../../../tests/renderer'
8
+ import generator from '../../tests/generator'
9
+ import renderer, { act, screen, fire, waitFor } from '../../tests/renderer'
10
10
  import selectEvent from '../../testing/SelectEvent'
11
11
 
12
12
  import type { SelectProps, Option } from './Select.types'
@@ -22,24 +22,6 @@ const {
22
22
  CreatableAsync,
23
23
  } = composeStories(stories)
24
24
 
25
- async function expandSelect(waitForOptionsToBeAvailable = false) {
26
- await waitFor(() => {
27
- expect(screen.getByTestId('select-trigger-handle')).toBeEnabled()
28
- })
29
-
30
- fire.click(screen.getByTestId('select-trigger-handle'))
31
-
32
- await waitFor(() => {
33
- screen.queryByRole('listbox')
34
- })
35
-
36
- if (waitForOptionsToBeAvailable) {
37
- await waitFor(() => {
38
- screen.getAllByRole('option')
39
- })
40
- }
41
- }
42
-
43
25
  describe('Select', () => {
44
26
  describe('Generic', () => {
45
27
  const setup = (overrides: Partial<SelectProps>) =>
@@ -55,23 +37,28 @@ describe('Select', () => {
55
37
  it('does not expand with the available options when search input is clicked', () => {
56
38
  setup({ disabled: true })
57
39
 
58
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
59
- expect(screen.getByTestId('select-trigger-search-field')).toBeDisabled()
40
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
60
41
 
61
- fire.click(screen.getByTestId('select-trigger-search-field'))
42
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
43
+ expect(searchInput).toBeDisabled()
62
44
 
63
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
45
+ fire.click(searchInput)
46
+
47
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
64
48
  })
65
49
 
66
50
  it('does not expand with the available options when trigger handle is clicked', () => {
67
51
  setup({ disabled: true })
68
52
 
69
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
70
- expect(screen.getByTestId('select-trigger-handle')).toBeDisabled()
53
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
54
+ const triggerHandle = screen.getByTestId('select-trigger-handle')
71
55
 
72
- fire.click(screen.getByTestId('select-trigger-handle'))
56
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
57
+ expect(triggerHandle).toBeDisabled()
73
58
 
74
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
59
+ fire.click(triggerHandle)
60
+
61
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
75
62
  })
76
63
  })
77
64
 
@@ -79,40 +66,38 @@ describe('Select', () => {
79
66
  it('expands with the available options when search input is clicked', async () => {
80
67
  setup({})
81
68
 
82
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
83
-
84
69
  await waitFor(() => {
85
70
  expect(screen.getByTestId('select-trigger-handle')).toBeEnabled()
86
71
  })
87
72
 
88
- fire.click(screen.getByTestId('select-trigger-search-field'))
73
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
74
+
75
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
89
76
 
90
- expect(await screen.findByRole('listbox')).toBeInTheDocument()
77
+ fire.click(searchInput)
91
78
 
92
- await waitFor(() => {
93
- screen.getAllByRole('option')
94
- })
79
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(true)
95
80
 
96
- const items = screen.getAllByRole('option')
81
+ const options = await selectEvent.getOptions(searchInput)
97
82
 
98
83
  for (let i = 0; i < FRUITS.length; i++) {
99
- expect(items[i]).toHaveTextContent(FRUITS[i].label)
84
+ expect(options[i]).toHaveTextContent(FRUITS[i].label)
100
85
  }
101
86
  })
102
87
 
103
88
  it('expands with the available options when trigger handle is clicked', async () => {
104
89
  setup({})
105
90
 
106
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
91
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
107
92
 
108
- await expandSelect(true)
93
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
109
94
 
110
- expect(screen.getByRole('listbox')).toBeInTheDocument()
95
+ await selectEvent.expand(searchInput)
111
96
 
112
- const items = screen.getAllByRole('option')
97
+ const options = await selectEvent.getOptions(searchInput)
113
98
 
114
99
  for (let i = 0; i < FRUITS.length; i++) {
115
- expect(items[i]).toHaveTextContent(FRUITS[i].label)
100
+ expect(options[i]).toHaveTextContent(FRUITS[i].label)
116
101
  }
117
102
  })
118
103
 
@@ -120,17 +105,19 @@ describe('Select', () => {
120
105
  render(<Playground options={undefined} />)
121
106
 
122
107
  const searchInput = screen.getByLabelText('Select your favorite fruit')
108
+ const triggerHandle = screen.getByTestId('select-trigger-handle')
123
109
 
124
- expect(screen.getByTestId('select-trigger-handle')).toBeDisabled()
125
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
110
+ expect(triggerHandle).toBeDisabled()
111
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
126
112
 
127
113
  userEvent.type(searchInput, generator.word())
128
114
 
129
115
  await selectEvent.expand(searchInput)
130
116
 
117
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(true)
118
+
131
119
  await waitFor(() => {
132
- expect(screen.getByTestId('select-trigger-handle')).toBeEnabled()
133
- expect(screen.queryByRole('listbox')).toBeInTheDocument()
120
+ expect(triggerHandle).toBeEnabled()
134
121
  })
135
122
  })
136
123
 
@@ -157,33 +144,32 @@ describe('Select', () => {
157
144
  }
158
145
  })
159
146
 
160
- it('expands when user enters a search string', async () => {
147
+ it('expands when user enters a search string', () => {
161
148
  setup({})
162
149
 
163
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
150
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
164
151
 
165
- fire.change(screen.getByTestId('select-trigger-search-field'), { target: { value: 'foo' } })
152
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
166
153
 
167
- await waitFor(() => expect(screen.queryByRole('listbox')).toBeInTheDocument())
154
+ fire.change(searchInput, { target: { value: 'foo' } })
155
+
156
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(true)
168
157
  })
169
158
 
170
159
  it('filters the available options when user enters a search string', async () => {
171
160
  setup({})
172
161
 
173
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
162
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
163
+ const searchedFruit = generator.pickone([...FRUITS])
174
164
 
175
- const indexToSearch = generator.natural({ min: 0, max: FRUITS.length - 1 })
176
- fire.change(screen.getByTestId('select-trigger-search-field'), {
177
- target: { value: FRUITS[indexToSearch].label },
165
+ fire.change(searchInput, {
166
+ target: { value: searchedFruit.label },
178
167
  })
179
168
 
180
- let items = [] as HTMLElement[]
181
- await waitFor(() => {
182
- items = screen.getAllByRole('option')
183
- })
169
+ const options = await selectEvent.getOptions(searchInput)
184
170
 
185
- expect(items.length).toBeGreaterThanOrEqual(1)
186
- expect(items[0]).toHaveTextContent(FRUITS[indexToSearch].label)
171
+ expect(options.length).toBeGreaterThanOrEqual(1)
172
+ expect(options[0]).toHaveTextContent(searchedFruit.label)
187
173
  })
188
174
 
189
175
  it('calls blur when focus is lost', async () => {
@@ -242,10 +228,11 @@ describe('Select', () => {
242
228
  })
243
229
 
244
230
  it('updates selected item after the initially selected item changes', async () => {
245
- const selectedFruit = generator.pickone([...FRUITS])
231
+ const [selectedFruit, newSelectedFruit] = generator.pickset([...FRUITS], 2)
246
232
  const props = {
247
233
  value: selectedFruit as Option,
248
234
  }
235
+
249
236
  const { rerender } = render(<Playground {...props} />)
250
237
 
251
238
  const searchInput = screen.getByLabelText('Select your favorite fruit')
@@ -256,7 +243,6 @@ describe('Select', () => {
256
243
 
257
244
  expect(selectedOptions[0]).toHaveTextContent(selectedFruit.label)
258
245
 
259
- const newSelectedFruit = generator.pickone([...FRUITS])
260
246
  const newProps = {
261
247
  value: newSelectedFruit as Option,
262
248
  }
@@ -316,19 +302,18 @@ describe('Select', () => {
316
302
 
317
303
  describe('Multi selection', () => {
318
304
  it('selects multiple options', async () => {
319
- const [firstOption, secondOption] = FRUITS
305
+ const [firstOption, secondOption] = generator.pickset([...FRUITS], 2)
306
+
320
307
  setup({ multiple: true })
321
308
 
322
309
  const searchInput = screen.getByLabelText('Select your favorite fruit')
323
310
  await selectEvent.select(firstOption.label, searchInput)
324
311
 
325
- expect(screen.getByTestId('select-trigger-clear-counter')).toHaveTextContent('1')
326
- expect(screen.getByTitle('1 selected option')).toBeInTheDocument()
312
+ expect(screen.getByTitle('1 selected option')).toHaveTextContent('1')
327
313
 
328
314
  await selectEvent.select(secondOption.label, searchInput)
329
315
 
330
- expect(screen.getByTestId('select-trigger-clear-counter')).toHaveTextContent('2')
331
- expect(screen.getByTitle('2 selected options')).toBeInTheDocument()
316
+ expect(screen.getByTitle('2 selected options')).toHaveTextContent('2')
332
317
 
333
318
  const selectedOptions = await selectEvent.getSelectedOptions(searchInput)
334
319
  expect(selectedOptions).toHaveLength(2)
@@ -340,13 +325,14 @@ describe('Select', () => {
340
325
  })
341
326
 
342
327
  it('unselects a selected option keeping selected the others', async () => {
343
- const [firstOption, secondOption, thirdOption] = FRUITS
328
+ const [firstOption, secondOption, thirdOption] = generator.pickset([...FRUITS], 3)
329
+
344
330
  setup({ multiple: true, value: [firstOption, secondOption, thirdOption] as Option[] })
345
331
 
346
332
  const searchInput = screen.getByLabelText('Select your favorite fruit')
347
333
  expect(await selectEvent.getSelectedOptions(searchInput)).toHaveLength(3)
348
334
 
349
- expect(screen.getByTestId('select-trigger-clear-counter')).toHaveTextContent('3')
335
+ expect(screen.getByTitle('3 selected options')).toHaveTextContent('3')
350
336
 
351
337
  await selectEvent.unselect(secondOption.label, searchInput)
352
338
 
@@ -360,19 +346,19 @@ describe('Select', () => {
360
346
  })
361
347
 
362
348
  it('clears all selections when clicking the counter close button', async () => {
363
- const [firstOption, secondOption, thirdOption] = FRUITS
349
+ const [firstOption, secondOption, thirdOption] = generator.pickset([...FRUITS], 3)
364
350
  setup({ multiple: true, value: [firstOption, secondOption, thirdOption] as Option[] })
365
351
 
366
352
  const searchInput = screen.getByLabelText('Select your favorite fruit')
367
353
  expect(await selectEvent.getSelectedOptions(searchInput)).toHaveLength(3)
368
354
 
369
- expect(screen.getByTestId('select-trigger-clear-counter')).toHaveTextContent('3')
355
+ expect(screen.getByTitle('3 selected options')).toHaveTextContent('3')
370
356
 
371
357
  await selectEvent.clear(searchInput)
372
358
 
373
359
  expect(screen.queryByTestId('select-trigger-clear-counter')).not.toBeInTheDocument()
374
360
 
375
- expect(screen.queryByRole('option', { selected: true })).not.toBeInTheDocument()
361
+ expect(await selectEvent.getSelectedOptions(searchInput)).toHaveLength(0)
376
362
  })
377
363
  })
378
364
  })
@@ -384,59 +370,59 @@ describe('Select', () => {
384
370
  it('expands with the available options when search input is clicked', async () => {
385
371
  setup({})
386
372
 
387
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
373
+ await waitFor(() => {
374
+ expect(screen.getByTestId('select-trigger-handle')).toBeEnabled()
375
+ })
388
376
 
389
- await expandSelect(true)
377
+ const searchInput = screen.getByLabelText('Select the project manager')
390
378
 
391
- expect(screen.getByRole('listbox')).toBeInTheDocument()
379
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
392
380
 
393
- const items = screen.getAllByRole('option')
381
+ fire.click(searchInput)
382
+
383
+ await waitFor(() => {
384
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(true)
385
+ })
386
+
387
+ const options = await selectEvent.getOptions(searchInput)
394
388
 
395
389
  for (let i = 0; i < USERS.length; i++) {
396
- expect(items[i]).toHaveTextContent(USERS[i].name)
390
+ expect(options[i]).toHaveTextContent(USERS[i].name)
397
391
  }
398
392
  })
399
393
 
400
394
  it('expands with the available options when trigger handle is clicked', async () => {
401
395
  setup({})
402
396
 
403
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
397
+ const searchInput = screen.getByLabelText('Select the project manager')
404
398
 
405
- await expandSelect(true)
399
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(false)
406
400
 
407
- expect(screen.getByRole('listbox')).toBeInTheDocument()
401
+ await selectEvent.expand(searchInput)
408
402
 
409
- const items = screen.getAllByRole('option')
403
+ expect(selectEvent.isMenuExpanded(searchInput)).toBe(true)
404
+
405
+ const options = await selectEvent.getOptions(searchInput)
410
406
 
411
407
  for (let i = 0; i < USERS.length; i++) {
412
- expect(items[i]).toHaveTextContent(USERS[i].name)
408
+ expect(options[i]).toHaveTextContent(USERS[i].name)
413
409
  }
414
410
  })
415
411
 
416
412
  it('filters the available options when user enters a search string', async () => {
417
413
  setup({})
418
414
 
419
- expect(screen.queryByRole('listbox')).not.toBeInTheDocument()
415
+ const searchInput = screen.getByLabelText('Select the project manager')
416
+ const searchedUser = generator.pickone([...USERS])
420
417
 
421
- const indexToSearch = generator.natural({ min: 0, max: USERS.length - 1 })
422
- fire.change(screen.getByTestId('select-trigger-search-field'), {
423
- target: { value: USERS[indexToSearch].name },
418
+ fire.change(searchInput, {
419
+ target: { value: searchedUser.name },
424
420
  })
425
421
 
426
- await waitFor(() => screen.findByTestId('select-trigger-loading'))
427
-
428
- let items = [] as HTMLElement[]
429
- await waitFor(
430
- () => {
431
- items = screen.getAllByRole('option')
432
- },
433
- {
434
- timeout: 2500,
435
- }
436
- )
422
+ const options = await selectEvent.getOptions(searchInput)
437
423
 
438
- expect(items.length).toBe(1)
439
- expect(items[0]).toHaveTextContent(USERS[indexToSearch].name)
424
+ expect(options.length).toBe(1)
425
+ expect(options[0]).toHaveTextContent(searchedUser.name)
440
426
  })
441
427
  })
442
428
 
@@ -455,7 +441,8 @@ describe('Select', () => {
455
441
  async (props) => {
456
442
  setup(props)
457
443
 
458
- await expandSelect(true)
444
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
445
+ await selectEvent.expand(searchInput)
459
446
 
460
447
  const items = screen.getAllByTestId('custom-option')
461
448
  expect(items).toHaveLength(FRUITS.length)
@@ -467,28 +454,28 @@ describe('Select', () => {
467
454
  )
468
455
 
469
456
  it('overrides the option component with initial value', async () => {
470
- const [firstOption, secondOption] = FRUITS
471
- setup({ multiple: true, value: [firstOption, secondOption] as Option[] })
457
+ const selectedFruit = generator.pickone([...FRUITS])
472
458
 
473
- await expandSelect(true)
459
+ setup({ value: selectedFruit as Option })
474
460
 
475
- expect(screen.getAllByTestId('custom-option')).toHaveLength(2)
461
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
462
+ await selectEvent.expand(searchInput)
476
463
 
477
- await waitFor(() => {
478
- expect(screen.getAllByTestId('custom-option')).toHaveLength(FRUITS.length)
479
- })
464
+ const customOptions = screen.getAllByTestId('custom-option')
465
+ expect(customOptions).toHaveLength(FRUITS.length)
480
466
 
481
- const items = screen.getAllByTestId('custom-option')
482
- for (let i = 0; i < FRUITS.length; i++) {
483
- expect(items[i]).toHaveTextContent(getOptionText(FRUITS[i]))
484
- }
467
+ const selectedOptions = await selectEvent.getSelectedOptions(searchInput)
468
+
469
+ expect(selectedOptions).toHaveLength(1)
470
+ expect(selectedOptions[0]).toHaveTextContent(selectedFruit.label)
485
471
  })
486
472
 
487
473
  it('selects custom item clicked', async () => {
474
+ const selectedFruit = generator.pickone<Fruit>([...FRUITS])
475
+
488
476
  setup({})
489
477
 
490
478
  const searchInput = screen.getByLabelText('Select your favorite fruit')
491
- const selectedFruit = generator.pickone<Fruit>([...FRUITS])
492
479
  const optionText = getOptionText(selectedFruit)
493
480
 
494
481
  await selectEvent.select(optionText, searchInput)
@@ -500,11 +487,12 @@ describe('Select', () => {
500
487
  })
501
488
 
502
489
  it('selects multiple clicked custom items', async () => {
490
+ const SELECTED_OPTIONS_AMOUNT = 2
491
+ const options = generator.pickset([...FRUITS], SELECTED_OPTIONS_AMOUNT)
492
+
503
493
  setup({ multiple: true })
504
494
 
505
- const SELECTED_OPTIONS_AMOUNT = 2
506
495
  const searchInput = screen.getByLabelText('Select your favorite fruit')
507
- const options = generator.pickset([...FRUITS], SELECTED_OPTIONS_AMOUNT)
508
496
 
509
497
  for await (const option of options) {
510
498
  const optionText = getOptionText(option)
@@ -569,12 +557,17 @@ describe('Select', () => {
569
557
  })
570
558
 
571
559
  const searchInput = screen.getByLabelText('Select your favorite fruit')
572
- fire.change(searchInput, {
573
- target: { value: 'foo' },
560
+
561
+ await act(async () => {
562
+ fire.change(searchInput, {
563
+ target: { value: 'foo' },
564
+ })
565
+
566
+ const creatableOption = await screen.findByTestId('custom-creatable')
567
+
568
+ fire.click(creatableOption)
574
569
  })
575
570
 
576
- const creatableOption = await screen.findByTestId('custom-creatable')
577
- fire.click(creatableOption)
578
571
  expect(onCreate).toBeCalledWith('foo')
579
572
  }
580
573
  )
@@ -583,13 +576,11 @@ describe('Select', () => {
583
576
  describe('Creatable sync', () => {
584
577
  const setup = (overrides: Partial<SelectProps>) =>
585
578
  renderer(<CreatableSync {...overrides} />).render()
586
-
587
579
  it.each([[{ multiple: false }], [{ multiple: true }]])(
588
580
  'does not render the creatable option when onCreate callback is not provided - %s',
589
581
  async (args) => {
590
582
  setup({ onCreate: (null as unknown) as undefined, ...args })
591
583
 
592
- await expandSelect(true)
593
584
  const searchInput = screen.getByLabelText('Select your favorite fruit')
594
585
  fire.change(searchInput, {
595
586
  target: { value: 'foo' },
@@ -606,12 +597,10 @@ describe('Select', () => {
606
597
  'renders creatable option when onCreate callback is provided - %s',
607
598
  async (args) => {
608
599
  setup({ ...args })
609
-
610
600
  const searchInput = screen.getByLabelText('Select your favorite fruit')
611
601
  fire.change(searchInput, {
612
602
  target: { value: 'foo' },
613
603
  })
614
-
615
604
  await waitFor(() => {
616
605
  expect(screen.getByText('Add "foo"')).toBeInTheDocument()
617
606
  })
@@ -624,8 +613,8 @@ describe('Select', () => {
624
613
  setup({ ...args })
625
614
  const { label: availableOption } = generator.pickone([...FRUITS])
626
615
  const query = availableOption.slice(0, availableOption.length - 1)
627
-
628
616
  const searchInput = screen.getByLabelText('Select your favorite fruit')
617
+
629
618
  fire.change(searchInput, {
630
619
  target: { value: query },
631
620
  })
@@ -646,8 +635,8 @@ describe('Select', () => {
646
635
  })
647
636
  const { label: availableOption } = generator.pickone([...FRUITS])
648
637
  const query = availableOption.slice(0, availableOption.length - 1)
649
-
650
638
  const searchInput = screen.getByLabelText('Select your favorite fruit')
639
+
651
640
  fire.change(searchInput, {
652
641
  target: { value: query },
653
642
  })
@@ -666,8 +655,8 @@ describe('Select', () => {
666
655
  ...args,
667
656
  })
668
657
  const { label: availableOption } = generator.pickone([...FRUITS])
669
-
670
658
  const searchInput = screen.getByLabelText('Select your favorite fruit')
659
+
671
660
  fire.change(searchInput, {
672
661
  target: { value: availableOption },
673
662
  })
@@ -686,8 +675,9 @@ describe('Select', () => {
686
675
  ...args,
687
676
  })
688
677
  const { label: availableOption } = generator.pickone([...FRUITS])
678
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
689
679
 
690
- await expandSelect()
680
+ await selectEvent.expand(searchInput)
691
681
 
692
682
  await screen.findByLabelText(availableOption)
693
683
  await waitFor(() => {
@@ -701,14 +691,18 @@ describe('Select', () => {
701
691
  async (args) => {
702
692
  const onCreate = jest.fn()
703
693
  setup({ onCreate, ...args })
704
-
705
694
  const searchInput = screen.getByLabelText('Select your favorite fruit')
706
- fire.change(searchInput, {
707
- target: { value: 'foo' },
695
+
696
+ await act(async () => {
697
+ fire.change(searchInput, {
698
+ target: { value: 'foo' },
699
+ })
700
+
701
+ const creatableOption = await screen.findByText('Add "foo"')
702
+
703
+ fire.click(creatableOption)
708
704
  })
709
705
 
710
- const creatableOption = await screen.findByText('Add "foo"')
711
- fire.click(creatableOption)
712
706
  expect(onCreate).toBeCalledWith('foo')
713
707
  }
714
708
  )
@@ -725,11 +719,16 @@ describe('Select', () => {
725
719
  setup({ onCreate, onChange, ...args })
726
720
 
727
721
  const searchInput = screen.getByLabelText('Select your favorite fruit')
728
- fire.change(searchInput, {
729
- target: { value: query },
722
+
723
+ await act(async () => {
724
+ fire.change(searchInput, {
725
+ target: { value: query },
726
+ })
727
+
728
+ const creatableOption = await screen.findByText(`Add "${query}"`)
729
+
730
+ fire.click(creatableOption)
730
731
  })
731
- const creatableOption = await screen.findByText(`Add "${query}"`)
732
- fire.click(creatableOption)
733
732
 
734
733
  expect(onChange).toBeCalledWith({
735
734
  target: {
@@ -751,11 +750,16 @@ describe('Select', () => {
751
750
  setup({ onCreate, onChange, ...args })
752
751
 
753
752
  const searchInput = screen.getByLabelText('Select your favorite fruit')
754
- fire.change(searchInput, {
755
- target: { value: query },
753
+
754
+ await act(async () => {
755
+ fire.change(searchInput, {
756
+ target: { value: query },
757
+ })
758
+
759
+ const creatableOption = await screen.findByText(`Add "${query}"`)
760
+
761
+ fire.click(creatableOption)
756
762
  })
757
- const creatableOption = await screen.findByText(`Add "${query}"`)
758
- fire.click(creatableOption)
759
763
 
760
764
  expect(onChange).not.toBeCalled()
761
765
  }
@@ -776,13 +780,17 @@ describe('Select', () => {
776
780
  }),
777
781
  ]
778
782
  setup({ datasources, ...args })
779
-
780
783
  const searchInput = screen.getByLabelText('Select your favorite fruit')
781
- fire.change(searchInput, {
782
- target: { value: 'foo' },
784
+
785
+ await act(async () => {
786
+ fire.change(searchInput, {
787
+ target: { value: 'foo' },
788
+ })
789
+
790
+ const creatableOption = await screen.findByText('Add "foo"')
791
+
792
+ fire.click(creatableOption)
783
793
  })
784
- const creatableOption = await screen.findByText('Add "foo"')
785
- fire.click(creatableOption)
786
794
 
787
795
  await waitFor(() => {
788
796
  expect(dsFetch).toBeCalledTimes(2)
@@ -796,7 +804,8 @@ describe('Select', () => {
796
804
  async (args) => {
797
805
  setup({ ...args, isValidNewOption: true })
798
806
 
799
- await expandSelect(false)
807
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
808
+ await selectEvent.expand(searchInput)
800
809
 
801
810
  await waitFor(() => {
802
811
  expect(screen.getByText(/add ""/i)).toBeInTheDocument()
@@ -809,12 +818,12 @@ describe('Select', () => {
809
818
  async (args) => {
810
819
  setup({ ...args, isValidNewOption: true, createOptionPosition: 'first' })
811
820
 
812
- await expandSelect(true)
821
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
822
+ await selectEvent.expand(searchInput)
813
823
 
814
824
  await waitFor(() => {
815
825
  expect(screen.getByText(/add ""/i)).toBeInTheDocument()
816
826
  })
817
-
818
827
  expect(screen.getAllByTestId('dropdown-menu-item')[0]).toHaveTextContent(/add ""/i)
819
828
  }
820
829
  )
@@ -824,14 +833,13 @@ describe('Select', () => {
824
833
  async (args) => {
825
834
  setup({ ...args, isValidNewOption: true, createOptionPosition: 'last' })
826
835
 
827
- await expandSelect(true)
836
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
837
+ await selectEvent.expand(searchInput)
828
838
 
829
839
  await waitFor(() => {
830
840
  expect(screen.getByText(/add ""/i)).toBeInTheDocument()
831
841
  })
832
-
833
842
  const options = screen.getAllByTestId('dropdown-menu-item')
834
-
835
843
  expect(options[options.length - 1]).toHaveTextContent(/add ""/i)
836
844
  }
837
845
  )
@@ -844,9 +852,7 @@ describe('Select', () => {
844
852
  <Select.CreatableOption data-testid="custom-creatable">Add item</Select.CreatableOption>
845
853
  )
846
854
  }
847
-
848
855
  const value = generator.pickone([...FRUITS]) as Selectable
849
-
850
856
  setup({
851
857
  ...args,
852
858
  isValidNewOption: true,
@@ -857,7 +863,8 @@ describe('Select', () => {
857
863
  },
858
864
  })
859
865
 
860
- await expandSelect(true)
866
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
867
+ await selectEvent.expand(searchInput)
861
868
  expect(await screen.findByText(/add item/i)).toBeVisible()
862
869
  }
863
870
  )
@@ -868,7 +875,6 @@ describe('Select', () => {
868
875
  const CreatableOption = () => {
869
876
  return <Select.CreatableOption>Add item</Select.CreatableOption>
870
877
  }
871
-
872
878
  setup({
873
879
  ...args,
874
880
  isValidNewOption: true,
@@ -879,7 +885,8 @@ describe('Select', () => {
879
885
  },
880
886
  })
881
887
 
882
- await expandSelect(true)
888
+ const searchInput = screen.getByLabelText('Select your favorite fruit')
889
+ await selectEvent.expand(searchInput)
883
890
  expect(await screen.findByText(/add item/i)).toBeVisible()
884
891
  }
885
892
  )