@aarhus-university/au-lib-react-components 12.5.1 → 12.6.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 (115) hide show
  1. package/.claude/settings.local.json +12 -0
  2. package/.eslintrc.js +35 -35
  3. package/.storybook/main.js +34 -34
  4. package/.storybook/preview.js +17 -17
  5. package/.vscode/settings.json +22 -0
  6. package/README.md +19 -19
  7. package/__tests__/jest/AUButtonComponent.test.tsx +165 -165
  8. package/__tests__/jest/AUDynamicContentComponent.test.tsx +386 -0
  9. package/__tests__/jest/AUErrorComponent.test.tsx +142 -142
  10. package/__tests__/jest/AUModalComponent.test.tsx +186 -186
  11. package/__tests__/jest/AUNotificationComponent.test.tsx +115 -115
  12. package/__tests__/jest/AUSpinnerComponent.test.tsx +57 -57
  13. package/__tests__/jest/AUToolbarComponent.test.tsx +46 -46
  14. package/__tests__/jest/context.test.ts +25 -25
  15. package/__tests__/jest/helpers.test.ts +15 -15
  16. package/__tests__/jest/setupTests.ts +2 -2
  17. package/babel.config.js +8 -8
  18. package/build/umd/all.css +3 -2
  19. package/build/umd/all.css.map +1 -7
  20. package/build/umd/all.js +2 -45
  21. package/build/umd/all.js.map +1 -7
  22. package/build/umd/alphabox.js +2 -45
  23. package/build/umd/alphabox.js.map +1 -7
  24. package/build/umd/databox.js +2 -45
  25. package/build/umd/databox.js.map +1 -7
  26. package/build/umd/diagramme.js +2 -44
  27. package/build/umd/diagramme.js.map +1 -7
  28. package/build/umd/flowbox.js +2 -44
  29. package/build/umd/flowbox.js.map +1 -7
  30. package/build/umd/universe.js +1 -1
  31. package/build-storybook.log +386 -386
  32. package/esbuild.mjs +22 -22
  33. package/package.json +107 -105
  34. package/src/components/AUAlertComponent.tsx +128 -128
  35. package/src/components/AUAutoSuggestComponent.js +148 -148
  36. package/src/components/AUButtonComponent.tsx +99 -97
  37. package/src/components/AUCalendarComponent.tsx +497 -497
  38. package/src/components/AUCharacterCountComponent.tsx +56 -56
  39. package/src/components/AUComboBoxComponent.tsx +195 -195
  40. package/src/components/AUContentToggleComponent.tsx +50 -50
  41. package/src/components/AUDatepickerComponent.tsx +124 -124
  42. package/src/components/AUDialogModalComponent.tsx +124 -124
  43. package/src/components/AUDynamicContentComponent.tsx +137 -0
  44. package/src/components/AUEditorComponent.tsx +126 -117
  45. package/src/components/AUErrorComponent.tsx +73 -73
  46. package/src/components/AUMobilePrefixComponent.tsx +20 -20
  47. package/src/components/AUModalComponent.tsx +72 -72
  48. package/src/components/AUNotificationComponent.tsx +44 -44
  49. package/src/components/AUReceiptComponent.tsx +34 -34
  50. package/src/components/AUSpinnerComponent.tsx +40 -40
  51. package/src/components/AUStepComponent.tsx +75 -75
  52. package/src/components/AUSubNavComponent.tsx +57 -57
  53. package/src/components/AUSubmitButtonContainerComponent.tsx +38 -38
  54. package/src/components/AUTabbedContentComponent.tsx +154 -154
  55. package/src/components/AUTableComponent.tsx +29 -29
  56. package/src/components/AUToastComponent.tsx +104 -104
  57. package/src/components/AUToolbarComponent.tsx +108 -108
  58. package/src/components/AUTruncatorComponent.tsx +141 -141
  59. package/src/components/wrapping/AUEmbedComponent.js +47 -47
  60. package/src/layout-2016/components/alphabox/AlphaBoxComponent.js +142 -143
  61. package/src/layout-2016/components/alphabox/AlphaBoxContentComponent.js +136 -136
  62. package/src/layout-2016/components/common/AUCollapsibleComponent.js +152 -152
  63. package/src/layout-2016/components/common/AUSpinnerComponent.js +103 -103
  64. package/src/layout-2016/components/databox/DataBoxAlphabetComponent.js +144 -144
  65. package/src/layout-2016/components/databox/DataBoxAssociationComponent.js +122 -122
  66. package/src/layout-2016/components/databox/DataBoxButtonComponent.js +157 -157
  67. package/src/layout-2016/components/databox/DataBoxComponent.js +297 -297
  68. package/src/layout-2016/components/databox/DataBoxGroupingComponent.js +64 -64
  69. package/src/layout-2016/components/databox/DataBoxSearchResultComponent.js +36 -36
  70. package/src/layout-2016/components/databox/DataBoxStackedAssociationComponent.js +54 -54
  71. package/src/layout-2016/components/databox/DataBoxSuggestionComponent.js +39 -39
  72. package/src/layout-2016/components/diagramme/AUDiagrammeComponent.js +309 -309
  73. package/src/layout-2016/components/flowbox/FlowBoxComponent.js +126 -126
  74. package/src/layout-2016/components/flowbox/FlowBoxPhoneComponent.js +104 -104
  75. package/src/layout-2016/lib/all.js +3 -3
  76. package/src/layout-2016/lib/au-alphabox.js +99 -100
  77. package/src/layout-2016/lib/au-databox.js +399 -400
  78. package/src/layout-2016/lib/au-diagramme.js +85 -85
  79. package/src/layout-2016/lib/au-flowbox.js +119 -93
  80. package/src/lib/context.tsx +59 -59
  81. package/src/lib/dates.ts +52 -52
  82. package/src/lib/helpers.ts +208 -208
  83. package/src/lib/hooks.ts +157 -157
  84. package/src/lib/i18n.ts +600 -600
  85. package/src/lib/portals.tsx +150 -150
  86. package/src/lib/tinymce.ts +84 -84
  87. package/src/lib/wrapping.ts +21 -21
  88. package/src/styles/_settings.scss +10 -10
  89. package/src/styles/alphabox.scss +222 -222
  90. package/src/styles/app.scss +7 -7
  91. package/src/styles/autosuggest.scss +57 -57
  92. package/src/styles/databox.scss +563 -563
  93. package/src/styles/diagramme.scss +119 -119
  94. package/src/styles/flowbox.scss +72 -72
  95. package/src/styles/maps.scss +395 -395
  96. package/stories/AUAlertComponent.stories.tsx +133 -133
  97. package/stories/AUAutoSuggestComponent.stories.tsx +95 -95
  98. package/stories/AUButtonComponent.stories.tsx +139 -139
  99. package/stories/AUCharacterCountComponent.stories.tsx +121 -121
  100. package/stories/AUComboBoxComponent.stories.tsx +101 -101
  101. package/stories/AUContentToggleComponent.stories.tsx +87 -87
  102. package/stories/AUDialogModalComponent.stories.tsx +75 -75
  103. package/stories/AUDynamicContentComponent.stories.tsx +119 -0
  104. package/stories/AUEditorComponent.stories.tsx +66 -66
  105. package/stories/AUErrorComponent.stories.tsx +132 -132
  106. package/stories/AUModalComponent.stories.tsx +160 -160
  107. package/stories/AUNotificationComponent.stories.tsx +151 -151
  108. package/stories/AUSpinnerComponent.stories.tsx +44 -44
  109. package/stories/AUStepComponent.stories.tsx +91 -91
  110. package/stories/AUToolbarComponent.stories.tsx +389 -389
  111. package/stories/AUTruncatorComponent.stories.tsx +123 -123
  112. package/stories/lib/helpers.tsx +146 -146
  113. package/tsconfig.json +46 -46
  114. package/webpack.config.js +88 -88
  115. package/src/lib/tracking.ts +0 -69
