@eeacms/volto-eea-design-system 1.16.0 → 1.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.
Files changed (63) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/docker-compose.yml +5 -1
  3. package/locales/en/LC_MESSAGES/volto.po +14 -0
  4. package/package.json +1 -1
  5. package/src/helpers/index.js +4 -4
  6. package/src/helpers/useClickOutside.test.js +63 -0
  7. package/src/helpers/useFirstVisited.test.js +54 -0
  8. package/src/ui/Accordion/Accordion.stories.js +3 -1
  9. package/src/ui/Accordion/Accordion.stories.test.js +45 -0
  10. package/src/ui/Banner/Banner.test.jsx +292 -0
  11. package/src/ui/CallToAction/CallToAction.stories.test.jsx +69 -0
  12. package/src/ui/Card/Card.stories.test.jsx +78 -0
  13. package/src/ui/Card/IconCard/IconCard.stories.test.jsx +64 -0
  14. package/src/ui/Card/RelatedContent/RelatedContent.jsx +1 -1
  15. package/src/ui/Card/RelatedContent/RelatedContent.stories.jsx +2 -2
  16. package/src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx +65 -0
  17. package/src/ui/Confirm/Confirm.stories.test.js +27 -0
  18. package/src/ui/ContextNavigation/ContextNavigation.stories.test.jsx +170 -0
  19. package/src/ui/Divider/Divider.stories.test.jsx +44 -0
  20. package/src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx +24 -0
  21. package/src/ui/Footer/Description.test.jsx +11 -0
  22. package/src/ui/Footer/Footer.stories.test.js +131 -0
  23. package/src/ui/Footer/Social.test.jsx +11 -0
  24. package/src/ui/Form/Button/Button.stories.test.jsx +55 -0
  25. package/src/ui/Form/Checkbox.stories.test.js +79 -0
  26. package/src/ui/Form/Dropdown.stories.test.js +24 -0
  27. package/src/ui/Form/Radio.stories.test.js +55 -0
  28. package/src/ui/Form/Textarea.stories.test.js +41 -0
  29. package/src/ui/Form/input.stories.test.js +52 -0
  30. package/src/ui/Grid/ComponentGrid.stories.test.js +21 -0
  31. package/src/ui/Header/Header.stories.test.js +158 -0
  32. package/src/ui/Header/Header.test.jsx +293 -0
  33. package/src/ui/Header/HeaderMenuPopUp.js +12 -4
  34. package/src/ui/Header/HeaderSearchPopUp.test.js +114 -0
  35. package/src/ui/Hero/Hero.stories.test.jsx +67 -0
  36. package/src/ui/InpageNavigation/InpageNavigation.stories.test.jsx +10 -0
  37. package/src/ui/InpageNavigation/InpageNavigation.test.jsx +87 -0
  38. package/src/ui/Item/Item.stories.test.js +39 -0
  39. package/src/ui/Item/ItemGroupWithIcons.stories.test.js +119 -0
  40. package/src/ui/Label/Label.stories.test.js +76 -0
  41. package/src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx +19 -0
  42. package/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx +3 -2
  43. package/src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx +60 -0
  44. package/src/ui/Loader/Loader.stories.test.jsx +30 -0
  45. package/src/ui/Logo/Logo.stories.test.jsx +81 -0
  46. package/src/ui/Media/Image.stories.test.js +35 -0
  47. package/src/ui/Message/Message.stories.test.js +44 -0
  48. package/src/ui/Modal/Modal.stories.test.js +45 -0
  49. package/src/ui/Popup/Popup.jsx +24 -17
  50. package/src/ui/Popup/Popup.test.jsx +60 -0
  51. package/src/ui/Progress/Progress.stories.test.js +30 -0
  52. package/src/ui/Quote/Testimonial/Testimonial.stories.test.jsx +18 -0
  53. package/src/ui/Statistic/Statistic.stories.test.js +93 -0
  54. package/src/ui/Table/Table.stories.js +8 -0
  55. package/src/ui/Table/Table.stories.test.js +54 -0
  56. package/src/ui/Timeline/Timeline.stories.test.jsx +43 -0
  57. package/src/ui/index.js +21 -41
  58. package/theme/themes/eea/assets/images/Footer/Extras/footer-visual.svg +1 -2065
  59. package/theme/themes/eea/extras/banner.less +3 -3
  60. package/theme/themes/eea/modules/accordion.overrides +36 -11
  61. package/theme/themes/eea/modules/accordion.variables +2 -0
  62. package/theme/themes/eea/views/item.overrides +21 -0
  63. package/src/i18n.js +0 -180
