@transferwise/components 46.71.1 → 46.71.3

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 (32) hide show
  1. package/build/button/Button.js.map +1 -1
  2. package/build/button/Button.mjs.map +1 -1
  3. package/build/inputs/SelectInput.js +33 -4
  4. package/build/inputs/SelectInput.js.map +1 -1
  5. package/build/inputs/SelectInput.mjs +33 -4
  6. package/build/inputs/SelectInput.mjs.map +1 -1
  7. package/build/instructionsList/InstructionsList.js +4 -3
  8. package/build/instructionsList/InstructionsList.js.map +1 -1
  9. package/build/instructionsList/InstructionsList.mjs +4 -3
  10. package/build/instructionsList/InstructionsList.mjs.map +1 -1
  11. package/build/types/button/Button.d.ts +1 -1
  12. package/build/types/button/Button.d.ts.map +1 -1
  13. package/build/types/inputs/SelectInput.d.ts.map +1 -1
  14. package/build/types/instructionsList/InstructionsList.d.ts.map +1 -1
  15. package/package.json +3 -3
  16. package/src/accordion/AccordionItem/__snapshots__/AccordionItem.spec.js.snap +4 -4
  17. package/src/avatarWrapper/__snapshots__/AvatarWrapper.spec.tsx.snap +8 -8
  18. package/src/button/Button.tsx +1 -1
  19. package/src/chips/__snapshots__/Chips.spec.tsx.snap +2 -2
  20. package/src/circularButton/__snapshots__/CircularButton.spec.tsx.snap +20 -20
  21. package/src/common/bottomSheet/__snapshots__/BottomSheet.spec.tsx.snap +2 -2
  22. package/src/common/closeButton/__snapshots__/CloseButton.spec.tsx.snap +2 -2
  23. package/src/drawer/__snapshots__/Drawer.rtl.spec.tsx.snap +2 -2
  24. package/src/flowNavigation/__snapshots__/FlowNavigation.spec.js.snap +4 -4
  25. package/src/inputs/SelectInput.docs.mdx +21 -0
  26. package/src/inputs/SelectInput.spec.tsx +94 -1
  27. package/src/inputs/SelectInput.story.tsx +2 -2
  28. package/src/inputs/SelectInput.tsx +39 -2
  29. package/src/instructionsList/InstructionsList.spec.tsx +21 -5
  30. package/src/instructionsList/InstructionsList.tsx +11 -3
  31. package/src/moneyInput/MoneyInput.rtl.spec.tsx +9 -0
  32. package/src/overlayHeader/__snapshots__/OverlayHeader.spec.tsx.snap +2 -2