@@ -0,0 +1,386 @@
1
+ /* eslint-disable react/jsx-props-no-spreading */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any */
3
+ import React from 'react';
4
+ import { render, screen } from '@testing-library/react';
5
+ import '@testing-library/jest-dom';
6
+ import AUDynamicContentComponent, {
7
+ IDynamicContentProps,
8
+ IDynamicContentVideo,
9
+ IDynamicContentImage,
10
+ IDynamicContentInfoBox,
11
+ } from '../../src/components/AUDynamicContentComponent';
12
+
13
+ describe('<AUDynamicContentComponent />', () => {
14
+ const baseProps: IDynamicContentProps = {
15
+ name: 'Dynamic Content Section',
16
+ featuredContentDescription: '<p>This is a description</p>',
17
+ links: [
18
+ {
19
+ title: 'System Link',
20
+ description: 'A system link description',
21
+ url: 'https://example.com/system',
22
+ linkType: 'system',
23
+ },
24
+ {
25
+ title: 'Information Link',
26
+ description: 'An information link description',
27
+ url: 'https://example.com/info',
28
+ linkType: 'information',
29
+ },
30
+ ],
31
+ featuredContent: {
32
+ type: 'image',
33
+ url: 'https://example.com/image.jpg',
34
+ altText: 'Example image',
35
+ } as IDynamicContentImage,
36
+ };
37
+
38
+ describe('basic rendering', () => {
39
+ it('renders the component with all required props', () => {
40
+ const { container } = render(<AUDynamicContentComponent {...baseProps} />);
41
+
42
+ expect(screen.getByText('Dynamic Content Section')).toBeInTheDocument();
43
+ expect(screen.getByText('System Link')).toBeInTheDocument();
44
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
45
+ });
46
+
47
+ it('applies correct ARIA attributes', () => {
48
+ render(<AUDynamicContentComponent {...baseProps} />);
49
+
50
+ const section = screen.getByRole('region');
51
+ expect(section).toHaveAttribute('aria-labelledby', 'dynamic-content-heading');
52
+ expect(screen.getByRole('heading', { level: 3 })).toHaveAttribute(
53
+ 'id',
54
+ 'dynamic-content-heading',
55
+ );
56
+ });
57
+
58
+ it('renders the featured content description as HTML', () => {
59
+ const { container } = render(<AUDynamicContentComponent {...baseProps} />);
60
+
61
+ const description = container.querySelector('.dynamic-content__featured p');
62
+ expect(description).toBeInTheDocument();
63
+ expect(description?.textContent).toBe('This is a description');
64
+ });
65
+ });
66
+
67
+ describe('featured content variants', () => {
68
+ it('renders a video featured content', () => {
69
+ // Note: Backend/admin panel validates that video URLs are from Panopto or YouTube-nocookie
70
+ // This component is a thin client that renders what the backend provides
71
+ const videoContent: IDynamicContentVideo = {
72
+ type: 'video',
73
+ url: 'https://aarhusuniversitet.cloud.panopto.eu/Panopto/Pages/Embed.aspx?id=test-video-id',
74
+ };
75
+
76
+ const { container } = render(
77
+ <AUDynamicContentComponent
78
+ {...baseProps}
79
+ featuredContent={videoContent}
80
+ />,
81
+ );
82
+
83
+ const iframe = container.querySelector('iframe');
84
+ expect(iframe).toBeInTheDocument();
85
+ expect(iframe).toHaveAttribute('src', 'https://aarhusuniversitet.cloud.panopto.eu/Panopto/Pages/Embed.aspx?id=test-video-id');
86
+ expect(iframe).toHaveAttribute('title', 'Video player: Dynamic Content Section');
87
+ expect(iframe).toHaveAttribute('loading', 'lazy');
88
+ expect(iframe).toHaveAttribute('allowfullscreen');
89
+ });
90
+
91
+ it('renders an image featured content without optional fields', () => {
92
+ const imageContent: IDynamicContentImage = {
93
+ type: 'image',
94
+ url: 'https://example.com/image.jpg',
95
+ altText: 'Test image',
96
+ };
97
+
98
+ const { container } = render(
99
+ <AUDynamicContentComponent
100
+ {...baseProps}
101
+ featuredContent={imageContent}
102
+ />,
103
+ );
104
+
105
+ const img = container.querySelector('img');
106
+ expect(img).toBeInTheDocument();
107
+ expect(img).toHaveAttribute('src', 'https://example.com/image.jpg');
108
+ expect(img).toHaveAttribute('alt', 'Test image');
109
+ expect(img).toHaveAttribute('loading', 'lazy');
110
+ expect(container.querySelector('figcaption')).not.toBeInTheDocument();
111
+ // Check that the image is not wrapped in a link (only links in links section)
112
+ const featuredDiv = container.querySelector('.dynamic-content__featured');
113
+ expect(featuredDiv?.querySelector('a')).not.toBeInTheDocument();
114
+ });
115
+
116
+ it('renders an image with caption', () => {
117
+ const imageContent: IDynamicContentImage = {
118
+ type: 'image',
119
+ url: 'https://example.com/image.jpg',
120
+ altText: 'Test image',
121
+ caption: 'This is a caption',
122
+ };
123
+
124
+ render(
125
+ <AUDynamicContentComponent
126
+ {...baseProps}
127
+ featuredContent={imageContent}
128
+ />,
129
+ );
130
+
131
+ const caption = screen.getByText('This is a caption');
132
+ expect(caption).toBeInTheDocument();
133
+ expect(caption.tagName).toBe('FIGCAPTION');
134
+ expect(caption).toHaveClass('text--small');
135
+ });
136
+
137
+ it('renders an image wrapped in a link when linkUrl is provided', () => {
138
+ const imageContent: IDynamicContentImage = {
139
+ type: 'image',
140
+ url: 'https://example.com/image.jpg',
141
+ altText: 'Test image',
142
+ linkUrl: 'https://example.com/destination',
143
+ };
144
+
145
+ const { container } = render(
146
+ <AUDynamicContentComponent
147
+ {...baseProps}
148
+ featuredContent={imageContent}
149
+ />,
150
+ );
151
+
152
+ const link = container.querySelector('.dynamic-content__featured a');
153
+ expect(link).toBeInTheDocument();
154
+ expect(link).toHaveAttribute('href', 'https://example.com/destination');
155
+ expect(link?.querySelector('img')).toBeInTheDocument();
156
+ });
157
+
158
+ it('renders an infoBox featured content', () => {
159
+ const infoBoxContent: IDynamicContentInfoBox = {
160
+ type: 'infoBox',
161
+ htmlContent: '<div class="info">Important information</div>',
162
+ };
163
+
164
+ const { container } = render(
165
+ <AUDynamicContentComponent
166
+ {...baseProps}
167
+ featuredContent={infoBoxContent}
168
+ />,
169
+ );
170
+
171
+ const infoBox = container.querySelector('.dynamic-content__infobox');
172
+ expect(infoBox).toBeInTheDocument();
173
+ expect(infoBox?.querySelector('.info')).toBeInTheDocument();
174
+ expect(screen.getByText('Important information')).toBeInTheDocument();
175
+ });
176
+ });
177
+
178
+ describe('links rendering', () => {
179
+ it('renders multiple links with correct styling', () => {
180
+ render(<AUDynamicContentComponent {...baseProps} />);
181
+
182
+ const systemLink = screen.getByText('System Link').closest('a');
183
+ const infoLink = screen.getByText('Information Link').closest('a');
184
+
185
+ expect(systemLink).toHaveClass('button', 'button--block');
186
+ expect(systemLink).not.toHaveClass('button--dimmed');
187
+
188
+ expect(infoLink).toHaveClass('button', 'button--block', 'button--dimmed');
189
+ });
190
+
191
+ it('renders link titles and descriptions', () => {
192
+ render(<AUDynamicContentComponent {...baseProps} />);
193
+
194
+ expect(screen.getByText('System Link')).toHaveClass('card__title');
195
+ expect(screen.getByText('A system link description')).toHaveClass('card__subtitle');
196
+ expect(screen.getByText('Information Link')).toHaveClass('card__title');
197
+ expect(screen.getByText('An information link description')).toHaveClass('card__subtitle');
198
+ });
199
+
200
+ it('renders correct href attributes', () => {
201
+ render(<AUDynamicContentComponent {...baseProps} />);
202
+
203
+ const systemLink = screen.getByText('System Link').closest('a');
204
+ const infoLink = screen.getByText('Information Link').closest('a');
205
+
206
+ expect(systemLink).toHaveAttribute('href', 'https://example.com/system');
207
+ expect(infoLink).toHaveAttribute('href', 'https://example.com/info');
208
+ });
209
+
210
+ it('does not render links when array is empty', () => {
211
+ const { container } = render(
212
+ <AUDynamicContentComponent
213
+ {...baseProps}
214
+ links={[]}
215
+ />,
216
+ );
217
+
218
+ const linksContainer = container.querySelector('.dynamic-content__links');
219
+ expect(linksContainer).toBeInTheDocument();
220
+ expect(linksContainer?.querySelector('a')).not.toBeInTheDocument();
221
+ });
222
+
223
+ it('renders a single link', () => {
224
+ const singleLinkProps = {
225
+ ...baseProps,
226
+ links: [baseProps.links[0]],
227
+ };
228
+
229
+ render(<AUDynamicContentComponent {...singleLinkProps} />);
230
+
231
+ expect(screen.getByText('System Link')).toBeInTheDocument();
232
+ expect(screen.queryByText('Information Link')).not.toBeInTheDocument();
233
+ });
234
+ });
235
+
236
+ describe('defensive coding - null/undefined handling', () => {
237
+ it('handles undefined links array gracefully', () => {
238
+ const { container } = render(
239
+ <AUDynamicContentComponent
240
+ {...baseProps}
241
+ links={undefined as any}
242
+ />,
243
+ );
244
+
245
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
246
+ expect(container.querySelector('.dynamic-content__links a')).not.toBeInTheDocument();
247
+ });
248
+
249
+ it('handles null links array gracefully', () => {
250
+ const { container } = render(
251
+ <AUDynamicContentComponent
252
+ {...baseProps}
253
+ links={null as any}
254
+ />,
255
+ );
256
+
257
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
258
+ expect(container.querySelector('.dynamic-content__links a')).not.toBeInTheDocument();
259
+ });
260
+
261
+ it('handles undefined name gracefully', () => {
262
+ const { container } = render(
263
+ <AUDynamicContentComponent
264
+ {...baseProps}
265
+ name={undefined as any}
266
+ />,
267
+ );
268
+
269
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
270
+ expect(container.querySelector('h3')).not.toBeInTheDocument();
271
+ });
272
+
273
+ it('handles empty string name gracefully', () => {
274
+ const { container } = render(
275
+ <AUDynamicContentComponent
276
+ {...baseProps}
277
+ name=""
278
+ />,
279
+ );
280
+
281
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
282
+ expect(container.querySelector('h3')).not.toBeInTheDocument();
283
+ });
284
+
285
+ it('handles undefined featuredContent gracefully', () => {
286
+ const { container } = render(
287
+ <AUDynamicContentComponent
288
+ {...baseProps}
289
+ featuredContent={undefined as any}
290
+ />,
291
+ );
292
+
293
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
294
+ expect(container.querySelector('iframe')).not.toBeInTheDocument();
295
+ expect(container.querySelector('img')).not.toBeInTheDocument();
296
+ expect(container.querySelector('.dynamic-content__infobox')).not.toBeInTheDocument();
297
+ });
298
+
299
+ it('handles null featuredContent gracefully', () => {
300
+ const { container } = render(
301
+ <AUDynamicContentComponent
302
+ {...baseProps}
303
+ featuredContent={null as any}
304
+ />,
305
+ );
306
+
307
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
308
+ expect(container.querySelector('iframe')).not.toBeInTheDocument();
309
+ expect(container.querySelector('img')).not.toBeInTheDocument();
310
+ expect(container.querySelector('.dynamic-content__infobox')).not.toBeInTheDocument();
311
+ });
312
+
313
+ it('handles undefined featuredContentDescription gracefully', () => {
314
+ const { container } = render(
315
+ <AUDynamicContentComponent
316
+ {...baseProps}
317
+ featuredContentDescription={undefined as any}
318
+ />,
319
+ );
320
+
321
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
322
+ const featuredDiv = container.querySelector('.dynamic-content__featured');
323
+ expect(featuredDiv).toBeInTheDocument();
324
+ // Should not have a child div with dangerouslySetInnerHTML
325
+ const childDivs = Array.from(featuredDiv?.children || []).filter(
326
+ (child) => child.tagName === 'DIV' && child !== featuredDiv,
327
+ );
328
+ expect(childDivs.length).toBe(0);
329
+ });
330
+
331
+ it('handles empty string featuredContentDescription gracefully', () => {
332
+ const { container } = render(
333
+ <AUDynamicContentComponent
334
+ {...baseProps}
335
+ featuredContentDescription=""
336
+ />,
337
+ );
338
+
339
+ expect(container.querySelector('.dynamic-content')).toBeInTheDocument();
340
+ const featuredDiv = container.querySelector('.dynamic-content__featured');
341
+ expect(featuredDiv).toBeInTheDocument();
342
+ // Should not render the description div when empty
343
+ const childDivs = Array.from(featuredDiv?.children || []).filter(
344
+ (child) => child.tagName === 'DIV' && child !== featuredDiv,
345
+ );
346
+ expect(childDivs.length).toBe(0);
347
+ });
348
+ });
349
+
350
+ describe('edge cases', () => {
351
+ it('renders with minimal valid props', () => {
352
+ const minimalProps: IDynamicContentProps = {
353
+ name: 'Minimal',
354
+ featuredContentDescription: '<p>Description</p>',
355
+ links: [],
356
+ featuredContent: {
357
+ type: 'image',
358
+ url: 'https://example.com/img.jpg',
359
+ altText: 'Image',
360
+ },
361
+ };
362
+
363
+ const { container } = render(<AUDynamicContentComponent {...minimalProps} />);
364
+
365
+ expect(screen.getByText('Minimal')).toBeInTheDocument();
366
+ expect(container.querySelector('img')).toBeInTheDocument();
367
+ expect(container.querySelector('.dynamic-content__links a')).not.toBeInTheDocument();
368
+ });
369
+
370
+ it('handles all link types correctly', () => {
371
+ const allTypesProps = {
372
+ ...baseProps,
373
+ links: [
374
+ { ...baseProps.links[0], linkType: 'system' as const },
375
+ { ...baseProps.links[1], linkType: 'information' as const },
376
+ ],
377
+ };
378
+
379
+ render(<AUDynamicContentComponent {...allTypesProps} />);
380
+
381
+ const links = screen.getAllByRole('link');
382
+ expect(links[0]).not.toHaveClass('button--dimmed');
383
+ expect(links[1]).toHaveClass('button--dimmed');
384
+ });
385
+ });
386
+ });
@@ -1,142 +1,142 @@
1
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
- import React from 'react';
3
- import { render } from '@testing-library/react';
4
- import { SerializedError } from '@reduxjs/toolkit';
5
- import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query';
6
- // import userEvent from '@testing-library/user-event';
7
- import '@testing-library/jest-dom';
8
- import AUErrorComponent from '../../src/components/AUErrorComponent';
9
-
10
- const auError: AU.IError = {
11
- header: 'Our own custom error',
12
- message: 'With a nice header and descriptive error message',
13
- status: 500,
14
- };
15
-
16
- const fetchError1: FetchBaseQueryError = {
17
- status: 'FETCH_ERROR',
18
- error: 'Sum Ting Wong',
19
- };
20
-
21
- const fetchError2: FetchBaseQueryError = {
22
- status: 500,
23
- data: {
24
- status: 'Error',
25
- message: 'Sum Ting Wong',
26
- },
27
- };
28
-
29
- const serializedError: SerializedError = {
30
- code: '500',
31
- message: 'Sum Ting Wong',
32
- name: 'Some kind of error',
33
- stack: 'Some kind of stack trace',
34
- };
35
-
36
- describe('<AUErrorComponent />', () => {
37
- it('renders an AU custom error without a status code', () => {
38
- const { container } = render(
39
- <AUErrorComponent
40
- error={auError}
41
- />,
42
- );
43
-
44
- const header = container.querySelector('.notification__header');
45
- const p = container.querySelector('.notification__content p');
46
- expect(header).toBeInTheDocument();
47
- expect(p?.innerHTML).toBe(auError.message);
48
- });
49
-
50
- it('renders an AU custom error with a status code', () => {
51
- const { container } = render(
52
- <AUErrorComponent
53
- error={auError}
54
- withStatus
55
- />,
56
- );
57
-
58
- const header = container.querySelector('.notification__header');
59
- expect(header?.innerHTML).toBe(`${auError.status}: ${auError.header}`);
60
- });
61
-
62
- it('renders a fetch error without a status code', () => {
63
- const { container } = render(
64
- <AUErrorComponent
65
- fetchError={fetchError1}
66
- />,
67
- );
68
-
69
- const header = container.querySelector('.notification__header');
70
- const p = container.querySelector('.notification__content p');
71
- expect(header).toBe(null);
72
- expect(p?.innerHTML).toBe(fetchError1.error);
73
- });
74
-
75
- it('renders a fetch error with a status code', () => {
76
- const { container } = render(
77
- <AUErrorComponent
78
- fetchError={fetchError1}
79
- withStatus
80
- />,
81
- );
82
-
83
- const header = container.querySelector('.notification__header');
84
- const p = container.querySelector('.notification__content p');
85
- expect(header?.innerHTML).toBe(fetchError1.status);
86
- expect(p?.innerHTML).toBe(fetchError1.error);
87
- });
88
-
89
- it('renders a fetch error with stringified text without a status code', () => {
90
- const { container } = render(
91
- <AUErrorComponent
92
- fetchError={fetchError2}
93
- />,
94
- );
95
-
96
- const header = container.querySelector('.notification__header');
97
- const p = container.querySelector('.notification__content p');
98
- expect(header).toBe(null);
99
- expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
100
- });
101
-
102
- it('renders a fetch error with stringified text with a status code', () => {
103
- const { container } = render(
104
- <AUErrorComponent
105
- fetchError={fetchError2}
106
- withStatus
107
- />,
108
- );
109
-
110
- const header = container.querySelector('.notification__header');
111
- const p = container.querySelector('.notification__content p');
112
- expect(header?.innerHTML).toBe(`${fetchError2.status}`);
113
- expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
114
- });
115
-
116
- it('renders a serialized error with without a status code', () => {
117
- const { container } = render(
118
- <AUErrorComponent
119
- serializedError={serializedError}
120
- />,
121
- );
122
-
123
- const header = container.querySelector('.notification__header');
124
- const p = container.querySelector('.notification__content p');
125
- expect(header).toBe(null);
126
- expect(p?.innerHTML).toBe(serializedError.message);
127
- });
128
-
129
- it('renders a serialized error with a status code', () => {
130
- const { container } = render(
131
- <AUErrorComponent
132
- serializedError={serializedError}
133
- withStatus
134
- />,
135
- );
136
-
137
- const header = container.querySelector('.notification__header');
138
- const p = container.querySelector('.notification__content p');
139
- expect(header?.innerHTML).toBe(serializedError.code);
140
- expect(p?.innerHTML).toBe(serializedError.message);
141
- });
142
- });
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ import React from 'react';
3
+ import { render } from '@testing-library/react';
4
+ import { SerializedError } from '@reduxjs/toolkit';
5
+ import { FetchBaseQueryError } from '@reduxjs/toolkit/dist/query';
6
+ // import userEvent from '@testing-library/user-event';
7
+ import '@testing-library/jest-dom';
8
+ import AUErrorComponent from '../../src/components/AUErrorComponent';
9
+
10
+ const auError: AU.IError = {
11
+ header: 'Our own custom error',
12
+ message: 'With a nice header and descriptive error message',
13
+ status: 500,
14
+ };
15
+
16
+ const fetchError1: FetchBaseQueryError = {
17
+ status: 'FETCH_ERROR',
18
+ error: 'Sum Ting Wong',
19
+ };
20
+
21
+ const fetchError2: FetchBaseQueryError = {
22
+ status: 500,
23
+ data: {
24
+ status: 'Error',
25
+ message: 'Sum Ting Wong',
26
+ },
27
+ };
28
+
29
+ const serializedError: SerializedError = {
30
+ code: '500',
31
+ message: 'Sum Ting Wong',
32
+ name: 'Some kind of error',
33
+ stack: 'Some kind of stack trace',
34
+ };
35
+
36
+ describe('<AUErrorComponent />', () => {
37
+ it('renders an AU custom error without a status code', () => {
38
+ const { container } = render(
39
+ <AUErrorComponent
40
+ error={auError}
41
+ />,
42
+ );
43
+
44
+ const header = container.querySelector('.notification__header');
45
+ const p = container.querySelector('.notification__content p');
46
+ expect(header).toBeInTheDocument();
47
+ expect(p?.innerHTML).toBe(auError.message);
48
+ });
49
+
50
+ it('renders an AU custom error with a status code', () => {
51
+ const { container } = render(
52
+ <AUErrorComponent
53
+ error={auError}
54
+ withStatus
55
+ />,
56
+ );
57
+
58
+ const header = container.querySelector('.notification__header');
59
+ expect(header?.innerHTML).toBe(`${auError.status}: ${auError.header}`);
60
+ });
61
+
62
+ it('renders a fetch error without a status code', () => {
63
+ const { container } = render(
64
+ <AUErrorComponent
65
+ fetchError={fetchError1}
66
+ />,
67
+ );
68
+
69
+ const header = container.querySelector('.notification__header');
70
+ const p = container.querySelector('.notification__content p');
71
+ expect(header).toBe(null);
72
+ expect(p?.innerHTML).toBe(fetchError1.error);
73
+ });
74
+
75
+ it('renders a fetch error with a status code', () => {
76
+ const { container } = render(
77
+ <AUErrorComponent
78
+ fetchError={fetchError1}
79
+ withStatus
80
+ />,
81
+ );
82
+
83
+ const header = container.querySelector('.notification__header');
84
+ const p = container.querySelector('.notification__content p');
85
+ expect(header?.innerHTML).toBe(fetchError1.status);
86
+ expect(p?.innerHTML).toBe(fetchError1.error);
87
+ });
88
+
89
+ it('renders a fetch error with stringified text without a status code', () => {
90
+ const { container } = render(
91
+ <AUErrorComponent
92
+ fetchError={fetchError2}
93
+ />,
94
+ );
95
+
96
+ const header = container.querySelector('.notification__header');
97
+ const p = container.querySelector('.notification__content p');
98
+ expect(header).toBe(null);
99
+ expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
100
+ });
101
+
102
+ it('renders a fetch error with stringified text with a status code', () => {
103
+ const { container } = render(
104
+ <AUErrorComponent
105
+ fetchError={fetchError2}
106
+ withStatus
107
+ />,
108
+ );
109
+
110
+ const header = container.querySelector('.notification__header');
111
+ const p = container.querySelector('.notification__content p');
112
+ expect(header?.innerHTML).toBe(`${fetchError2.status}`);
113
+ expect(p?.innerHTML).toBe(JSON.stringify(fetchError2.data));
114
+ });
115
+
116
+ it('renders a serialized error with without a status code', () => {
117
+ const { container } = render(
118
+ <AUErrorComponent
119
+ serializedError={serializedError}
120
+ />,
121
+ );
122
+
123
+ const header = container.querySelector('.notification__header');
124
+ const p = container.querySelector('.notification__content p');
125
+ expect(header).toBe(null);
126
+ expect(p?.innerHTML).toBe(serializedError.message);
127
+ });
128
+
129
+ it('renders a serialized error with a status code', () => {
130
+ const { container } = render(
131
+ <AUErrorComponent
132
+ serializedError={serializedError}
133
+ withStatus
134
+ />,
135
+ );
136
+
137
+ const header = container.querySelector('.notification__header');
138
+ const p = container.querySelector('.notification__content p');
139
+ expect(header?.innerHTML).toBe(serializedError.code);
140
+ expect(p?.innerHTML).toBe(serializedError.message);
141
+ });
142
+ });