@hyphen/hyphen-components 2.16.3 → 2.18.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.
@@ -4,457 +4,405 @@ import { fireEvent, render, screen } from '@testing-library/react';
4
4
 
5
5
  import React from 'react';
6
6
 
7
+ const renderButton = (props = {}) => render(<Button {...props} />);
8
+ const getButton = (text: string): HTMLButtonElement =>
9
+ screen.getByText(text).closest('button') as HTMLButtonElement;
10
+ const getAnchor = (text: string): HTMLAnchorElement =>
11
+ screen.getByText(text).closest('a') as HTMLAnchorElement;
12
+
7
13
  describe('Button', () => {
8
- describe('html button type', () => {
9
- test('is set to button', () => {
10
- render(<Button>Button</Button>);
14
+ describe('HTML Button Type', () => {
15
+ test('is set to button by default', () => {
16
+ renderButton({ children: 'Button' });
11
17
  const testBtn = screen.getByRole('button');
12
- expect(testBtn.getAttribute('type')).toBe('button');
18
+ expect(testBtn).toHaveAttribute('type', 'button');
13
19
  });
14
20
 
15
- test('is set to "submit" if specified', () => {
16
- render(<Button type="submit">Submit Button</Button>);
17
-
21
+ test('is set to submit if specified', () => {
22
+ renderButton({ type: 'submit', children: 'Submit Button' });
18
23
  const testBtn = screen.getByRole('button');
19
- expect(testBtn.getAttribute('type')).toBe('submit');
24
+ expect(testBtn).toHaveAttribute('type', 'submit');
20
25
  });
21
26
 
22
- test('is set to "reset" if specified', () => {
23
- render(<Button type="reset">Reset Button</Button>);
24
-
27
+ test('is set to reset if specified', () => {
28
+ renderButton({ type: 'reset', children: 'Reset Button' });
25
29
  const testBtn = screen.getByRole('button');
26
- expect(testBtn.getAttribute('type')).toBe('reset');
30
+ expect(testBtn).toHaveAttribute('type', 'reset');
27
31
  });
28
32
 
29
- test('is not set if "as" prop is an anchor tag', () => {
30
- render(
31
- <Button as="a" href="https://www.hyphen.ai">
32
- link button
33
- </Button>
34
- );
33
+ test('is not set if as prop is an anchor tag', () => {
34
+ renderButton({
35
+ as: 'a',
36
+ href: 'https://www.hyphen.ai',
37
+ children: 'link button',
38
+ });
35
39
  const testBtn = screen.getByText('link button').parentElement;
36
40
  expect(testBtn).not.toHaveAttribute('type');
37
41
  });
38
42
  });
39
43
 
40
- describe('with Icon', () => {
41
- test('Renders an icon prefix if specified', () => {
42
- render(<Button iconPrefix="alarm">Alarm Button</Button>);
44
+ describe('With Icon', () => {
45
+ test('renders an icon prefix if specified', () => {
46
+ renderButton({ iconPrefix: 'alarm', children: 'Alarm Button' });
43
47
  expect(screen.getByTestId('prefixIcon')).toBeInTheDocument();
44
48
  });
45
49
 
46
- test('Renders an icon suffix if specified', () => {
47
- render(<Button iconSuffix="alarm">Alarm Button</Button>);
50
+ test('renders an icon suffix if specified', () => {
51
+ renderButton({ iconSuffix: 'alarm', children: 'Alarm Button' });
48
52
  expect(screen.getByTestId('suffixIcon')).toBeInTheDocument();
49
53
  });
50
54
 
51
- test('Renders icon prefix and suffix if specified', () => {
52
- render(
53
- <Button iconPrefix="alarm" iconSuffix="check">
54
- Suffix Prefix Icon Button
55
- </Button>
56
- );
55
+ test('renders icon prefix and suffix if specified', () => {
56
+ renderButton({
57
+ iconPrefix: 'alarm',
58
+ iconSuffix: 'check',
59
+ children: 'Suffix Prefix Icon Button',
60
+ });
57
61
  expect(screen.getByTestId('prefixIcon')).toBeInTheDocument();
58
62
  expect(screen.getByTestId('suffixIcon')).toBeInTheDocument();
59
63
  });
60
64
  });
61
65
 
62
66
  describe('Sizes', () => {
63
- BUTTON_SIZES.map((size) =>
64
- describe(`${BUTTON_SIZES}`, () => {
65
- test(`it has a ${size} class applied to it`, () => {
66
- render(<Button size={size}>{`${size} Button`}</Button>);
67
-
68
- const btn = screen.getByText(`${size} Button`).closest('button');
67
+ BUTTON_SIZES.forEach((size) => {
68
+ test(`it has a ${size} class applied to it`, () => {
69
+ renderButton({ size, children: `${size} Button` });
70
+ const btn = getButton(`${size} Button`);
71
+ expect(btn).toHaveClass(`size-${size}`);
72
+ });
73
+ });
69
74
 
70
- expect(btn?.getAttribute('class')).toContain(`size-${size}`);
71
- });
72
- })
73
- );
74
-
75
- test('It applies responsive classes', () => {
76
- render(
77
- <Button size={{ base: 'lg', tablet: 'sm', desktop: 'md', hd: 'lg' }}>
78
- button
79
- </Button>
75
+ test('applies responsive classes', () => {
76
+ renderButton({
77
+ size: { base: 'lg', tablet: 'sm', desktop: 'md', hd: 'lg' },
78
+ children: 'button',
79
+ });
80
+ const btn = getButton('button');
81
+ expect(btn).toHaveClass(
82
+ 'size-lg',
83
+ 'size-sm-tablet',
84
+ 'size-md-desktop',
85
+ 'size-lg-hd'
80
86
  );
81
-
82
- const btn = screen.getByText('button').closest('button');
83
-
84
- expect(btn?.getAttribute('class')).toContain('size-lg');
85
- expect(btn?.getAttribute('class')).toContain('size-sm-tablet');
86
- expect(btn?.getAttribute('class')).toContain('size-md-desktop');
87
- expect(btn?.getAttribute('class')).toContain('size-lg-hd');
88
87
  });
89
88
  });
90
89
 
91
90
  describe('Variants', () => {
92
- BUTTON_VARIANTS.map((variant) =>
93
- describe(`${BUTTON_VARIANTS}`, () => {
94
- test(`it has a ${variant} class applied to it`, () => {
95
- render(<Button variant={variant}>{`${variant} Button`}</Button>);
96
-
97
- const btn = screen.getByText(`${variant} Button`).closest('button');
98
-
99
- expect(btn?.getAttribute('class')).toContain(variant);
100
- });
101
- })
102
- );
91
+ BUTTON_VARIANTS.forEach((variant) => {
92
+ test(`it has a ${variant} class applied to it`, () => {
93
+ renderButton({ variant, children: `${variant} Button` });
94
+ const btn = getButton(`${variant} Button`);
95
+ expect(btn).toHaveClass(variant);
96
+ });
97
+ });
103
98
  });
104
99
 
105
100
  describe('Callback Handling', () => {
106
101
  describe('onClick', () => {
107
- test('it fires onClick callback', () => {
102
+ test('fires onClick callback', () => {
108
103
  const mockedHandleClick = jest.fn();
109
-
110
- render(<Button onClick={mockedHandleClick}>Click</Button>);
111
-
112
- const buttonElement = screen.getByText('Click').closest('button');
113
- if (buttonElement) {
114
- fireEvent.click(buttonElement);
115
- }
116
-
117
- expect(mockedHandleClick).toBeCalledTimes(1);
104
+ renderButton({ onClick: mockedHandleClick, children: 'Click' });
105
+ const buttonElement: HTMLButtonElement = getButton('Click');
106
+ fireEvent.click(buttonElement);
107
+ expect(mockedHandleClick).toHaveBeenCalledTimes(1);
118
108
  });
119
109
 
120
- test('it does not fire function if onClick callback not provided', () => {
110
+ test('does not fire function if onClick callback not provided', () => {
121
111
  const mockedHandleClick = jest.fn();
122
-
123
- render(<Button>Click</Button>);
124
-
125
- const buttonElement = screen.getByText('Click').closest('button');
126
- if (buttonElement) {
127
- fireEvent.click(buttonElement);
128
- }
129
-
130
- expect(mockedHandleClick).toBeCalledTimes(0);
112
+ renderButton({ children: 'Click' });
113
+ const buttonElement = getButton('Click');
114
+ fireEvent.click(buttonElement);
115
+ expect(mockedHandleClick).toHaveBeenCalledTimes(0);
131
116
  });
132
117
 
133
- test('it prevents default event behavior if specified by onClick', async () => {
118
+ test('prevents default event behavior if specified by onClick', () => {
134
119
  const mockedHandleClick = jest.fn((event) => event.preventDefault());
135
- const mockedNavigate = jest.fn(() => null);
136
-
137
- render(
138
- <Button navigate={mockedNavigate} onClick={mockedHandleClick}>
139
- Click
140
- </Button>
141
- );
142
- const buttonElement = screen.getByText('Click').closest('button');
143
- if (buttonElement) {
144
- fireEvent.click(buttonElement);
145
- }
146
-
147
- expect(mockedHandleClick).toBeCalledTimes(1);
120
+ const mockedNavigate = jest.fn();
121
+ renderButton({
122
+ navigate: mockedNavigate,
123
+ onClick: mockedHandleClick,
124
+ children: 'Click',
125
+ });
126
+ const buttonElement = getButton('Click');
127
+ fireEvent.click(buttonElement);
128
+ expect(mockedHandleClick).toHaveBeenCalledTimes(1);
148
129
  expect(mockedNavigate).not.toBeCalled();
149
130
  });
150
131
  });
151
132
 
152
133
  describe('onFocus', () => {
153
- test('it fires onFocus callback', () => {
134
+ test('fires onFocus callback', () => {
154
135
  const mockedHandleFocus = jest.fn();
155
-
156
- render(<Button onFocus={mockedHandleFocus}>Focus</Button>);
157
-
158
- const buttonElement = screen.getByText('Focus').closest('button');
159
- if (buttonElement) {
160
- fireEvent.focus(buttonElement);
161
- }
162
-
163
- expect(mockedHandleFocus).toBeCalledTimes(1);
136
+ renderButton({ onFocus: mockedHandleFocus, children: 'Focus' });
137
+ const buttonElement = getButton('Focus');
138
+ fireEvent.focus(buttonElement);
139
+ expect(mockedHandleFocus).toHaveBeenCalledTimes(1);
164
140
  });
165
141
 
166
- test('it does not fire function of onFocus callback not provided', () => {
142
+ test('does not fire function if onFocus callback not provided', () => {
167
143
  const mockedHandleFocus = jest.fn();
168
-
169
- render(<Button>Focus</Button>);
170
-
171
- const buttonElement = screen.getByText('Focus').closest('button');
172
- if (buttonElement) {
173
- fireEvent.focus(buttonElement);
174
- }
175
-
176
- expect(mockedHandleFocus).toBeCalledTimes(0);
144
+ renderButton({ children: 'Focus' });
145
+ const buttonElement = getButton('Focus');
146
+ fireEvent.focus(buttonElement);
147
+ expect(mockedHandleFocus).toHaveBeenCalledTimes(0);
177
148
  });
178
149
  });
179
150
 
180
151
  describe('onBlur', () => {
181
- test('it fires onBlur callback', () => {
152
+ test('fires onBlur callback', () => {
182
153
  const mockedHandleBlur = jest.fn();
183
-
184
- render(<Button onBlur={mockedHandleBlur}>Blur</Button>);
185
-
186
- const buttonElement = screen.getByText('Blur').closest('button');
187
- if (buttonElement) {
188
- fireEvent.blur(buttonElement);
189
- }
190
-
191
- expect(mockedHandleBlur).toBeCalledTimes(1);
154
+ renderButton({ onBlur: mockedHandleBlur, children: 'Blur' });
155
+ const buttonElement = getButton('Blur');
156
+ fireEvent.blur(buttonElement);
157
+ expect(mockedHandleBlur).toHaveBeenCalledTimes(1);
192
158
  });
193
159
 
194
- test('it does not fire onBlur callback if not provided', () => {
160
+ test('does not fire onBlur callback if not provided', () => {
195
161
  const mockedHandleBlur = jest.fn();
196
-
197
- render(<Button>Blur</Button>);
198
-
199
- const buttonElement = screen.getByText('Blur').closest('button');
200
- if (buttonElement) {
201
- fireEvent.blur(buttonElement);
202
- }
203
-
204
- expect(mockedHandleBlur).toBeCalledTimes(0);
162
+ renderButton({ children: 'Blur' });
163
+ const buttonElement = getButton('Blur');
164
+ fireEvent.blur(buttonElement);
165
+ expect(mockedHandleBlur).toHaveBeenCalledTimes(0);
205
166
  });
206
167
  });
207
168
  });
208
169
 
209
170
  describe('States', () => {
210
171
  describe('Default', () => {
211
- test('it renders the button with simple text', () => {
212
- render(<Button>Button!</Button>);
172
+ test('renders the button with simple text', () => {
173
+ renderButton({ children: 'Button!' });
213
174
  const buttonElement = screen.getByText('Button!');
214
-
215
175
  expect(buttonElement).toBeInTheDocument();
216
176
  });
217
177
 
218
- test('it renders the button with nested dom nodes', () => {
219
- render(
220
- <Button>
178
+ test('renders the button with nested DOM nodes', () => {
179
+ renderButton({
180
+ children: (
221
181
  <div className="buttonLoadingIndicator">
222
- <div>Im a nested dom node!</div>
182
+ <div>I'm a nested DOM node!</div>
223
183
  </div>
224
- </Button>
225
- );
226
- const buttonElement = screen.getByText('Im a nested dom node!');
227
-
184
+ ),
185
+ });
186
+ const buttonElement = screen.getByText("I'm a nested DOM node!");
228
187
  expect(buttonElement).toBeInTheDocument();
229
188
  });
230
189
 
231
- test('it does not have a disabled attribute', () => {
232
- render(<Button>Not Disabled Button</Button>);
233
-
234
- expect(
235
- screen.getByText('Not Disabled Button').closest('button')
236
- ).not.toBeDisabled();
190
+ test('does not have a disabled attribute', () => {
191
+ renderButton({ children: 'Not Disabled Button' });
192
+ expect(getButton('Not Disabled Button')).not.toBeDisabled();
237
193
  });
238
194
 
239
- test('it renders an empty button when no children are passed', () => {
240
- render(<Button />);
195
+ test('renders an empty button when no children are passed', () => {
196
+ renderButton();
241
197
  const buttonElement = screen.getByRole('button');
242
-
243
198
  expect(buttonElement).toBeInTheDocument();
244
- expect(buttonElement.innerText).toBe(undefined);
199
+ expect(buttonElement).toBeEmptyDOMElement();
245
200
  });
246
201
  });
247
202
 
248
203
  describe('Full Width', () => {
249
- test('it has a fullWidth class applied to it', () => {
250
- render(<Button fullWidth>Full Width Button</Button>);
251
-
252
- const fullWidthBtn = screen
253
- .getByText('Full Width Button')
254
- .closest('button');
255
-
256
- expect(fullWidthBtn?.getAttribute('class')).toContain('full-width');
204
+ test('has a fullWidth class applied to it', () => {
205
+ renderButton({ fullWidth: true, children: 'Full Width Button' });
206
+ const fullWidthBtn = getButton('Full Width Button');
207
+ expect(fullWidthBtn).toHaveClass('full-width');
257
208
  });
258
209
  });
259
210
 
260
211
  describe('Custom ClassName', () => {
261
- test('if a ClassName is provided, its added to the button', () => {
262
- render(<Button className="custom-class">Custom ClassName</Button>);
263
-
264
- const customClassNameBtn = screen
265
- .getByText('Custom ClassName')
266
- .closest('button');
267
-
268
- expect(customClassNameBtn?.getAttribute('class')).toContain(
269
- 'custom-class'
270
- );
212
+ test('adds custom className to the button', () => {
213
+ renderButton({
214
+ className: 'custom-class',
215
+ children: 'Custom ClassName',
216
+ });
217
+ const customClassNameBtn = getButton('Custom ClassName');
218
+ expect(customClassNameBtn).toHaveClass('custom-class');
271
219
  });
272
220
  });
273
221
 
274
222
  describe('Disabled', () => {
275
- test('it has a disabled attribute', () => {
276
- render(<Button isDisabled>Disabled Button</Button>);
223
+ test('has a disabled attribute', () => {
224
+ renderButton({ isDisabled: true, children: 'Disabled Button' });
225
+ expect(getButton('Disabled Button')).toBeDisabled();
226
+ });
277
227
 
278
- expect(
279
- screen.getByText('Disabled Button').closest('button')
280
- ).toBeDisabled();
228
+ test('applies aria-disabled attribute when button is disabled', () => {
229
+ renderButton({ isDisabled: true, children: 'Aria Disabled Button' });
230
+ const buttonElement = getButton('Aria Disabled Button');
231
+ expect(buttonElement).toHaveAttribute('aria-disabled', 'true');
281
232
  });
282
233
  });
283
234
 
284
235
  describe('Loading', () => {
285
- test('it renders the spinning loading indicator', () => {
286
- render(<Button isLoading>Button is loading</Button>);
236
+ test('renders the spinning loading indicator', () => {
237
+ renderButton({ isLoading: true, children: 'Button is loading' });
287
238
  const spinnerElement = document.getElementsByClassName('spinner')[0];
288
239
  expect(spinnerElement).toBeInTheDocument();
289
240
  });
290
241
 
291
- test('it renders the grey spinning indicator if button variant is secondary', () => {
292
- render(
293
- <Button isLoading variant="secondary">
294
- Button is loading
295
- </Button>
296
- );
242
+ test('renders the grey spinning indicator if button variant is secondary', () => {
243
+ renderButton({
244
+ isLoading: true,
245
+ variant: 'secondary',
246
+ children: 'Button is loading',
247
+ });
297
248
  const spinnerElement = document.getElementsByClassName('spinner')[0];
298
249
  expect(spinnerElement).toBeInTheDocument();
299
250
  });
300
251
 
301
- test('it keeps the button text in the dom so the button width does not change', () => {
302
- render(<Button isLoading>Button is loading</Button>);
252
+ test('keeps the button text in the DOM so the button width does not change', () => {
253
+ renderButton({ isLoading: true, children: 'Button is loading' });
303
254
  expect(screen.getByText('Button is loading')).toBeInTheDocument();
304
255
  });
305
256
 
306
- test('it renders white spinning indicator when button is primary', () => {
307
- render(
308
- <Button variant="primary" isLoading>
309
- Button is loading
310
- </Button>
311
- );
257
+ test('renders white spinning indicator when button is primary', () => {
258
+ renderButton({
259
+ isLoading: true,
260
+ variant: 'primary',
261
+ children: 'Button is loading',
262
+ });
312
263
  const spinnerElement = document.getElementsByClassName('spinner')[0];
313
264
  expect(spinnerElement).toBeInTheDocument();
314
265
  });
315
266
 
316
- test('it renders white spinning indicator when button is danger', () => {
317
- render(
318
- <Button variant="danger" isLoading>
319
- Button is loading
320
- </Button>
321
- );
267
+ test('renders white spinning indicator when button is danger', () => {
268
+ renderButton({
269
+ isLoading: true,
270
+ variant: 'danger',
271
+ children: 'Button is loading',
272
+ });
322
273
  const spinnerElement = document.getElementsByClassName('spinner')[0];
323
274
  expect(spinnerElement).toBeInTheDocument();
324
275
  });
325
276
  });
326
277
 
327
278
  describe('Disabled and Loading', () => {
328
- test('it has a disabled attribute', () => {
329
- render(
330
- <Button isDisabled isLoading>
331
- Disabled and Loading Button
332
- </Button>
333
- );
334
-
335
- expect(
336
- screen.getByText('Disabled and Loading Button').closest('button')
337
- ).toBeDisabled();
279
+ test('has a disabled attribute', () => {
280
+ renderButton({
281
+ isDisabled: true,
282
+ isLoading: true,
283
+ children: 'Disabled and Loading Button',
284
+ });
285
+ expect(getButton('Disabled and Loading Button')).toBeDisabled();
338
286
  });
339
287
  });
340
288
 
341
289
  describe('Color Variations', () => {
342
- test('Renders button with default variant neutral', () => {
343
- render(<Button>primary</Button>);
344
-
345
- expect(screen.getByText('primary').closest('button')).toHaveClass(
346
- 'primary'
347
- );
290
+ test('renders button with default variant primary', () => {
291
+ renderButton({ children: 'primary' });
292
+ expect(getButton('primary')).toHaveClass('primary');
348
293
  });
349
294
 
350
- const variants = [
295
+ const variants: ButtonVariant[] = [
351
296
  'primary',
352
297
  'secondary',
353
298
  'tertiary',
354
299
  'danger',
355
- ] as ButtonVariant[];
300
+ ];
356
301
  variants.forEach((variant) => {
357
- test(`It renders component with variant: ${variant} when passed`, () => {
358
- render(<Button variant={variant}>{variant}</Button>);
359
- expect(screen.getByText(variant).closest('button')).toHaveClass(
360
- variant
361
- );
302
+ test(`renders component with variant: ${variant} when passed`, () => {
303
+ renderButton({ variant, children: variant });
304
+ expect(getButton(variant)).toHaveClass(variant);
362
305
  });
363
306
  });
364
307
  });
365
308
 
366
309
  describe('Anchor', () => {
367
- test('it renders an anchor tag if as prop `a` is passed', () => {
368
- render(
369
- <Button href="http://hyphen.ai" as="a">
370
- hey there
371
- </Button>
372
- );
310
+ test('renders an anchor tag if as prop `a` is passed', () => {
311
+ renderButton({
312
+ as: 'a',
313
+ href: 'http://hyphen.ai',
314
+ children: 'hey there',
315
+ });
373
316
  const buttonElement = screen.getByRole('link');
374
-
375
317
  expect(buttonElement).toBeInTheDocument();
376
318
  });
377
319
 
378
- test('it does not have a button type attribute if as prop `a` is passed', () => {
379
- render(
380
- <Button href="http://hyphen.ai" as="a">
381
- hey there
382
- </Button>
383
- );
320
+ test('does not have a button type attribute if as prop `a` is passed', () => {
321
+ renderButton({
322
+ as: 'a',
323
+ href: 'http://hyphen.ai',
324
+ children: 'hey there',
325
+ });
384
326
  const buttonElement = screen.getByRole('link');
385
-
386
- expect(buttonElement.getAttribute('type')).toBe(null);
327
+ expect(buttonElement).not.toHaveAttribute('type');
387
328
  });
388
329
 
389
- test('it renders a target attribute if one is passed, the element is an anchor, and there is a href', () => {
390
- render(
391
- <Button href="http://hyphen.ai" as="a" target="_blank">
392
- hey there
393
- </Button>
394
- );
330
+ test('renders a target attribute if one is passed, the element is an anchor, and there is a href', () => {
331
+ renderButton({
332
+ as: 'a',
333
+ href: 'http://hyphen.ai',
334
+ target: '_blank',
335
+ children: 'hey there',
336
+ });
395
337
  const buttonElement = screen.getByRole('link');
396
-
397
- expect(buttonElement).toBeInTheDocument();
398
- expect(buttonElement).toHaveAttribute('target');
338
+ expect(buttonElement).toHaveAttribute('target', '_blank');
399
339
  });
400
340
 
401
- test('it does not render a target attribute if the element is not an anchor', () => {
402
- render(
403
- <Button href="http://hyphen.ai" target="_blank">
404
- hey there
405
- </Button>
406
- );
341
+ test('does not render a target attribute if the element is not an anchor', () => {
342
+ renderButton({
343
+ href: 'http://hyphen.ai',
344
+ target: '_blank',
345
+ children: 'hey there',
346
+ });
407
347
  const buttonElement = screen.getByRole('button');
408
-
409
- expect(buttonElement).toBeInTheDocument();
410
348
  expect(buttonElement).not.toHaveAttribute('target');
411
349
  });
412
350
 
413
- test('it does not render a target attribute if the element does not have an href', () => {
414
- render(
415
- <Button as="a" target="_blank">
416
- hey there
417
- </Button>
418
- );
351
+ test('does not render a target attribute if the element does not have an href', () => {
352
+ renderButton({ as: 'a', target: '_blank', children: 'hey there' });
419
353
  const buttonElement = screen.getByText('hey there');
420
-
421
- expect(buttonElement).toBeInTheDocument();
422
354
  expect(buttonElement).not.toHaveAttribute('target');
423
355
  });
356
+
357
+ describe('Rel Attribute', () => {
358
+ test('applies rel attribute when target is _blank', () => {
359
+ renderButton({
360
+ as: 'a',
361
+ href: 'http://hyphen.ai',
362
+ target: '_blank',
363
+ children: 'Link with rel',
364
+ });
365
+ const anchorElement = getAnchor('Link with rel');
366
+ expect(anchorElement).toHaveAttribute('rel', 'noopener noreferrer');
367
+ });
368
+ });
424
369
  });
425
370
  });
426
371
 
427
372
  describe('React Router', () => {
428
- it('fires navigate callback when included', () => {
429
- const mockedNavigate = jest.fn(() => {});
430
- render(
431
- <Button as="a" navigate={mockedNavigate} href="/">
432
- react router link
433
- </Button>
434
- );
435
-
436
- const anchorElement = screen.getByText('react router link').closest('a');
437
- if (anchorElement) {
438
- fireEvent.click(anchorElement);
439
- }
440
-
441
- expect(mockedNavigate).toBeCalledTimes(1);
373
+ test('fires navigate callback when included', () => {
374
+ const mockedNavigate = jest.fn();
375
+ renderButton({
376
+ as: 'a',
377
+ navigate: mockedNavigate,
378
+ href: '/',
379
+ children: 'react router link',
380
+ });
381
+ const anchorElement = getAnchor('react router link');
382
+ fireEvent.click(anchorElement);
383
+ expect(mockedNavigate).toHaveBeenCalledTimes(1);
442
384
  });
443
385
 
444
- it('does not fire navigate callback if target is _blank', () => {
445
- const mockedNavigate = jest.fn(() => {});
446
- render(
447
- <Button as="a" navigate={mockedNavigate} href="/" target="_blank">
448
- react router link
449
- </Button>
450
- );
451
-
452
- const anchorElement = screen.getByText('react router link').closest('a');
453
- if (anchorElement) {
454
- fireEvent.click(anchorElement);
455
- }
386
+ test('does not fire navigate callback if target is _blank', () => {
387
+ const mockedNavigate = jest.fn();
388
+ renderButton({
389
+ as: 'a',
390
+ navigate: mockedNavigate,
391
+ href: '/',
392
+ target: '_blank',
393
+ children: 'react router link',
394
+ });
395
+ const anchorElement = getAnchor('react router link');
396
+ fireEvent.click(anchorElement);
397
+ expect(mockedNavigate).toHaveBeenCalledTimes(0);
398
+ });
399
+ });
456
400
 
457
- expect(mockedNavigate).toBeCalledTimes(0);
401
+ describe('Role Attribute', () => {
402
+ test('applies role attribute', () => {
403
+ renderButton({ role: 'button', children: 'Button with Role' });
404
+ const buttonElement = getButton('Button with Role');
405
+ expect(buttonElement).toHaveAttribute('role', 'button');
458
406
  });
459
407
  });
460
408
  });