@@ -0,0 +1,293 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { createMemoryHistory } from 'history';
4
+ import { Router } from 'react-router-dom';
5
+ import Header from './Header';
6
+ import '@testing-library/jest-dom/extend-expect';
7
+
8
+ describe('Header component', () => {
9
+ let history;
10
+
11
+ beforeEach(() => {
12
+ history = createMemoryHistory();
13
+ });
14
+
15
+ it('renders without crashing', () => {
16
+ render(<Header />);
17
+ });
18
+
19
+ it('renders children correctly', () => {
20
+ render(<Header>Test Children</Header>);
21
+ expect(screen.getByText('Test Children')).toBeInTheDocument();
22
+ });
23
+
24
+ it('renders without crashing', () => {
25
+ render(
26
+ <Header>
27
+ <Header.TopHeader>
28
+ <Header.TopItem>
29
+ <p>Test</p>
30
+ </Header.TopItem>
31
+ <Header.TopItem>
32
+ <Header.TopDropdownMenu
33
+ hasLanguageDropdown={true}
34
+ viewportWidth={1000}
35
+ >
36
+ <div aria-label="language switcher">Language Switcher</div>
37
+ </Header.TopDropdownMenu>
38
+ </Header.TopItem>
39
+ </Header.TopHeader>
40
+ <Header.Main
41
+ menuItems={[{ '@id': '/home', title: 'Home', items: [] }]}
42
+ pathname={'/home'}
43
+ renderGlobalMenuItem={(item, { onClick }) =>
44
+ item.title !== 'Home' && (
45
+ <a
46
+ href={item.url}
47
+ title={item.title}
48
+ onClick={(e) => {
49
+ e.preventDefault();
50
+ onClick(e, item);
51
+ }}
52
+ >
53
+ {item.title}
54
+ </a>
55
+ )
56
+ }
57
+ renderMenuItem={(item, options, props) => {
58
+ return (
59
+ <a
60
+ href={item.url || '/'}
61
+ title={item.nav_title || item.title}
62
+ {...(options || {})}
63
+ >
64
+ {props?.iconPosition !== 'right' && props?.children}
65
+ <span>{item.nav_title || item.title}</span>
66
+ {props?.iconPosition === 'right' && props?.children}
67
+ </a>
68
+ );
69
+ }}
70
+ />
71
+ </Header>,
72
+ );
73
+ });
74
+
75
+ it('renders without crashing', () => {
76
+ render(
77
+ <Header>
78
+ <Header.TopHeader>
79
+ <Header.TopItem>
80
+ <Header.TopDropdownMenu viewportWidth={900}>
81
+ <div aria-label="test">No Language Switcher</div>
82
+ </Header.TopDropdownMenu>
83
+ </Header.TopItem>
84
+ </Header.TopHeader>
85
+ <Header.Main
86
+ menuItems={[{ '@id': '/home', title: 'Home', items: [] }]}
87
+ pathname={'/home'}
88
+ isMultilingual={true}
89
+ renderGlobalMenuItem={(item, { onClick }) =>
90
+ item.title !== 'Home' && (
91
+ <a
92
+ href={item.url}
93
+ title={item.title}
94
+ onClick={(e) => {
95
+ e.preventDefault();
96
+ onClick(e, item);
97
+ }}
98
+ >
99
+ {item.title}
100
+ </a>
101
+ )
102
+ }
103
+ renderMenuItem={(item, options, props) => {
104
+ return (
105
+ <a
106
+ href={item.url || '/'}
107
+ title={item.nav_title || item.title}
108
+ {...(options || {})}
109
+ >
110
+ {props?.iconPosition !== 'right' && props?.children}
111
+ <span>{item.nav_title || item.title}</span>
112
+ {props?.iconPosition === 'right' && props?.children}
113
+ </a>
114
+ );
115
+ }}
116
+ />
117
+ </Header>,
118
+ );
119
+ });
120
+
121
+ it('renders without crashing', () => {
122
+ const { getByText, getAllByText, container } = render(
123
+ <Router history={history}>
124
+ <Header>
125
+ <Header.TopHeader>
126
+ <Header.TopItem>
127
+ <Header.TopDropdownMenu viewportWidth={760}>
128
+ <div aria-label="test">No Language Switcher</div>
129
+ </Header.TopDropdownMenu>
130
+ </Header.TopItem>
131
+ </Header.TopHeader>
132
+ <Header.Main
133
+ transparency={true}
134
+ inverted={true}
135
+ menuItems={[
136
+ {
137
+ '@id': '/countries',
138
+ url: '/countries',
139
+ title: 'Countries',
140
+ items: [
141
+ {
142
+ title: 'At a glance',
143
+ url: '/countries/at-a-glance/in-depth',
144
+ items: [
145
+ {
146
+ title: 'test',
147
+ url: '/countries/at-a-glance/test',
148
+ items: [
149
+ {
150
+ title: 'test',
151
+ url: '/countries/at-a-glance/test',
152
+ items: [],
153
+ },
154
+ {
155
+ title: 'test',
156
+ url: '/countries/at-a-glance/test',
157
+ items: [],
158
+ },
159
+ ],
160
+ },
161
+ {
162
+ title: 'test2',
163
+ url: '/countries/at-a-glance/test2',
164
+ items: [
165
+ {
166
+ title: 'test',
167
+ url: '/countries/at-a-glance/test',
168
+ items: [],
169
+ },
170
+ {
171
+ title: 'test',
172
+ url: '/countries/at-a-glance/test',
173
+ items: [],
174
+ },
175
+ ],
176
+ },
177
+ ],
178
+ },
179
+ {
180
+ title: 'anything else',
181
+ url: '/countries/anything-else/in-depth',
182
+ items: [],
183
+ },
184
+ ],
185
+ },
186
+ {
187
+ '@id': '/topics',
188
+ url: '/topics',
189
+ title: 'Topics',
190
+ items: [
191
+ {
192
+ title: 'At a glance',
193
+ url: '/topics/at-a-glance/in-depth',
194
+ items: [
195
+ {
196
+ title: 'test',
197
+ url: '/topics/at-a-glance/test',
198
+ items: [],
199
+ },
200
+ ],
201
+ },
202
+ {
203
+ title: 'Anything else',
204
+ url: '/topics/anything-else/in-depth',
205
+ items: [
206
+ {
207
+ title: 'test',
208
+ url: '/topics/anything-else/test',
209
+ items: [],
210
+ },
211
+ ],
212
+ },
213
+ ],
214
+ },
215
+ {
216
+ '@id': '/test',
217
+ url: '/test',
218
+ title: 'Test Click',
219
+ items: [
220
+ {
221
+ title: 'test',
222
+ items: [
223
+ {
224
+ title: 'test',
225
+ url: '/test/at-a-glance/test',
226
+ items: [],
227
+ },
228
+ ],
229
+ },
230
+ ],
231
+ },
232
+ {
233
+ '@id': undefined,
234
+ url: '/test2',
235
+ title: 'Test Click 2',
236
+ items: [],
237
+ },
238
+ {
239
+ '@id': undefined,
240
+ url: 'http://test.com',
241
+ title: 'Test Click 3',
242
+ items: [],
243
+ },
244
+ ]}
245
+ pathname={'/test'}
246
+ renderGlobalMenuItem={(item, { onClick }) =>
247
+ item.title !== 'Home' && (
248
+ <a
249
+ href={item.url}
250
+ title={item.title}
251
+ onClick={(e) => {
252
+ e.preventDefault();
253
+ onClick(e, item);
254
+ }}
255
+ >
256
+ {item.title}
257
+ </a>
258
+ )
259
+ }
260
+ renderMenuItem={(item, options, props) => {
261
+ return (
262
+ <a
263
+ href={item.url || '/'}
264
+ title={item.nav_title || item.title}
265
+ {...(options || {})}
266
+ >
267
+ {props?.iconPosition !== 'right' && props?.children}
268
+ <span>{item.nav_title || item.title}</span>
269
+ {props?.iconPosition === 'right' && props?.children}
270
+ </a>
271
+ );
272
+ }}
273
+ />
274
+ </Header>
275
+ </Router>,
276
+ );
277
+ const menuItemsWithInternalUrl = getAllByText('Test Click 2');
278
+ const menuItemsWithExternalUrl = getAllByText('Test Click 3');
279
+ const menuItemsWithCountries = getAllByText('Countries');
280
+ const menuItemsWithTopics = getAllByText('Topics');
281
+
282
+ fireEvent.click(getByText('Test Click'));
283
+ fireEvent.click(menuItemsWithInternalUrl[0]);
284
+ fireEvent.click(container.querySelector('.search-action'));
285
+ fireEvent.click(menuItemsWithExternalUrl[0]);
286
+ fireEvent.click(menuItemsWithCountries[0]);
287
+ fireEvent.click(menuItemsWithTopics[0]);
288
+ fireEvent.keyDown(getByText('No Language Switcher'), {
289
+ key: 'Enter',
290
+ code: 'Enter',
291
+ });
292
+ });
293
+ });
@@ -168,7 +168,17 @@ const FirstLevelContent = ({ element, renderMenuItem, pathName }) => {
168
168
  defaultIndex = index;
169
169
  }
