@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.
- package/dist/components/Calendar/Calendar.stories.d.ts +2 -7
- package/dist/components/Calendar/Date.helper.d.ts +47 -12
- package/dist/components/Dropdown/Dropdown.stories.d.ts +4 -1
- package/dist/components/Loaders/LoadingBar.stories.d.ts +1 -1
- package/dist/index.js +445 -295
- package/dist/index.js.map +1 -1
- package/dist/testing/SelectEvent/SelectEvent.d.ts +2 -0
- package/dist/testing/index.js +1 -1
- package/dist/testing/index.js.map +1 -1
- package/dist/tests/generator.d.ts +35 -0
- package/dist/tests/renderer.d.ts +10 -0
- package/package.json +8 -7
- package/src/common/CloseButton/CloseButton.tsx +11 -7
- package/src/common/SelectionWrapper.tsx +7 -7
- package/src/components/Accordion/Accordion.stories.tsx +1 -1
- package/src/components/Accordion/Accordion.test.tsx +2 -2
- package/src/components/Accordion/Accordion.tsx +28 -22
- package/src/components/Banner/Banner.test.tsx +2 -2
- package/src/components/Banner/Banner.tsx +2 -2
- package/src/components/Breadcrumbs/Breadbrumbs.test.tsx +2 -2
- package/src/components/Breadcrumbs/Breadcrumb.tsx +3 -2
- package/src/components/Breadcrumbs/Breadcrumbs.tsx +1 -1
- package/src/components/Button/Button.test.tsx +2 -2
- package/src/components/Button/Button.tsx +20 -17
- package/src/components/Calendar/Calendar.stories.tsx +4 -2
- package/src/components/Calendar/Calendar.test.tsx +3 -3
- package/src/components/Calendar/Calendar.tsx +8 -4
- package/src/components/Calendar/Date.helper.test.ts +463 -15
- package/src/components/Calendar/Date.helper.ts +106 -45
- package/src/components/Calendar/PickerModeToggle.tsx +6 -3
- package/src/components/Calendar/Pickers/DayPicker.test.tsx +2 -2
- package/src/components/Calendar/Pickers/DayPicker.tsx +1 -1
- package/src/components/Calendar/Pickers/MonthPicker.test.tsx +2 -2
- package/src/components/Calendar/Pickers/MonthPicker.tsx +1 -1
- package/src/components/Calendar/Pickers/PickerButton.tsx +39 -29
- package/src/components/Calendar/Pickers/YearPicker.test.tsx +9 -7
- package/src/components/Calendar/Pickers/YearPicker.tsx +1 -1
- package/src/components/Card/Card.stories.tsx +1 -1
- package/src/components/Card/Card.test.tsx +2 -2
- package/src/components/Card/Card.tsx +9 -6
- package/src/components/Card/CardTitle.tsx +3 -4
- package/src/components/Checkbox/Checkbox.test.tsx +2 -2
- package/src/components/Checkbox/Checkbox.tsx +26 -14
- package/src/components/DatePicker/DatePicker.test.tsx +2 -2
- package/src/components/DatePicker/DateRangePicker.stories.tsx +6 -1
- package/src/components/DatePicker/DateRangePicker.test.tsx +2 -2
- package/src/components/Dialog/Dialog.test.tsx +2 -2
- package/src/components/Dialog/Dialog.tsx +5 -5
- package/src/components/DragDropFile/components/DropZone.test.tsx +1 -1
- package/src/components/DragDropFile/styles.tsx +11 -6
- package/src/components/Drawer/Drawer.test.tsx +1 -1
- package/src/components/Drawer/Drawer.tsx +6 -6
- package/src/components/Dropdown/Dropdown.stories.tsx +10 -5
- package/src/components/Dropdown/Dropdown.test.tsx +14 -16
- package/src/components/Dropdown/DropdownMenu.tsx +28 -15
- package/src/components/Dropdown/DropdownTrigger.tsx +34 -24
- package/src/components/EmptyState/EmptyState.test.tsx +1 -1
- package/src/components/ErrorMessage/ErrorMessage.test.tsx +1 -1
- package/src/components/HighlightMatch/HighlightMatch.test.tsx +1 -1
- package/src/components/HighlightMatch/HighlightMatch.tsx +1 -2
- package/src/components/IconFactory/IconFactory.test.tsx +2 -2
- package/src/components/Label/Label.test.tsx +2 -2
- package/src/components/Label/Label.tsx +3 -3
- package/src/components/Link/Link.test.tsx +2 -2
- package/src/components/Link/Link.tsx +13 -9
- package/src/components/Loaders/LoadingBar.stories.tsx +2 -2
- package/src/components/Loaders/LoadingBar.test.tsx +1 -1
- package/src/components/Loaders/LoadingBar.tsx +2 -2
- package/src/components/Loaders/LoadingDots.test.tsx +1 -1
- package/src/components/Loaders/Spinner.test.tsx +2 -2
- package/src/components/Modal/Modal.test.tsx +2 -2
- package/src/components/Modal/Modal.tsx +12 -7
- package/src/components/Pagination/Pagination.test.tsx +1 -1
- package/src/components/Popover/Popover.test.tsx +2 -2
- package/src/components/ProgressBar/ProgressBar.test.tsx +1 -1
- package/src/components/ProgressBar/ProgressBar.tsx +6 -4
- package/src/components/Radio/Radio.test.tsx +2 -2
- package/src/components/Radio/Radio.tsx +19 -11
- package/src/components/Section/Section.test.tsx +2 -2
- package/src/components/Section/Section.tsx +8 -6
- package/src/components/Section/Sections.stories.tsx +1 -1
- package/src/components/Select/Select.fixtures.ts +1 -1
- package/src/components/Select/Select.stories.tsx +2 -2
- package/src/components/Select/Select.test.tsx +162 -155
- package/src/components/Select/SelectEmpty.tsx +5 -4
- package/src/components/Select/SelectTrigger.tsx +11 -6
- package/src/components/Select/useSelect.helpers.test.ts +1 -1
- package/src/components/SideNavigation/Logo/Logo.test.tsx +2 -2
- package/src/components/SideNavigation/Menu/Menu.test.tsx +2 -2
- package/src/components/SideNavigation/Menu/Menu.tsx +3 -3
- package/src/components/SideNavigation/Menu/MenuBaseItem.tsx +5 -4
- package/src/components/SideNavigation/Menu/MenuExpandable.tsx +3 -2
- package/src/components/SideNavigation/Separator/Separator.test.tsx +1 -1
- package/src/components/SideNavigation/SideNavigation.test.tsx +2 -2
- package/src/components/Steps/ProgressSteps/ProgressStep.tsx +39 -31
- package/src/components/Steps/Steps.fixtures.ts +1 -1
- package/src/components/Steps/Steps.test.tsx +2 -2
- package/src/components/Steps/useStep.test.tsx +1 -1
- package/src/components/Switch/Switch.test.tsx +1 -1
- package/src/components/Switch/Switch.tsx +18 -6
- package/src/components/Table/Table.fixtures.ts +1 -1
- package/src/components/Table/Table.test.tsx +1 -1
- package/src/components/Table/Table.tsx +2 -2
- package/src/components/TablePagination/TablePagination.test.tsx +1 -1
- package/src/components/Tabs/Tabs.test.tsx +1 -1
- package/src/components/Tabs/Tabs.tsx +32 -26
- package/src/components/Tag/Tag.stories.tsx +1 -1
- package/src/components/Tag/Tag.test.tsx +2 -2
- package/src/components/Tag/Tag.tsx +44 -35
- package/src/components/Text/Text.test.tsx +2 -2
- package/src/components/TextField/TextField.test.tsx +1 -1
- package/src/components/TextField/TextField.tsx +22 -15
- package/src/components/Textarea/Textarea.test.tsx +1 -1
- package/src/components/Textarea/Textarea.tsx +22 -17
- package/src/components/Toast/Toast.test.tsx +2 -2
- package/src/components/Toast/Toast.tsx +3 -3
- package/src/components/ToggleGroup/Toggle.test.tsx +2 -2
- package/src/components/ToggleGroup/Toggle.tsx +7 -7
- package/src/components/ToggleGroup/ToggleGroup.stories.tsx +14 -12
- package/src/components/ToggleGroup/ToggleGroup.test.tsx +2 -2
- package/src/components/Tooltip/Tooltip.test.tsx +2 -2
- package/src/components/Tooltip/Tooltip.tsx +22 -20
- package/src/components/TopNavigation/Logo/Logo.test.tsx +2 -2
- package/src/components/TopNavigation/Menu/Menu.test.tsx +1 -1
- package/src/components/TopNavigation/Menu/MenuItemDropdown.tsx +1 -1
- package/src/components/TopNavigation/OpenSideNavButton/OpenSideNavButton.tsx +1 -1
- package/src/components/VisuallyHidden/VisuallyHidden.test.tsx +1 -1
- package/src/hooks/useClickOutside/useClickOutside.test.tsx +1 -1
- package/src/hooks/useDidMount/useDidMount.test.tsx +1 -1
- package/src/hooks/useFocusTrap/useFocusTrap.test.tsx +1 -1
- package/src/hooks/useFocusWithin/useFocusWithin.test.tsx +1 -1
- package/src/hooks/useHeightExpansionToggler/useHeightExpansionToggler.test.tsx +1 -1
- package/src/hooks/useSelectable/SelectableStrategy.test.ts +1 -1
- package/src/hooks/useSelectable/useSelectable.test.ts +1 -1
- package/src/styles/font.tsx +3 -3
- package/src/testing/SelectEvent/SelectEvent.test.tsx +2 -2
- package/src/testing/SelectEvent/SelectEvent.ts +87 -45
- package/src/tests/generator.ts +127 -0
- package/src/tests/renderer.tsx +39 -0
- package/src/tools/conditional.test.ts +1 -1
- package/src/utils/toolset/interleave.test.ts +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { renderHook, act } from '@testing-library/react-hooks'
|
|
2
2
|
|
|
3
3
|
import { createSelectable } from './useSelectable'
|
|
4
|
-
import generator from '
|
|
4
|
+
import generator from '../../tests/generator'
|
|
5
5
|
|
|
6
6
|
import type { Selectable, SelectableAdapter, SelectableKeyType } from './useSelectable.types'
|
|
7
7
|
|
package/src/styles/font.tsx
CHANGED
|
@@ -26,11 +26,11 @@ function fontStyle({
|
|
|
26
26
|
transform = 'none',
|
|
27
27
|
}: FontStyleOptions): FlattenInterpolation<ThemedProps> {
|
|
28
28
|
return css`
|
|
29
|
-
|
|
30
|
-
font-size: ${getToken(size)};
|
|
29
|
+
color: ${getToken(color)};
|
|
31
30
|
font-weight: ${getToken(weight)};
|
|
31
|
+
font-size: ${getToken(size)};
|
|
32
|
+
font-family: ${getToken(family)};
|
|
32
33
|
line-height: ${getToken(height)};
|
|
33
|
-
color: ${getToken(color)};
|
|
34
34
|
text-transform: ${transform};
|
|
35
35
|
-webkit-font-smoothing: antialiased;
|
|
36
36
|
-moz-osx-font-smoothing: grayscale;
|
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
useSyncFruits,
|
|
8
8
|
useAsyncUsers,
|
|
9
9
|
} from '../../components/Select/Select.fixtures'
|
|
10
|
-
import generator from '
|
|
11
|
-
import renderer, { screen } from '
|
|
10
|
+
import generator from '../../tests/generator'
|
|
11
|
+
import renderer, { screen } from '../../tests/renderer'
|
|
12
12
|
import Select from '../../components/Select/Select'
|
|
13
13
|
|
|
14
14
|
import selectEvent from './SelectEvent'
|
|
@@ -1,16 +1,56 @@
|
|
|
1
1
|
/* eslint-disable */
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
fireEvent,
|
|
4
|
+
queries,
|
|
5
|
+
waitFor,
|
|
6
|
+
within,
|
|
7
|
+
waitForElementToBeRemoved,
|
|
8
|
+
} from '@testing-library/dom'
|
|
3
9
|
import { act } from '@testing-library/react'
|
|
4
10
|
import userEvent from '@testing-library/user-event'
|
|
5
11
|
|
|
6
12
|
// based on https://github.com/romgain/react-select-event/blob/master/src/index.ts
|
|
7
13
|
|
|
8
|
-
// find the
|
|
9
|
-
function
|
|
14
|
+
// find the select container from its input field 🤷
|
|
15
|
+
function getSelectContainer(input: HTMLElement): HTMLElement {
|
|
10
16
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
11
17
|
return input.parentNode!.parentNode!.parentNode as HTMLElement
|
|
12
18
|
}
|
|
13
19
|
|
|
20
|
+
/**
|
|
21
|
+
* Please, make sure to call expand before trying to get the menu container
|
|
22
|
+
*/
|
|
23
|
+
function getSelectMenu(input: HTMLElement): HTMLElement {
|
|
24
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
25
|
+
return input.parentNode!.parentNode!.nextSibling as HTMLElement
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function getSelectTriggerHandle(input: HTMLElement): HTMLElement {
|
|
29
|
+
return input.parentNode!.nextSibling!.nextSibling as HTMLElement
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function getSelectSearchContainer(input: HTMLElement): HTMLElement {
|
|
33
|
+
return input.parentNode as HTMLElement
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isSelectMenuExpanded(input: HTMLElement): boolean {
|
|
37
|
+
const selectContainer = getSelectContainer(input)
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Once the select is expanded, we have the following structure:
|
|
41
|
+
* +-------------+
|
|
42
|
+
* | Close button (visually hiddren)
|
|
43
|
+
* +-------------+
|
|
44
|
+
* | DropdownTrigger
|
|
45
|
+
* +-------------+
|
|
46
|
+
* | Popover
|
|
47
|
+
* +-------------+
|
|
48
|
+
*
|
|
49
|
+
* This, if the container has 3 children, we assume the menu is expanded
|
|
50
|
+
*/
|
|
51
|
+
return selectContainer.children.length == 3
|
|
52
|
+
}
|
|
53
|
+
|
|
14
54
|
/**
|
|
15
55
|
* This is needed because some datasources might be asynchronous.
|
|
16
56
|
* To ensure that the data they retrieve will be available, we wait for the
|
|
@@ -18,15 +58,16 @@ function getReactSelectContainerFromInput(input: HTMLElement): HTMLElement {
|
|
|
18
58
|
* @param {HTMLElement} input - You can refer to this element by the label you applied to the `Select`.
|
|
19
59
|
*/
|
|
20
60
|
async function waitForPendingQuery(input: HTMLElement) {
|
|
21
|
-
const
|
|
61
|
+
const searchContainer = getSelectSearchContainer(input)
|
|
22
62
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
}
|
|
63
|
+
if (!queries.queryByTestId(searchContainer, 'select-trigger-loading')) {
|
|
64
|
+
return
|
|
65
|
+
}
|
|
26
66
|
|
|
27
|
-
await
|
|
28
|
-
|
|
29
|
-
|
|
67
|
+
await waitForElementToBeRemoved(
|
|
68
|
+
() => queries.queryByTestId(searchContainer, 'select-trigger-loading'),
|
|
69
|
+
{ timeout: 2500 }
|
|
70
|
+
)
|
|
30
71
|
}
|
|
31
72
|
|
|
32
73
|
/**
|
|
@@ -35,21 +76,23 @@ async function waitForPendingQuery(input: HTMLElement) {
|
|
|
35
76
|
* @returns {Promise<void>}
|
|
36
77
|
*/
|
|
37
78
|
async function expand(input: HTMLElement): Promise<void> {
|
|
38
|
-
|
|
79
|
+
await waitForPendingQuery(input)
|
|
39
80
|
|
|
40
|
-
|
|
41
|
-
if (queries.queryByRole(selectContainer, 'listbox')) {
|
|
81
|
+
if (isSelectMenuExpanded(input)) {
|
|
42
82
|
return
|
|
43
83
|
}
|
|
44
84
|
|
|
85
|
+
const triggerHandle = getSelectTriggerHandle(input)
|
|
86
|
+
|
|
45
87
|
await waitFor(() => {
|
|
46
|
-
expect(
|
|
88
|
+
expect(triggerHandle).toBeEnabled()
|
|
47
89
|
})
|
|
48
90
|
|
|
49
91
|
await act(async () => {
|
|
50
|
-
userEvent.click(
|
|
51
|
-
|
|
52
|
-
|
|
92
|
+
userEvent.click(triggerHandle)
|
|
93
|
+
await waitFor(() => {
|
|
94
|
+
expect(isSelectMenuExpanded(input)).toBe(true)
|
|
95
|
+
})
|
|
53
96
|
})
|
|
54
97
|
}
|
|
55
98
|
|
|
@@ -59,18 +102,17 @@ async function expand(input: HTMLElement): Promise<void> {
|
|
|
59
102
|
* @returns {Promise<void>}
|
|
60
103
|
*/
|
|
61
104
|
async function collapse(input: HTMLElement): Promise<void> {
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
// if listbox is not rendered, then the select is already collapsed
|
|
65
|
-
if (!queries.queryByRole(selectContainer, 'listbox')) {
|
|
105
|
+
if (!isSelectMenuExpanded(input)) {
|
|
66
106
|
return
|
|
67
107
|
}
|
|
68
108
|
|
|
109
|
+
const triggerHandle = getSelectTriggerHandle(input)
|
|
110
|
+
|
|
69
111
|
await act(async () => {
|
|
70
|
-
userEvent.click(
|
|
112
|
+
userEvent.click(triggerHandle)
|
|
71
113
|
|
|
72
114
|
await waitFor(() => {
|
|
73
|
-
expect(
|
|
115
|
+
expect(isSelectMenuExpanded(input)).toBe(false)
|
|
74
116
|
})
|
|
75
117
|
})
|
|
76
118
|
}
|
|
@@ -83,13 +125,12 @@ async function collapse(input: HTMLElement): Promise<void> {
|
|
|
83
125
|
* @returns {Promise<void>}
|
|
84
126
|
*/
|
|
85
127
|
async function select(option: string, input: HTMLElement): Promise<void> {
|
|
86
|
-
const selectContainer = getReactSelectContainerFromInput(input)
|
|
87
|
-
|
|
88
|
-
await waitForPendingQuery(input)
|
|
89
128
|
await expand(input)
|
|
90
129
|
|
|
130
|
+
const menuContainer = getSelectMenu(input)
|
|
131
|
+
|
|
91
132
|
await act(async () => {
|
|
92
|
-
const optionElement = await queries.findByLabelText(
|
|
133
|
+
const optionElement = await queries.findByLabelText(menuContainer, option)
|
|
93
134
|
|
|
94
135
|
// click the option if exists; Select currently closes when an item is clicked.
|
|
95
136
|
if (optionElement && optionElement.getAttribute('aria-selected') == 'false') {
|
|
@@ -109,13 +150,12 @@ async function select(option: string, input: HTMLElement): Promise<void> {
|
|
|
109
150
|
* @returns {Promise<void>}
|
|
110
151
|
*/
|
|
111
152
|
async function unselect(option: string, input: HTMLElement): Promise<void> {
|
|
112
|
-
const selectContainer = getReactSelectContainerFromInput(input)
|
|
113
|
-
|
|
114
|
-
await waitForPendingQuery(input)
|
|
115
153
|
await expand(input)
|
|
116
154
|
|
|
155
|
+
const menuContainer = getSelectMenu(input)
|
|
156
|
+
|
|
117
157
|
await act(async () => {
|
|
118
|
-
const optionElement = await queries.findByLabelText(
|
|
158
|
+
const optionElement = await queries.findByLabelText(menuContainer, option)
|
|
119
159
|
|
|
120
160
|
// ensures that the option exists and IS selected
|
|
121
161
|
if (optionElement && optionElement.getAttribute('aria-selected') == 'true') {
|
|
@@ -133,12 +173,12 @@ async function unselect(option: string, input: HTMLElement): Promise<void> {
|
|
|
133
173
|
* @returns {Promise<void>}
|
|
134
174
|
*/
|
|
135
175
|
async function clear(input: HTMLElement): Promise<void> {
|
|
136
|
-
const selectContainer = getReactSelectContainerFromInput(input)
|
|
137
|
-
|
|
138
176
|
await waitForPendingQuery(input)
|
|
139
177
|
|
|
178
|
+
const searchContainer = getSelectSearchContainer(input)
|
|
179
|
+
|
|
140
180
|
await act(async () => {
|
|
141
|
-
const clearButton = within(
|
|
181
|
+
const clearButton = within(searchContainer).getByTestId('select-trigger-clear')
|
|
142
182
|
|
|
143
183
|
if (clearButton) {
|
|
144
184
|
userEvent.click(clearButton)
|
|
@@ -153,7 +193,7 @@ async function clear(input: HTMLElement): Promise<void> {
|
|
|
153
193
|
* @returns {Promise<void>}
|
|
154
194
|
*/
|
|
155
195
|
async function search(query: string, input: HTMLElement): Promise<void> {
|
|
156
|
-
const selectContainer =
|
|
196
|
+
const selectContainer = getSelectContainer(input)
|
|
157
197
|
|
|
158
198
|
await act(async () => {
|
|
159
199
|
fireEvent.change(input, { target: { value: query } })
|
|
@@ -168,14 +208,14 @@ async function search(query: string, input: HTMLElement): Promise<void> {
|
|
|
168
208
|
* @returns {Promise<HTMLElement[]>}
|
|
169
209
|
*/
|
|
170
210
|
async function getOptions(input: HTMLElement): Promise<HTMLElement[]> {
|
|
171
|
-
const selectContainer = getReactSelectContainerFromInput(input)
|
|
172
|
-
|
|
173
|
-
await waitForPendingQuery(input)
|
|
174
211
|
await expand(input)
|
|
175
|
-
|
|
212
|
+
|
|
213
|
+
const menuContainer = getSelectMenu(input)
|
|
214
|
+
|
|
215
|
+
const options = queries.queryAllByRole(menuContainer, 'option')
|
|
176
216
|
await collapse(input)
|
|
177
217
|
|
|
178
|
-
return
|
|
218
|
+
return options
|
|
179
219
|
}
|
|
180
220
|
|
|
181
221
|
/**
|
|
@@ -184,14 +224,15 @@ async function getOptions(input: HTMLElement): Promise<HTMLElement[]> {
|
|
|
184
224
|
* @returns {Promise<HTMLElement[]>}
|
|
185
225
|
*/
|
|
186
226
|
async function getSelectedOptions(input: HTMLElement): Promise<HTMLElement[]> {
|
|
187
|
-
const selectContainer = getReactSelectContainerFromInput(input)
|
|
188
|
-
let selectedOptions: HTMLElement[] = []
|
|
189
|
-
|
|
190
|
-
await waitForPendingQuery(input)
|
|
191
227
|
await expand(input)
|
|
192
228
|
|
|
229
|
+
const menuContainer = getSelectMenu(input)
|
|
230
|
+
let selectedOptions: HTMLElement[] = []
|
|
231
|
+
|
|
193
232
|
try {
|
|
194
|
-
selectedOptions = await queries.findAllByRole(
|
|
233
|
+
selectedOptions = await queries.findAllByRole(menuContainer, 'option', {
|
|
234
|
+
selected: true,
|
|
235
|
+
})
|
|
195
236
|
} catch (err) {
|
|
196
237
|
selectedOptions = []
|
|
197
238
|
}
|
|
@@ -210,6 +251,7 @@ export const selectEvent = {
|
|
|
210
251
|
collapse,
|
|
211
252
|
getOptions,
|
|
212
253
|
getSelectedOptions,
|
|
254
|
+
isMenuExpanded: isSelectMenuExpanded,
|
|
213
255
|
}
|
|
214
256
|
|
|
215
257
|
export default selectEvent
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import Chance from 'chance'
|
|
2
|
+
import { nanoid } from 'nanoid'
|
|
3
|
+
|
|
4
|
+
const chance = new Chance()
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generates an array of `amount` (or random) length, based on the given
|
|
8
|
+
* template function.
|
|
9
|
+
* The template function receives as named parameter the current `index`.
|
|
10
|
+
* @param {Function} template Template function to generate one item
|
|
11
|
+
* @param {number} amount Amount of items to be generated. If none is provide,
|
|
12
|
+
* then a random amount is generated.
|
|
13
|
+
* @returns {Array} Returns an array of lenght `amount`, with items
|
|
14
|
+
* generated based on the provided `template`.
|
|
15
|
+
*/
|
|
16
|
+
function generateArray<T>(
|
|
17
|
+
template: ({ index }: { index: number }) => T,
|
|
18
|
+
amount?: number
|
|
19
|
+
): Array<T> {
|
|
20
|
+
const safeAmount = amount || chance.integer({ min: 5, max: 10 })
|
|
21
|
+
|
|
22
|
+
const data = []
|
|
23
|
+
for (let i = 0; i < safeAmount; i++) {
|
|
24
|
+
const item = template({ index: i })
|
|
25
|
+
data.push(item)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return data
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function generatePick<T>(
|
|
32
|
+
array: Array<T>,
|
|
33
|
+
options?: { amount: number; allowRepeat?: boolean }
|
|
34
|
+
): T | Array<T> {
|
|
35
|
+
const { amount = 1, allowRepeat = true } = options || {}
|
|
36
|
+
|
|
37
|
+
if (amount === 1) {
|
|
38
|
+
return chance.pickone(array)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
let picked = chance.pickset(array, amount)
|
|
42
|
+
|
|
43
|
+
if (!allowRepeat) {
|
|
44
|
+
picked = Array.from(new Set(picked))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return picked
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function generateDate(overrides: { month?: number; day?: number; year?: number } = {}): string {
|
|
51
|
+
const month = String(overrides.month ?? chance.natural({ min: 1, max: 12 })).padStart(2, '0')
|
|
52
|
+
const day = String(overrides.day ?? chance.natural({ min: 1, max: 28 })).padStart(2, '0')
|
|
53
|
+
const year = overrides.year ?? new Date().getFullYear()
|
|
54
|
+
|
|
55
|
+
return `${month}/${day}/${year}`
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function generateTime(opts?: Chance.Options): string {
|
|
59
|
+
const hour = String(chance.hour({ twentyfour: true, ...opts })).padStart(2, '0')
|
|
60
|
+
const minute = String(chance.minute()).padStart(2, '0')
|
|
61
|
+
|
|
62
|
+
return `${hour}:${minute}`
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function generateUsername(): string {
|
|
66
|
+
const name = chance.name()
|
|
67
|
+
return name.replace(/^\s+|\s+$/g, '').toLowerCase()
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function generateID(): string {
|
|
71
|
+
return nanoid()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
interface DataGenerator {
|
|
75
|
+
animal: () => string
|
|
76
|
+
array: <T>(template: ({ index }: { index: number }) => T, amount?: number) => Array<T>
|
|
77
|
+
boolean: () => boolean
|
|
78
|
+
company: () => string
|
|
79
|
+
date: () => string
|
|
80
|
+
float: (opts?: Chance.Options) => number
|
|
81
|
+
id: () => string
|
|
82
|
+
name: (opts?: Chance.Options) => string
|
|
83
|
+
natural: (opts?: Chance.Options) => number
|
|
84
|
+
paragraph: (opts?: Chance.Options) => string
|
|
85
|
+
/**
|
|
86
|
+
* @deprecated Use pickone or pickset
|
|
87
|
+
*/
|
|
88
|
+
pick: <T>(array: Array<T>, options?: { amount: number; allowRepeat?: boolean }) => T | Array<T>
|
|
89
|
+
pickone<T>(arr: T[]): T
|
|
90
|
+
pickset<T>(arr: T[], count?: number): T[]
|
|
91
|
+
profession: () => string
|
|
92
|
+
sentence: (opts?: Chance.Options) => string
|
|
93
|
+
state: (opts?: Chance.Options) => string
|
|
94
|
+
time: (opts?: Chance.Options) => string
|
|
95
|
+
token: () => string
|
|
96
|
+
url: () => string
|
|
97
|
+
username: () => string
|
|
98
|
+
word: (opts?: Chance.Options) => string
|
|
99
|
+
dollar: () => string
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const generators: DataGenerator = {
|
|
103
|
+
animal: chance.animal.bind(chance),
|
|
104
|
+
array: generateArray,
|
|
105
|
+
boolean: chance.bool.bind(chance),
|
|
106
|
+
company: chance.company.bind(chance),
|
|
107
|
+
date: generateDate,
|
|
108
|
+
float: chance.floating.bind(chance),
|
|
109
|
+
id: generateID,
|
|
110
|
+
name: chance.name.bind(chance),
|
|
111
|
+
natural: chance.natural.bind(chance),
|
|
112
|
+
paragraph: chance.paragraph.bind(chance),
|
|
113
|
+
pick: generatePick,
|
|
114
|
+
pickone: chance.pickone.bind(chance),
|
|
115
|
+
pickset: chance.pickset.bind(chance),
|
|
116
|
+
profession: chance.profession.bind(chance),
|
|
117
|
+
sentence: chance.sentence.bind(chance),
|
|
118
|
+
state: chance.state.bind(chance),
|
|
119
|
+
time: generateTime,
|
|
120
|
+
token: chance.animal.bind(chance),
|
|
121
|
+
url: chance.url.bind(chance),
|
|
122
|
+
username: generateUsername,
|
|
123
|
+
word: chance.word.bind(chance),
|
|
124
|
+
dollar: chance.dollar.bind(chance),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export default generators
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import {
|
|
2
|
+
render,
|
|
3
|
+
fireEvent,
|
|
4
|
+
RenderOptions,
|
|
5
|
+
within,
|
|
6
|
+
waitFor,
|
|
7
|
+
waitForElementToBeRemoved,
|
|
8
|
+
act,
|
|
9
|
+
screen,
|
|
10
|
+
queries,
|
|
11
|
+
} from '@testing-library/react'
|
|
12
|
+
import userEvent from '@testing-library/user-event'
|
|
13
|
+
|
|
14
|
+
class Renderer {
|
|
15
|
+
result: React.ReactElement
|
|
16
|
+
|
|
17
|
+
constructor(children: React.ReactElement) {
|
|
18
|
+
this.result = children
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
render(options?: Omit<RenderOptions, 'queries'>) {
|
|
22
|
+
return render(this.result, options)
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export default function customRenderer(children: React.ReactElement): Renderer {
|
|
27
|
+
return new Renderer(children)
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
act,
|
|
32
|
+
fireEvent as fire,
|
|
33
|
+
queries,
|
|
34
|
+
screen,
|
|
35
|
+
userEvent as user,
|
|
36
|
+
waitFor,
|
|
37
|
+
waitForElementToBeRemoved,
|
|
38
|
+
within,
|
|
39
|
+
}
|