@@ -11,15 +11,15 @@ exports[`CircularButton defaults renders a button of type accent and priority pr
11
11
  type="button"
12
12
  />
13
13
  <span
14
- aria-hidden="true"
15
14
  class="tw-icon tw-icon-plus "
16
15
  data-testid="plus-icon"
17
- role="presentation"
18
16
  >
19
17
  <svg
18
+ aria-hidden="true"
20
19
  fill="currentColor"
21
20
  focusable="false"
22
21
  height="24"
22
+ role="none"
23
23
  viewBox="0 0 24 24"
24
24
  width="24"
25
25
  >
@@ -48,15 +48,15 @@ exports[`CircularButton priorities renders primary buttons 1`] = `
48
48
  type="button"
49
49
  />
50
50
  <span
51
- aria-hidden="true"
52
51
  class="tw-icon tw-icon-plus "
53
52
  data-testid="plus-icon"
54
- role="presentation"
55
53
  >
56
54
  <svg
55
+ aria-hidden="true"
57
56
  fill="currentColor"
58
57
  focusable="false"
59
58
  height="24"
59
+ role="none"
60
60
  viewBox="0 0 24 24"
61
61
  width="24"
62
62
  >
@@ -85,15 +85,15 @@ exports[`CircularButton priorities renders primary buttons 2`] = `
85
85
  type="button"
86
86
  />
87
87
  <span
88
- aria-hidden="true"
89
88
  class="tw-icon tw-icon-plus "
90
89
  data-testid="plus-icon"
91
- role="presentation"
92
90
  >
93
91
  <svg
92
+ aria-hidden="true"
94
93
  fill="currentColor"
95
94
  focusable="false"
96
95
  height="24"
96
+ role="none"
97
97
  viewBox="0 0 24 24"
98
98
  width="24"
99
99
  >
@@ -122,15 +122,15 @@ exports[`CircularButton priorities renders primary buttons 3`] = `
122
122
  type="button"
123
123
  />
124
124
  <span
125
- aria-hidden="true"
126
125
  class="tw-icon tw-icon-plus "
127
126
  data-testid="plus-icon"
128
- role="presentation"
129
127
  >
130
128
  <svg
129
+ aria-hidden="true"
131
130
  fill="currentColor"
132
131
  focusable="false"
133
132
  height="24"
133
+ role="none"
134
134
  viewBox="0 0 24 24"
135
135
  width="24"
136
136
  >
@@ -159,15 +159,15 @@ exports[`CircularButton priorities renders secondary buttons 1`] = `
159
159
  type="button"
160
160
  />
161
161
  <span
162
- aria-hidden="true"
163
162
  class="tw-icon tw-icon-plus "
164
163
  data-testid="plus-icon"
165
- role="presentation"
166
164
  >
167
165
  <svg
166
+ aria-hidden="true"
168
167
  fill="currentColor"
169
168
  focusable="false"
170
169
  height="24"
170
+ role="none"
171
171
  viewBox="0 0 24 24"
172
172
  width="24"
173
173
  >
@@ -196,15 +196,15 @@ exports[`CircularButton priorities renders secondary buttons 2`] = `
196
196
  type="button"
197
197
  />
198
198
  <span
199
- aria-hidden="true"
200
199
  class="tw-icon tw-icon-plus "
201
200
  data-testid="plus-icon"
202
- role="presentation"
203
201
  >
204
202
  <svg
203
+ aria-hidden="true"
205
204
  fill="currentColor"
206
205
  focusable="false"
207
206
  height="24"
207
+ role="none"
208
208
  viewBox="0 0 24 24"
209
209
  width="24"
210
210
  >
@@ -233,15 +233,15 @@ exports[`CircularButton priorities renders secondary buttons 3`] = `
233
233
  type="button"
234
234
  />
235
235
  <span
236
- aria-hidden="true"
237
236
  class="tw-icon tw-icon-plus "
238
237
  data-testid="plus-icon"
239
- role="presentation"
240
238
  >
241
239
  <svg
240
+ aria-hidden="true"
242
241
  fill="currentColor"
243
242
  focusable="false"
244
243
  height="24"
244
+ role="none"
245
245
  viewBox="0 0 24 24"
246
246
  width="24"
247
247
  >
@@ -270,15 +270,15 @@ exports[`CircularButton types renders accent buttons 1`] = `
270
270
  type="button"
271
271
  />
272
272
  <span
273
- aria-hidden="true"
274
273
  class="tw-icon tw-icon-plus "
275
274
  data-testid="plus-icon"
276
- role="presentation"
277
275
  >
278
276
  <svg
277
+ aria-hidden="true"
279
278
  fill="currentColor"
280
279
  focusable="false"
281
280
  height="24"
281
+ role="none"
282
282
  viewBox="0 0 24 24"
283
283
  width="24"
284
284
  >
@@ -307,15 +307,15 @@ exports[`CircularButton types renders negative buttons 1`] = `
307
307
  type="button"
308
308
  />
309
309
  <span
310
- aria-hidden="true"
311
310
  class="tw-icon tw-icon-plus "
312
311
  data-testid="plus-icon"
313
- role="presentation"
314
312
  >
315
313
  <svg
314
+ aria-hidden="true"
316
315
  fill="currentColor"
317
316
  focusable="false"
318
317
  height="24"
318
+ role="none"
319
319
  viewBox="0 0 24 24"
320
320
  width="24"
321
321
  >
@@ -344,15 +344,15 @@ exports[`CircularButton types renders positive buttons 1`] = `
344
344
  type="button"
345
345
  />
346
346
  <span
347
- aria-hidden="true"
348
347
  class="tw-icon tw-icon-plus "
349
348
  data-testid="plus-icon"
350
- role="presentation"
351
349
  >
352
350
  <svg
351
+ aria-hidden="true"
353
352
  fill="currentColor"
354
353
  focusable="false"
355
354
  height="24"
355
+ role="none"
356
356
  viewBox="0 0 24 24"
357
357
  width="24"
358
358
  >
@@ -39,15 +39,15 @@ exports[`BottomSheet renders content when open 1`] = `
39
39
  type="button"
40
40
  >
41
41
  <span
42
- aria-hidden="true"
43
42
  class="tw-icon tw-icon-cross "
44
43
  data-testid="cross-icon"
45
- role="presentation"
46
44
  >
47
45
  <svg
46
+ aria-hidden="true"
48
47
  fill="currentColor"
49
48
  focusable="false"
50
49
  height="16"
50
+ role="none"
51
51
  viewBox="0 0 24 24"
52
52
  width="16"
53
53
  >
@@ -8,15 +8,15 @@ exports[`CloseButton renders as expected 1`] = `
8
8
  type="button"
9
9
  >
10
10
  <span
11
- aria-hidden="true"
12
11
  class="tw-icon tw-icon-cross "
13
12
  data-testid="cross-icon"
14
- role="presentation"
15
13
  >
16
14
  <svg
15
+ aria-hidden="true"
17
16
  fill="currentColor"
18
17
  focusable="false"
19
18
  height="24"
19
+ role="none"
20
20
  viewBox="0 0 24 24"
21
21
  width="24"
22
22
  >
@@ -24,15 +24,15 @@ exports[`Drawer renders content when open 1`] = `
24
24
  type="button"
25
25
  >
26
26
  <span
27
- aria-hidden="true"
28
27
  class="tw-icon tw-icon-cross "
29
28
  data-testid="cross-icon"
30
- role="presentation"
31
29
  >
32
30
  <svg
31
+ aria-hidden="true"
33
32
  fill="currentColor"
34
33
  focusable="false"
35
34
  height="24"
35
+ role="none"
36
36
  viewBox="0 0 24 24"
37
37
  width="24"
38
38
  >
@@ -38,15 +38,15 @@ exports[`FlowNavigation on mobile renders as expected 1`] = `
38
38
  type="button"
39
39
  >
40
40
  <span
41
- aria-hidden="true"
42
41
  class="tw-icon tw-icon-cross "
43
42
  data-testid="cross-icon"
44
- role="presentation"
45
43
  >
46
44
  <svg
45
+ aria-hidden="true"
47
46
  fill="currentColor"
48
47
  focusable="false"
49
48
  height="24"
49
+ role="none"
50
50
  viewBox="0 0 24 24"
51
51
  width="24"
52
52
  >
@@ -153,15 +153,15 @@ exports[`FlowNavigation renders as expected 1`] = `
153
153
  type="button"
154
154
  >
155
155
  <span
156
- aria-hidden="true"
157
156
  class="tw-icon tw-icon-cross "
158
157
  data-testid="cross-icon"
159
- role="presentation"
160
158
  >
161
159
  <svg
160
+ aria-hidden="true"
162
161
  fill="currentColor"
163
162
  focusable="false"
164
163
  height="24"
164
+ role="none"
165
165
  viewBox="0 0 24 24"
166
166
  width="24"
167
167
  >
@@ -0,0 +1,21 @@
1
+ import { Meta } from '@storybook/blocks';
2
+ import { MoneyInput } from '..';
3
+
4
+ <Meta title="Forms/SelectInput/Accessibility" />
5
+
6
+ # Accessibility
7
+
8
+ ## Labelling
9
+
10
+ In order for the `<SelectInput />` to be considered accessible, it must be provided with a matching label, preferably via the <a href="/?path=/docs/field--docs">Field</a> component.
11
+
12
+ Additionally, the `listbox` container that holds all the options is also expected to have its own label, which the component will attempt to resolve by looking in the following places:
13
+
14
+ 1. `UNSAFE_triggerButtonProps['aria-label']` prop, which reuses the custom label provided for the trigger button.
15
+ <br /> A good example of this strategy is the `<MoneyInput />` component, internally setting
16
+ `"Select currency"` as a trigger button label, which then gets automatically applied to the
17
+ `listbox`.
18
+ 2. `UNSAFE_triggerButtonProps['aria-labelledby']` prop, which holds the id of the element labelling the trigger button.
19
+ 3. Correctly paired input `<label />` text, ideally via the `Field` component.
20
+
21
+ > Using option group heading is possible but complicated as we can have multiple groups, and those are not necessarily rendered consistently if search or virtualisation are enabled.
@@ -3,7 +3,7 @@ import { userEvent } from '@testing-library/user-event';
3
3
 
4
4
  import { render, mockMatchMedia, mockResizeObserver } from '../test-utils';
5
5
 
6
- import { SelectInput } from './SelectInput';
6
+ import { SelectInput, type SelectInputOptionItem, type SelectInputProps } from './SelectInput';
7
7
  import { Field } from '../field/Field';
8
8
 
9
9
  mockMatchMedia();
@@ -216,4 +216,97 @@ describe('SelectInput', () => {
216
216
  );
217
217
  expect(screen.getByLabelText(/Currency/)).toHaveAttribute('aria-haspopup');
218
218
  });
219
+
220
+ describe('listbox label', () => {
221
+ const fieldLabel = 'Fruits';
222
+ const triggerLabel = 'Select fruit';
223
+ const options: SelectInputOptionItem[] = [
224
+ { type: 'option', value: 'Banana' },
225
+ { type: 'option', value: 'Orange' },
226
+ { type: 'option', value: 'Olive' },
227
+ ];
228
+ const requiredTriggerButtonProps = {
229
+ id: undefined,
230
+ 'aria-labelledby': undefined,
231
+ 'aria-describedby': undefined,
232
+ 'aria-invalid': undefined,
233
+ 'aria-label': undefined,
234
+ };
235
+
236
+ const renderSelectInput = (props: Omit<SelectInputProps<string | null>, 'items'> = {}) =>
237
+ render(
238
+ <Field label={fieldLabel} id="selectId">
239
+ <SelectInput {...props} items={options} />
240
+ </Field>,
241
+ );
242
+
243
+ it("should propagate trigger's label if nothing is selected", async () => {
244
+ renderSelectInput({
245
+ UNSAFE_triggerButtonProps: {
246
+ ...requiredTriggerButtonProps,
247
+ 'aria-label': triggerLabel,
248
+ },
249
+ });
250
+ const trigger = screen.getByRole('combobox');
251
+ await userEvent.click(trigger);
252
+ expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
253
+ });
254
+
255
+ it("should propagate trigger's label if an option is selected", async () => {
256
+ renderSelectInput({
257
+ UNSAFE_triggerButtonProps: {
258
+ ...requiredTriggerButtonProps,
259
+ 'aria-label': triggerLabel,
260
+ },
261
+ value: options[1].value,
262
+ });
263
+ const trigger = screen.getByRole('combobox');
264
+ await userEvent.click(trigger);
265
+ expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
266
+ });
267
+
268
+ it("should propagate trigger's label by id", async () => {
269
+ const customLabelId = 'customLabelId';
270
+ renderSelectInput({
271
+ UNSAFE_triggerButtonProps: {
272
+ ...requiredTriggerButtonProps,
273
+ 'aria-labelledby': customLabelId,
274
+ },
275
+ });
276
+ const trigger = screen.getByRole('combobox');
277
+ await userEvent.click(trigger);
278
+ expect(screen.getByRole('listbox')).toHaveAttribute('aria-labelledby', customLabelId);
279
+ });
280
+
281
+ it("should propagate input's label by id", async () => {
282
+ renderSelectInput();
283
+ const trigger = screen.getByRole('combobox');
284
+ await userEvent.click(trigger);
285
+ expect(screen.getByRole('listbox', { name: fieldLabel })).toBeInTheDocument();
286
+ });
287
+
288
+ it('should prefer explicit label over label ids', async () => {
289
+ const customLabelId = 'customLabelId';
290
+ renderSelectInput({
291
+ UNSAFE_triggerButtonProps: {
292
+ ...requiredTriggerButtonProps,
293
+ 'aria-labelledby': customLabelId,
294
+ 'aria-label': triggerLabel,
295
+ },
296
+ });
297
+ const trigger = screen.getByRole('combobox');
298
+ await userEvent.click(trigger);
299
+ expect(screen.getByRole('listbox', { name: triggerLabel })).toBeInTheDocument();
300
+ expect(screen.getByRole('listbox')).not.toHaveAttribute('aria-labelledby');
301
+ });
302
+
303
+ it('should have no label if none of the above are provided', async () => {
304
+ render(<SelectInput items={options} />);
305
+ const trigger = screen.getByRole('combobox');
306
+ await userEvent.click(trigger);
307
+ const listBox = screen.getByRole('listbox');
308
+ expect(listBox).not.toHaveAttribute('aria-label');
309
+ expect(listBox).not.toHaveAttribute('aria-labelledby');
310
+ });
311
+ });
219
312
  });
@@ -20,7 +20,7 @@ import {
20
20
  } from './SelectInput';
21
21
 
22
22
  const meta = {
23
- title: 'components/SelectInput',
23
+ title: 'Forms/SelectInput',
24
24
  component: SelectInput,
25
25
  tags: ['autodocs'],
26
26
  parameters: { actions: { argTypesRegex: '' } },
@@ -347,7 +347,7 @@ export const WithinField = {
347
347
  args: Months.args,
348
348
  decorators: [
349
349
  (Story) => (
350
- <Field message="Something went wrong" sentiment="negative">
350
+ <Field message="Something went wrong" sentiment="negative" label="Month">
351
351
  <Story />
352
352
  </Field>
353
353
  ),
@@ -258,8 +258,9 @@ export function SelectInput<T = string, M extends boolean = false>({
258
258
  onClose,
259
259
  onClear,
260
260
  }: SelectInputProps<T, M>) {
261
- const inputAttributes = useInputAttributes();
261
+ const inputAttributes = useInputAttributes({ nonLabelable: true });
262
262
  const id = idProp ?? inputAttributes.id;
263
+
263
264
  const [open, setOpen] = useState(false);
264
265
 
265
266
  const initialized = useRef(false);
@@ -295,6 +296,35 @@ export function SelectInput<T = string, M extends boolean = false>({
295
296
  const listboxRef = useRef<HTMLDivElement>(null);
296
297
  const controllerRef = filterable ? searchInputRef : listboxRef;
297
298
 
299
+ /**
300
+ * Attempts to resolve the `listbox` label
301
+ * @see https://storybook.wise.design/?path=/docs/forms-selectinput-accessibility--docs#labelling
302
+ */
303
+ const getListBoxLabelProps = (): {
304
+ listBoxLabel?: string;
305
+ listBoxLabelledBy?: string;
306
+ } => {
307
+ if (UNSAFE_triggerButtonProps?.['aria-label']) {
308
+ return {
309
+ listBoxLabel: UNSAFE_triggerButtonProps['aria-label'],
310
+ };
311
+ }
312
+
313
+ if (UNSAFE_triggerButtonProps?.['aria-labelledby']) {
314
+ return {
315
+ listBoxLabelledBy: UNSAFE_triggerButtonProps['aria-labelledby'],
316
+ };
317
+ }
318
+
319
+ if (inputAttributes['aria-labelledby']) {
320
+ return {
321
+ listBoxLabelledBy: inputAttributes['aria-labelledby'],
322
+ };
323
+ }
324
+
325
+ return {};
326
+ };
327
+
298
328
  return (
299
329
  <ListboxBase
300
330
  name={name}
@@ -388,7 +418,7 @@ export function SelectInput<T = string, M extends boolean = false>({
388
418
  }}
389
419
  >
390
420
  <SelectInputOptions
391
- id={`${id}Search`}
421
+ id={id ? `${id}Search` : undefined}
392
422
  items={items}
393
423
  renderValue={renderValue}
394
424
  renderFooter={renderFooter}
@@ -398,6 +428,7 @@ export function SelectInput<T = string, M extends boolean = false>({
398
428
  listboxRef={listboxRef}
399
429
  filterQuery={deferredFilterQuery}
400
430
  onFilterChange={setFilterQuery}
431
+ {...getListBoxLabelProps()}
401
432
  />
402
433
  </OptionsOverlay>
403
434
  );
@@ -496,6 +527,8 @@ interface SelectInputOptionsProps<T = string>
496
527
  listboxRef: React.MutableRefObject<HTMLDivElement | null>;
497
528
  filterQuery: string;
498
529
  onFilterChange: (query: string) => void;
530
+ listBoxLabel?: string;
531
+ listBoxLabelledBy?: string;
499
532
  }
500
533
 
501
534
  function SelectInputOptions<T = string>({
@@ -509,6 +542,8 @@ function SelectInputOptions<T = string>({
509
542
  listboxRef,
510
543
  filterQuery,
511
544
  onFilterChange,
545
+ listBoxLabel,
546
+ listBoxLabelledBy,
512
547
  }: SelectInputOptionsProps<T>) {
513
548
  const intl = useIntl();
514
549
 
@@ -662,6 +697,8 @@ function SelectInputOptions<T = string>({
662
697
  id={listboxId}
663
698
  role="listbox"
664
699
  aria-orientation="vertical"
700
+ aria-label={listBoxLabel}
701
+ aria-labelledby={listBoxLabelledBy}
665
702
  tabIndex={0}
666
703
  className="np-select-input-listbox"
667
704
  >
@@ -1,4 +1,4 @@
1
- import { render, screen } from '../test-utils';
1
+ import { render, screen, within } from '../test-utils';
2
2
 
3
3
  import InstructionsList from '.';
4
4
 
@@ -34,8 +34,16 @@ describe('InstructionsList', () => {
34
34
 
35
35
  const instructions = container.querySelectorAll('.instruction');
36
36
  expect(instructions).toHaveLength(2);
37
- expect(instructions[0]).toHaveAttribute('aria-label', dos[0]['aria-label']);
38
- expect(instructions[1]).toHaveAttribute('aria-label', donts[0]['aria-label']);
37
+ expect(
38
+ within(instructions[0] as HTMLElement).getByRole('graphics-symbol', {
39
+ name: dos[0]['aria-label'],
40
+ }),
41
+ ).toBeInTheDocument();
42
+ expect(
43
+ within(instructions[1] as HTMLElement).getByRole('graphics-symbol', {
44
+ name: donts[0]['aria-label'],
45
+ }),
46
+ ).toBeInTheDocument();
39
47
  });
40
48
 
41
49
  it('should render donts first when sort is set to `dontsFirst`', () => {
@@ -48,7 +56,15 @@ describe('InstructionsList', () => {
48
56
 
49
57
  const instructions = container.querySelectorAll('.instruction');
50
58
  expect(instructions).toHaveLength(2);
51
- expect(instructions[0]).toHaveAttribute('aria-label', donts[0]['aria-label']);
52
- expect(instructions[1]).toHaveAttribute('aria-label', dos[0]['aria-label']);
59
+ expect(
60
+ within(instructions[0] as HTMLElement).getByRole('graphics-symbol', {
61
+ name: donts[0]['aria-label'],
62
+ }),
63
+ ).toBeInTheDocument();
64
+ expect(
65
+ within(instructions[1] as HTMLElement).getByRole('graphics-symbol', {
66
+ name: dos[0]['aria-label'],
67
+ }),
68
+ ).toBeInTheDocument();
53
69
  });
54
70
  });
@@ -57,11 +57,19 @@ function Instruction({ item, type }: { item: ReactNode | InstructionNode; type:
57
57
  const isInstructionNode =
58
58
  typeof item === 'object' && item !== null && 'content' in item && 'aria-label' in item;
59
59
  return (
60
- <li className="instruction" aria-label={isInstructionNode ? item['aria-label'] : undefined}>
60
+ <li className="instruction">
61
61
  {type === 'do' ? (
62
- <DoIcon size={24} className={type} />
62
+ <DoIcon
63
+ size={24}
64
+ className={type}
65
+ title={isInstructionNode ? item['aria-label'] : undefined}
66
+ />
63
67
  ) : (
64
- <DontIcon size={24} className={type} />
68
+ <DontIcon
69
+ size={24}
70
+ className={type}
71
+ title={isInstructionNode ? item['aria-label'] : undefined}
72
+ />
65
73
  )}
66
74
  <Body className="text-primary" type={Typography.BODY_LARGE}>
67
75
  {isInstructionNode ? item.content : item}
@@ -137,4 +137,13 @@ describe('MoneyInput', () => {
137
137
  messages.selectCurrencyLabel.defaultMessage,
138
138
  );
139
139
  });
140
+
141
+ it('should have a listbox label', async () => {
142
+ render(<MoneyInput {...props} />);
143
+ const trigger = screen.getByRole('combobox');
144
+ await userEvent.click(trigger);
145
+ const triggerLabel = trigger.getAttribute('aria-label');
146
+ expect(triggerLabel).toBeTruthy();
147
+ expect(screen.getByRole('listbox', { name: triggerLabel ?? '' })).toBeInTheDocument();
148
+ });
140
149
  });
@@ -35,15 +35,15 @@ exports[`OverlayHeader renders as expected 1`] = `
35
35
  type="button"
36
36
  >
37
37
  <span
38
- aria-hidden="true"
39
38
  class="tw-icon tw-icon-cross "
40
39
  data-testid="cross-icon"
41
- role="presentation"
42
40
  >
43
41
  <svg
42
+ aria-hidden="true"
44
43
  fill="currentColor"
45
44
  focusable="false"
46
45
  height="24"
46
+ role="none"
47
47
  viewBox="0 0 24 24"
48
48
  width="24"
49
49
  >