170
170
  x.title = (
171
- <Accordion.Title key={`title=${index}`} as="button">
171
+ <Accordion.Title
172
+ key={`title=${index}`}
173
+ as="button"
174
+ aria-expanded={false}
175
+ onClick={(e) => {
176
+ e.currentTarget.setAttribute(
177
+ 'aria-expanded',
178
+ e.currentTarget.className.indexOf('active') === -1,
179
+ );
180
+ }}
181
+ >
172
182
  {item.title}
173
183
  <Icon className="ri-arrow-down-s-line" size="small" />
174
184
  </Accordion.Title>
@@ -223,7 +233,6 @@ const SecondLevelContent = ({ element, topics = false, renderMenuItem }) => {
223
233
  <React.Fragment key={index}>
224
234
  {renderMenuItem(item, {
225
235
  key: index,
226
- role: 'listitem',
227
236
  className: 'item',
228
237
  })}
229
238
  </React.Fragment>
@@ -232,7 +241,6 @@ const SecondLevelContent = ({ element, topics = false, renderMenuItem }) => {
232
241
  <React.Fragment key={inDepth.url}>
233
242
  {renderMenuItem(inDepth, {
234
243
  key: inDepth.url,
235
- role: 'listitem',
236
244
  className: 'item',
237
245
  })}
238
246
  </React.Fragment>
@@ -246,7 +254,6 @@ const SecondLevelContent = ({ element, topics = false, renderMenuItem }) => {
246
254
  <React.Fragment key={index}>
247
255
  {renderMenuItem(item, {
248
256
  key: index,
249
- role: 'listitem',
250
257
  className: 'item',
251
258
  })}
252
259
  </React.Fragment>
@@ -277,6 +284,7 @@ const NestedAccordion = ({ menuItems, renderMenuItem, pathName }) => {
277
284
  <Accordion.Title
278
285
  key={`title-${index}`}
279
286
  index={index}
287
+ aria-expanded={activeIndex === index}
280
288
  as="button"
281
289
  onClick={() => {
282
290
  if (activeIndex === index) {
@@ -0,0 +1,114 @@
1
+ import React from 'react';
2
+ import { render, screen, fireEvent } from '@testing-library/react';
3
+ import { createMemoryHistory } from 'history';
4
+ import { Router } from 'react-router-dom';
5
+ import HeaderSearchPopUp from './HeaderSearchPopUp';
6
+ import '@testing-library/jest-dom/extend-expect';
7
+
8
+ describe('HeaderSearchPopUp', () => {
9
+ let history;
10
+ const mockOnClose = jest.fn();
11
+ const sampleHeaderSearchBox = [
12
+ {
13
+ path: '/search',
14
+ buttonTitle: 'Advanced Search',
15
+ buttonUrl: '/advanced-search',
16
+ description: 'Sample description',
17
+ placeholder: 'Search',
18
+ searchSuggestions: {
19
+ suggestionsTitle: 'Suggestions Title',
20
+ suggestions: ['suggestion 1', 'suggestion 2', 'suggestion 3'],
21
+ maxToShow: 3,
22
+ },
23
+ isDefault: true,
24
+ },
25
+ ];
26
+
27
+ const sampleHeaderSearchBoxWithMatchpath = [
28
+ {
29
+ matchpath: '/search',
30
+ buttonTitle: 'Advanced Search',
31
+ buttonUrl: undefined,
32
+ description: 'Sample description',
33
+ placeholder: 'Search',
34
+ searchSuggestions: {
35
+ suggestionsTitle: 'Suggestions Title',
36
+ suggestions: ['suggestion 1', 'suggestion 2', 'suggestion 3'],
37
+ maxToShow: 3,
38
+ },
39
+ isDefault: true,
40
+ },
41
+ ];
42
+
43
+ beforeEach(() => {
44
+ history = createMemoryHistory();
45
+ });
46
+
47
+ afterEach(() => {
48
+ jest.clearAllMocks();
49
+ });
50
+
51
+ it('should render HeaderSearchPopUp', () => {
52
+ render(
53
+ <Router history={history}>
54
+ <HeaderSearchPopUp
55
+ headerSearchBox={sampleHeaderSearchBox}
56
+ onClose={mockOnClose}
57
+ triggerRefs={[]}
58
+ />
59
+ </Router>,
60
+ );
61
+ expect(screen.getByPlaceholderText('Search')).toBeInTheDocument();
62
+ });
63
+
64
+ it('should update search text on change', () => {
65
+ render(
66
+ <Router history={history}>
67
+ <HeaderSearchPopUp
68
+ headerSearchBox={sampleHeaderSearchBox}
69
+ onClose={mockOnClose}
70
+ triggerRefs={[]}
71
+ />
72
+ </Router>,
73
+ );
74
+ const input = screen.getByPlaceholderText('Search');
75
+ fireEvent.change(input, { target: { value: 'New text' } });
76
+ expect(input.value).toBe('New text');
77
+ });
78
+
79
+ it('should submit the form with search text', () => {
80
+ window.searchContext = { resetSearch: jest.fn() };
81
+
82
+ const { container } = render(
83
+ <Router history={history}>
84
+ <HeaderSearchPopUp
85
+ headerSearchBox={sampleHeaderSearchBox}
86
+ onClose={mockOnClose}
87
+ triggerRefs={[]}
88
+ />
89
+ </Router>,
90
+ );
91
+ const input = screen.getByPlaceholderText('Search');
92
+ fireEvent.change(input, { target: { value: 'Search text' } });
93
+ fireEvent.submit(container.querySelector('form'));
94
+ fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
95
+ expect(history.location.pathname).toBe('/search');
96
+ // expect(history.location.search).toBe('?q=Search text');
97
+ });
98
+
99
+ it('should navigate to the suggestion when a suggestion is clicked', () => {
100
+ window.searchContext = { resetSearch: jest.fn() };
101
+
102
+ render(
103
+ <Router history={history}>
104
+ <HeaderSearchPopUp
105
+ headerSearchBox={sampleHeaderSearchBoxWithMatchpath}
106
+ onClose={mockOnClose}
107
+ />
108
+ </Router>,
109
+ );
110
+ fireEvent.click(screen.getByText('suggestion 1'));
111
+ expect(history.location.pathname).toBe('/');
112
+ expect(history.location.search).toBe('?q=suggestion 1');
113
+ });
114
+ });
@@ -0,0 +1,67 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { Playground, Default } from './Hero.st';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('Playground component', () => {
7
+ it('renders correctly', () => {
8
+ const { container, getByText } = render(
9
+ <Playground {...Playground.args} />,
10
+ );
11
+
12
+ expect(getByText(Playground.args.text)).toBeInTheDocument();
13
+ expect(getByText(Playground.args.buttonLabel)).toBeInTheDocument();
14
+ expect(getByText(Playground.args.buttonLabel)).toHaveClass(
15
+ 'ui inverted button primary',
16
+ );
17
+ expect(container.querySelector('.eea.copyright')).toBeInTheDocument();
18
+ expect(getByText(Playground.args.copyrightPrefix)).toHaveClass(
19
+ 'icon-prefix',
20
+ );
21
+ expect(
22
+ container.querySelector(`.icon.${Playground.args.copyrightIcon}`),
23
+ ).toBeInTheDocument();
24
+ expect(getByText(Playground.args.copyright)).toHaveClass('icon-content');
25
+ });
26
+ });
27
+
28
+ describe('Default component', () => {
29
+ it('renders correctly', () => {
30
+ const { container, getByText } = render(<Default {...Default.args} />);
31
+
32
+ expect(getByText(Default.args.text)).toBeInTheDocument();
33
+ expect(getByText(Default.args.buttonLabel)).toBeInTheDocument();
34
+ expect(getByText(Default.args.buttonLabel)).toHaveClass(
35
+ 'ui inverted button primary',
36
+ );
37
+ expect(container.querySelector('.eea.copyright')).toBeInTheDocument();
38
+ expect(getByText(Default.args.copyrightPrefix)).toHaveClass('icon-prefix');
39
+ expect(
40
+ container.querySelector(`.icon.${Default.args.copyrightIcon}`),
41
+ ).toBeInTheDocument();
42
+ expect(getByText(Default.args.copyright)).toHaveClass('icon-content');
43
+ });
44
+
45
+ it('renders correctly', () => {
46
+ const { container, getByText } = render(
47
+ <Default
48
+ {...Default.args}
49
+ image={false}
50
+ fullWidth={false}
51
+ fullHeight={false}
52
+ />,
53
+ );
54
+
55
+ expect(getByText(Default.args.text)).toBeInTheDocument();
56
+ expect(getByText(Default.args.buttonLabel)).toBeInTheDocument();
57
+ expect(getByText(Default.args.buttonLabel)).toHaveClass(
58
+ 'ui inverted button primary',
59
+ );
60
+ expect(container.querySelector('.eea.copyright')).toBeInTheDocument();
61
+ expect(getByText(Default.args.copyrightPrefix)).toHaveClass('icon-prefix');
62
+ expect(
63
+ container.querySelector(`.icon.${Default.args.copyrightIcon}`),
64
+ ).toBeInTheDocument();
65
+ expect(getByText(Default.args.copyright)).toHaveClass('icon-content');
66
+ });
67
+ });
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { Default } from './InpageNavigation.stories';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('Default component', () => {
7
+ it('renders correctly', () => {
8
+ render(<Default {...Default.args} />);
9
+ });
10
+ });
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react';
3
+ import InpageNavigation from './InpageNavigation';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('InpageNavigation', () => {
7
+ let scrollToMock;
8
+
9
+ beforeEach(() => {
10
+ scrollToMock = jest.fn();
11
+ global.window.scrollTo = scrollToMock;
12
+ });
13
+
14
+ afterEach(() => {
15
+ scrollToMock.mockClear();
16
+ delete global.window.scrollTo;
17
+ });
18
+
19
+ it('should scroll to top on button click', () => {
20
+ const { getByTitle } = render(<InpageNavigation />);
21
+ const button = getByTitle('Go to top');
22
+
23
+ fireEvent.click(button);
24
+
25
+ expect(scrollToMock).toHaveBeenCalledWith({
26
+ top: 0,
27
+ behavior: 'smooth',
28
+ });
29
+ });
30
+
31
+ it('should hide the button when scroll position is less than or equal to 50', () => {
32
+ Object.defineProperty(window, 'scrollY', { value: 30 });
33
+
34
+ const { getByTitle } = render(<InpageNavigation />);
35
+ const button = getByTitle('Go to top');
36
+
37
+ expect(button).toHaveClass('hidden');
38
+ });
39
+
40
+ it('should render the correct button content for different screen sizes', () => {
41
+ const { container } = render(<InpageNavigation />);
42
+ const mobileTabletOnlyContent = container.querySelector(
43
+ '.mobile.tablet.only',
44
+ );
45
+ const tabletOrLowerHiddenContent = container.querySelector(
46
+ '.tablet.or.lower.hidden',
47
+ );
48
+
49
+ expect(mobileTabletOnlyContent).toBeInTheDocument();
50
+ expect(tabletOrLowerHiddenContent).toBeInTheDocument();
51
+ expect(container.querySelector('.text')).toBeInTheDocument();
52
+ });
53
+
54
+ it('should scroll to top on button click', () => {
55
+ const { getByTitle } = render(<InpageNavigation />);
56
+ const button = getByTitle('Go to top');
57
+
58
+ fireEvent.click(button);
59
+
60
+ expect(scrollToMock).toHaveBeenCalledWith({
61
+ top: 0,
62
+ behavior: 'smooth',
63
+ });
64
+ });
65
+
66
+ it('should show the button when scroll position is greater than 50', () => {
67
+ Object.defineProperty(window, 'scrollY', { value: 100 });
68
+
69
+ const { getByTitle } = render(<InpageNavigation />);
70
+ const button = getByTitle('Go to top');
71
+
72
+ expect(button).toHaveStyle('display: inline-block;');
73
+ });
74
+
75
+ it('should update button visibility based on scroll position', () => {
76
+ const { getByTitle } = render(<InpageNavigation />);
77
+ const button = getByTitle('Go to top');
78
+
79
+ Object.defineProperty(window, 'scrollY', { value: 100 });
80
+ fireEvent.scroll(window);
81
+
82
+ expect(button).toHaveStyle('display: inline-block;');
83
+
84
+ Object.defineProperty(window, 'scrollY', { value: 30 });
85
+ fireEvent.scroll(window);
86
+ });
87
+ });
@@ -0,0 +1,39 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { DefaultGroup, DefaultItem, Default } from './Item.stories';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('DefaultGroup Component', () => {
7
+ it('renders correctly', () => {
8
+ const { container } = render(<DefaultGroup {...DefaultGroup.args} />);
9
+ DefaultGroup.args.items.forEach((element) => {
10
+ expect(
11
+ container.querySelector(`img[src="${element.image}"]`),
12
+ ).toBeInTheDocument();
13
+ });
14
+ expect(container.querySelector('.header')).toBeInTheDocument();
15
+ expect(container.querySelector('.meta')).toBeInTheDocument();
16
+ expect(container.querySelector('.description')).toBeInTheDocument();
17
+ expect(container.querySelector('.extra')).toBeInTheDocument();
18
+ });
19
+ });
20
+
21
+ describe('DefaultItem Component', () => {
22
+ it('renders correclty', () => {
23
+ const { container } = render(<DefaultItem {...DefaultItem.args} />);
24
+ expect(container.querySelector('.header')).toBeInTheDocument();
25
+ expect(container.querySelector('.meta')).toBeInTheDocument();
26
+ expect(container.querySelector('.description')).toBeInTheDocument();
27
+ expect(container.querySelector('.extra')).toBeInTheDocument();
28
+ });
29
+ });
30
+
31
+ describe('Default Component', () => {
32
+ it('renders correclty', () => {
33
+ const { container } = render(<Default {...Default.args} />);
34
+ expect(container.querySelector('.header')).toBeInTheDocument();
35
+ expect(container.querySelector('.meta')).toBeInTheDocument();
36
+ expect(container.querySelector('.description')).toBeInTheDocument();
37
+ expect(container.querySelector('.extra')).toBeInTheDocument();
38
+ });
39
+ });