@eeacms/volto-eea-design-system 1.16.0 → 1.17.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 (59) hide show
  1. package/CHANGELOG.md +31 -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 +82 -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 +113 -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 +69 -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/extras/banner.less +3 -3
  59. package/src/i18n.js +0 -180
package/CHANGELOG.md CHANGED
@@ -4,6 +4,37 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ ### [1.17.0](https://github.com/eea/volto-eea-design-system/compare/1.16.0...1.17.0) - 29 August 2023
8
+
9
+ #### :rocket: New Features
10
+
11
+ - feat(accordion): improve a11n by providing open close support using space bar on header [David Ichim - [`ac04dbd`](https://github.com/eea/volto-eea-design-system/commit/ac04dbd8fa166a70d535354f6ab631709ee021b3)]
12
+
13
+ #### :bug: Bug Fixes
14
+
15
+ - fix(popup): Fix wrong placement of Popper refs #256765 #384 from eea/popper [ichim-david - [`ee69ca2`](https://github.com/eea/volto-eea-design-system/commit/ee69ca299348509f10ecd954ae4415aaef347104)]
16
+ - fix(sharing): button placement and styling [David Ichim - [`15ecefc`](https://github.com/eea/volto-eea-design-system/commit/15ecefcb4e0a2fcc99d585bf0c913ea515b3f676)]
17
+
18
+ #### :nail_care: Enhancements
19
+
20
+ - change(accordion): removed listitem role from mobile accordion links [David Ichim - [`8b85dac`](https://github.com/eea/volto-eea-design-system/commit/8b85dac5451b10968275c9ed46a0b4cfc0ccd442)]
21
+ - change(mega-menu): mobile accordions now have aria expanded support [David Ichim - [`e0dbb3f`](https://github.com/eea/volto-eea-design-system/commit/e0dbb3f533c9022308527d2d44d32831f66b389f)]
22
+
23
+ #### :house: Internal changes
24
+
25
+ - chore: Remove i18n.js script [Alin Voinea - [`701b82a`](https://github.com/eea/volto-eea-design-system/commit/701b82a67dc97f774c6250d45f159c61b9c7bfec)]
26
+
27
+ #### :hammer_and_wrench: Others
28
+
29
+ - i18n: Add en [Alin Voinea - [`4584295`](https://github.com/eea/volto-eea-design-system/commit/458429530d993c27cfb962ddfe2f376f3568bf01)]
30
+ - Release 1.17.0 [Alin Voinea - [`e3c25ee`](https://github.com/eea/volto-eea-design-system/commit/e3c25eeeca5e863244faae396b5aa915d0702633)]
31
+ - test: add unit tests for DS components - refs #254313 [ana-oprea - [`0c4d4d1`](https://github.com/eea/volto-eea-design-system/commit/0c4d4d118b8e13082c576dc5c2dce6a715f49006)]
32
+ - chrore(mega-menu): mobile accordion accessibility enhancements #385 from eea/accordion-improvements [ichim-david - [`9dd717d`](https://github.com/eea/volto-eea-design-system/commit/9dd717dc4c82a220463da16dba33c9a9d1633c47)]
33
+ - fix popper [Dobricean Ioan Dorian - [`005f2be`](https://github.com/eea/volto-eea-design-system/commit/005f2be705136eebd5f8f4ae4dd5e27d9fbff15d)]
34
+ - fix [Dobricean Ioan Dorian - [`615e67f`](https://github.com/eea/volto-eea-design-system/commit/615e67ff3c9a0fbd6cc7cadbb0c845bf09eec4f0)]
35
+ - remove [Dobricean Ioan Dorian - [`bf3974b`](https://github.com/eea/volto-eea-design-system/commit/bf3974be18225c893fd09814cb2aca9a84ba0ece)]
36
+ - fix popper [Dobricean Ioan Dorian - [`762f199`](https://github.com/eea/volto-eea-design-system/commit/762f199ff5725e7ad1fb788feb4f7b7548d1ee44)]
37
+ - test: Update Makefile and docker-compose to align it with Jenkinsfile [valentinab25 - [`b7eea21`](https://github.com/eea/volto-eea-design-system/commit/b7eea21fd4e71c4f420cd061717166483082dd6e)]
7
38
  ### [1.16.0](https://github.com/eea/volto-eea-design-system/compare/1.15.0...1.16.0) - 17 August 2023
8
39
 
9
40
  #### :rocket: New Features
@@ -1,11 +1,12 @@
1
1
  version: "3"
2
2
  services:
3
3
  backend:
4
- image: plone/plone-backend:${PLONE_VERSION:-6}
4
+ image: eeacms/plone-backend
5
5
  ports:
6
6
  - "8080:8080"
7
7
  environment:
8
8
  SITE: "Plone"
9
+ PROFILES: "eea.kitkat:testing"
9
10
 
10
11
  frontend:
11
12
  build:
@@ -23,6 +24,9 @@ services:
23
24
  volumes:
24
25
  - ./:/app/src/addons/${ADDON_PATH}
25
26
  environment:
27
+ CI: "true"
28
+ NODE_ENV: "development"
29
+ RAZZLE_JEST_CONFIG: "src/addons/${ADDON_PATH}/jest-addon.config.js"
26
30
  RAZZLE_INTERNAL_API_PATH: "http://backend:8080/Plone"
27
31
  RAZZLE_DEV_PROXY_API_PATH: "http://backend:8080/Plone"
28
32
  HOST: "0.0.0.0"
@@ -0,0 +1,14 @@
1
+ msgid ""
2
+ msgstr ""
3
+ "Project-Id-Version: \n"
4
+ "Report-Msgid-Bugs-To: \n"
5
+ "POT-Creation-Date: \n"
6
+ "PO-Revision-Date: \n"
7
+ "Last-Translator: \n"
8
+ "Language: \n"
9
+ "Language-Team: \n"
10
+ "Content-Type: \n"
11
+ "Content-Transfer-Encoding: \n"
12
+ "Plural-Forms: \n"
13
+
14
+
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-eea-design-system",
3
- "version": "1.16.0",
3
+ "version": "1.17.0",
4
4
  "description": "@eeacms/volto-eea-design-system: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -1,4 +1,4 @@
1
- export useClickOutside from './useClickOutside';
2
- export usePrevious from './usePrevious';
3
- export useFirstVisited from './useFirstVisited';
4
- export handleEnterKeyPress from './eventHandlers';
1
+ export { default as useClickOutside } from './useClickOutside';
2
+ export { default as usePrevious } from './usePrevious';
3
+ export { default as useFirstVisited } from './useFirstVisited';
4
+ export { default as handleEnterKeyPress } from './eventHandlers';
@@ -0,0 +1,63 @@
1
+ import { act, renderHook } from '@testing-library/react-hooks';
2
+ import useClickOutside from './useClickOutside';
3
+ import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib';
4
+
5
+ jest.mock('semantic-ui-react/dist/commonjs/lib', () => ({
6
+ doesNodeContainClick: jest.fn(),
7
+ }));
8
+
9
+ describe('useClickOutside', () => {
10
+ let ref;
11
+ let callback;
12
+
13
+ beforeEach(() => {
14
+ ref = { current: {} };
15
+ callback = jest.fn();
16
+ });
17
+
18
+ it('does not call callback function when clicked inside', () => {
19
+ doesNodeContainClick.mockImplementation(() => true);
20
+
21
+ const { rerender } = renderHook(() =>
22
+ useClickOutside({ targetRefs: [ref], callback }),
23
+ );
24
+
25
+ act(() => {
26
+ document.dispatchEvent(new MouseEvent('mousedown'));
27
+ });
28
+
29
+ rerender();
30
+
31
+ expect(callback).not.toHaveBeenCalled();
32
+ });
33
+
34
+ it('calls callback function when clicked outside', () => {
35
+ doesNodeContainClick.mockImplementation(() => false);
36
+
37
+ const { rerender } = renderHook(() =>
38
+ useClickOutside({ targetRefs: [ref], callback }),
39
+ );
40
+
41
+ act(() => {
42
+ document.dispatchEvent(new MouseEvent('mousedown'));
43
+ });
44
+
45
+ rerender();
46
+
47
+ expect(callback).toHaveBeenCalled();
48
+ });
49
+
50
+ it('calls callback function when clicked outside and no refs', () => {
51
+ doesNodeContainClick.mockImplementation(() => false);
52
+
53
+ const { rerender } = renderHook(() => useClickOutside({ callback }));
54
+
55
+ act(() => {
56
+ document.dispatchEvent(new MouseEvent('mousedown'));
57
+ });
58
+
59
+ rerender();
60
+
61
+ expect(callback).toHaveBeenCalled();
62
+ });
63
+ });
@@ -0,0 +1,54 @@
1
+ import { renderHook } from '@testing-library/react-hooks';
2
+ import useFirstVisited from './useFirstVisited';
3
+
4
+ describe('useFirstVisited', () => {
5
+ let observe;
6
+ let unobserve;
7
+ let callback;
8
+ let disconnect;
9
+
10
+ beforeEach(() => {
11
+ observe = jest.fn();
12
+ unobserve = jest.fn();
13
+ disconnect = jest.fn();
14
+
15
+ window.IntersectionObserver = jest.fn(function (cb) {
16
+ this.observe = observe;
17
+ this.unobserve = unobserve;
18
+ this.disconnect = disconnect;
19
+ callback = cb;
20
+ });
21
+ });
22
+ it('should set intersected to true when element is intersecting', async () => {
23
+ const ref = { current: document.createElement('div') };
24
+ const { result } = renderHook(() => useFirstVisited(ref));
25
+ const entry = { isIntersecting: true };
26
+
27
+ expect(result.current).toBe(false); // Initial state
28
+ callback([entry]);
29
+ expect(result.current).toBe(true);
30
+ });
31
+
32
+ it('should unobserve and disconnect when ref changes or component unmounts', () => {
33
+ const ref = { current: document.createElement('div') };
34
+ const newRef = { current: document.createElement('div') };
35
+ const { unmount, rerender } = renderHook(
36
+ ({ ref }) => useFirstVisited(ref),
37
+ {
38
+ initialProps: { ref },
39
+ },
40
+ );
41
+
42
+ expect(unobserve).not.toHaveBeenCalled();
43
+ expect(disconnect).not.toHaveBeenCalled();
44
+
45
+ rerender({ ref: newRef });
46
+ expect(unobserve).toHaveBeenCalled();
47
+ expect(disconnect).toHaveBeenCalled();
48
+
49
+ unmount();
50
+
51
+ expect(unobserve).toHaveBeenCalledTimes(2);
52
+ expect(disconnect).toHaveBeenCalledTimes(2);
53
+ });
54
+ });
@@ -93,10 +93,12 @@ function AccordionContainer({ ...args }) {
93
93
  index={index}
94
94
  tabIndex={0}
95
95
  active={active}
96
+ role="button"
97
+ aria-expanded={activeIndex === index}
96
98
  onClick={handleClick}
97
99
  as={args.title_size === 'no value' ? '' : args.title_size}
98
100
  onKeyDown={(e) => {
99
- if (e.nativeEvent.keyCode === 13) {
101
+ if (e.keyCode === 13 || e.keyCode === 32) {
100
102
  handleClick(e, { index });
101
103
  }
102
104
  }}
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react';
3
+ import { Default } from './Accordion.stories';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('Default component', () => {
7
+ it('renders correctly and fires keyDown Enter events', () => {
8
+ const { getByText, getAllByText } = render(<Default {...Default.args} />);
9
+
10
+ Default.args.panels.forEach((panel) => {
11
+ expect(getByText(panel.title)).toBeInTheDocument();
12
+ });
13
+
14
+ expect(getAllByText(Default.args.panels[0].content)).toHaveLength(3);
15
+ fireEvent.keyDown(getByText(Default.args.panels[0].title), {
16
+ key: 'Enter',
17
+ code: 'Enter',
18
+ keyCode: 13,
19
+ charCode: 13,
20
+ });
21
+
22
+ fireEvent.keyDown(getByText(Default.args.panels[0].title), {
23
+ key: 'Enter',
24
+ code: 'Enter',
25
+ keyCode: 13,
26
+ charCode: 13,
27
+ });
28
+ });
29
+
30
+ it('renders correctly and fires keyDown A event', () => {
31
+ const { getByText, getAllByText } = render(
32
+ <Default {...Default.args} title_size={'h1'} />,
33
+ );
34
+
35
+ Default.args.panels.forEach((panel) => {
36
+ expect(getByText(panel.title)).toBeInTheDocument();
37
+ });
38
+
39
+ expect(getAllByText(Default.args.panels[0].content)).toHaveLength(3);
40
+ fireEvent.keyDown(getByText(Default.args.panels[0].title), {
41
+ key: 'A',
42
+ code: 'KeyA',
43
+ });
44
+ });
45
+ });
@@ -0,0 +1,292 @@
1
+ import React from 'react';
2
+ import { render, fireEvent } from '@testing-library/react';
3
+ import Banner from './Banner';
4
+ import { sharePage } from './Banner';
5
+ import '@testing-library/jest-dom/extend-expect';
6
+
7
+ describe('Banner', () => {
8
+ it('renders without errors', () => {
9
+ const { container } = render(<Banner />);
10
+ expect(container).toBeInTheDocument();
11
+ });
12
+
13
+ it('renders the children when image prop is not provided', () => {
14
+ const image = 'image-url';
15
+ const properties = {};
16
+ const { getByText } = render(
17
+ <Banner image={image} properties={properties}>
18
+ <div>Content</div>
19
+ </Banner>,
20
+ );
21
+ expect(getByText('Content')).toBeInTheDocument();
22
+ });
23
+
24
+ it('renders the image and children when image prop is provided', () => {
25
+ const image = 'image-url';
26
+ const metadata = {
27
+ image: {
28
+ scales: {
29
+ huge: {
30
+ download: 'image-url',
31
+ },
32
+ },
33
+ },
34
+ };
35
+ const { container, getByText } = render(
36
+ <Banner image={image} metadata={metadata}>
37
+ <div>Content</div>
38
+ </Banner>,
39
+ );
40
+ const imageElement = container.querySelector('.eea.banner .image');
41
+ expect(imageElement).toBeInTheDocument();
42
+ expect(imageElement.style.backgroundImage).toBe(`url(${image})`);
43
+ expect(getByText('Content')).toBeInTheDocument();
44
+ });
45
+
46
+ it('calls the onClick function when an action button is clicked', () => {
47
+ const onClick = jest.fn();
48
+ const { getByText } = render(
49
+ <Banner.Action title="Action" icon="icon-name" onClick={onClick} />,
50
+ );
51
+ const actionButton = getByText('Action');
52
+ fireEvent.click(actionButton);
53
+ expect(onClick).toHaveBeenCalled();
54
+ });
55
+
56
+ it('renders only the gradient and children when image prop is not provided', () => {
57
+ const { container, getByText } = render(
58
+ <Banner>
59
+ <div>Content</div>
60
+ </Banner>,
61
+ );
62
+ const imageElement = container.querySelector('.eea.banner .image');
63
+ expect(imageElement).not.toBeInTheDocument();
64
+ const gradientElement = container.querySelector('.eea.banner .gradient');
65
+ expect(gradientElement).toBeInTheDocument();
66
+ expect(getByText('Content')).toBeInTheDocument();
67
+ });
68
+
69
+ it('calls the onClick handler when the action button is clicked', () => {
70
+ const onClick = jest.fn();
71
+ const { getByText } = render(
72
+ <Banner.Action title="Action" icon="icon-name" onClick={onClick} />,
73
+ );
74
+ const actionButton = getByText('Action');
75
+ fireEvent.click(actionButton);
76
+ expect(onClick).toHaveBeenCalledTimes(1);
77
+ });
78
+
79
+ it('renders the content and actions correctly', () => {
80
+ const { getByText } = render(
81
+ <>
82
+ <Banner.Title>Test Banner Title</Banner.Title>
83
+ <Banner.Subtitle>Test Banner Subtitle</Banner.Subtitle>
84
+ <Banner.Metadata>Test Banner Metadata</Banner.Metadata>
85
+ <Banner.MetadataField
86
+ hidden={false}
87
+ label={'Test label'}
88
+ value={'02.03.2023'}
89
+ type={'date'}
90
+ >
91
+ Test Banner MetadataField
92
+ </Banner.MetadataField>
93
+ <Banner.Content actions={<div>Actions</div>}>
94
+ <div>Content</div>
95
+ </Banner.Content>
96
+ </>,
97
+ );
98
+ expect(getByText('Content')).toBeInTheDocument();
99
+ expect(getByText('Actions')).toBeInTheDocument();
100
+ expect(getByText('Test Banner Title')).toBeInTheDocument();
101
+ expect(getByText('Test Banner Subtitle')).toBeInTheDocument();
102
+ expect(getByText('Test Banner Metadata')).toBeInTheDocument();
103
+ });
104
+
105
+ it('renders the content and actions correctly', () => {
106
+ const { getByText } = render(
107
+ <>
108
+ <Banner.Title>Test Banner Title</Banner.Title>
109
+ <Banner.Subtitle>Test Banner Subtitle</Banner.Subtitle>
110
+ <Banner.Metadata>Test Banner Metadata</Banner.Metadata>
111
+ <Banner.MetadataField
112
+ hidden={false}
113
+ label={'Test label'}
114
+ value={'test'}
115
+ type={'text'}
116
+ >
117
+ Test Banner MetadataField
118
+ </Banner.MetadataField>
119
+ <Banner.Content actions={<div>Actions</div>}>
120
+ <div>Content</div>
121
+ </Banner.Content>
122
+ </>,
123
+ );
124
+ expect(getByText('Content')).toBeInTheDocument();
125
+ expect(getByText('Actions')).toBeInTheDocument();
126
+ expect(getByText('Test Banner Title')).toBeInTheDocument();
127
+ expect(getByText('Test Banner Subtitle')).toBeInTheDocument();
128
+ expect(getByText('Test Banner Metadata')).toBeInTheDocument();
129
+ });
130
+
131
+ it('renders the content and actions correctly', () => {
132
+ const { getByText } = render(
133
+ <>
134
+ <Banner.Title>Test Banner Title</Banner.Title>
135
+ <Banner.Subtitle>Test Banner Subtitle</Banner.Subtitle>
136
+ <Banner.Metadata>Test Banner Metadata</Banner.Metadata>
137
+ <Banner.MetadataField
138
+ hidden={true}
139
+ label={'Test label'}
140
+ value={undefined}
141
+ type={undefined}
142
+ >
143
+ Test Banner MetadataField
144
+ </Banner.MetadataField>
145
+ <Banner.Content actions={<div>Actions</div>}>
146
+ <div>Content</div>
147
+ </Banner.Content>
148
+ </>,
149
+ );
150
+ expect(getByText('Content')).toBeInTheDocument();
151
+ expect(getByText('Actions')).toBeInTheDocument();
152
+ expect(getByText('Test Banner Title')).toBeInTheDocument();
153
+ expect(getByText('Test Banner Subtitle')).toBeInTheDocument();
154
+ expect(getByText('Test Banner Metadata')).toBeInTheDocument();
155
+ });
156
+ });
157
+
158
+ describe('sharePage', () => {
159
+ it('should not do anything if an invalid platform is provided', () => {
160
+ document.createElement = jest.fn();
161
+ sharePage('https://example.com', 'invalidPlatform');
162
+ expect(document.createElement).not.toHaveBeenCalled();
163
+ });
164
+
165
+ it('should create an anchor element and click it for a valid platform', () => {
166
+ const url = 'https://example.com';
167
+ const platform = 'facebook';
168
+
169
+ const mockLink = {
170
+ setAttribute: jest.fn(),
171
+ click: jest.fn(),
172
+ };
173
+
174
+ document.createElement = jest.fn(() => mockLink);
175
+
176
+ sharePage(url, platform);
177
+
178
+ expect(document.createElement).toHaveBeenCalledWith('a');
179
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
180
+ 1,
181
+ 'href',
182
+ `https://facebook.com/sharer.php?u=${url}`,
183
+ );
184
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
185
+ 2,
186
+ 'target',
187
+ '_blank',
188
+ );
189
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
190
+ 3,
191
+ 'rel',
192
+ 'noreferrer',
193
+ );
194
+ expect(mockLink.click).toHaveBeenCalled();
195
+ });
196
+
197
+ it('should create an anchor element and click it for a valid platform', () => {
198
+ const url = 'https://example.com';
199
+ const platform = 'twitter';
200
+
201
+ const mockLink = {
202
+ setAttribute: jest.fn(),
203
+ click: jest.fn(),
204
+ };
205
+
206
+ document.createElement = jest.fn(() => mockLink);
207
+
208
+ sharePage(url, platform);
209
+
210
+ expect(document.createElement).toHaveBeenCalledWith('a');
211
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
212
+ 1,
213
+ 'href',
214
+ `https://www.twitter.com/share?url=${url}`,
215
+ );
216
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
217
+ 2,
218
+ 'target',
219
+ '_blank',
220
+ );
221
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
222
+ 3,
223
+ 'rel',
224
+ 'noreferrer',
225
+ );
226
+ expect(mockLink.click).toHaveBeenCalled();
227
+ });
228
+
229
+ it('should create an anchor element and click it for a valid platform', () => {
230
+ const url = 'https://example.com';
231
+ const platform = 'linkedin';
232
+
233
+ const mockLink = {
234
+ setAttribute: jest.fn(),
235
+ click: jest.fn(),
236
+ };
237
+
238
+ document.createElement = jest.fn(() => mockLink);
239
+
240
+ sharePage(url, platform);
241
+
242
+ expect(document.createElement).toHaveBeenCalledWith('a');
243
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
244
+ 1,
245
+ 'href',
246
+ `https://www.linkedin.com/sharing/share-offsite/?url=${url}`,
247
+ );
248
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
249
+ 2,
250
+ 'target',
251
+ '_blank',
252
+ );
253
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
254
+ 3,
255
+ 'rel',
256
+ 'noreferrer',
257
+ );
258
+ expect(mockLink.click).toHaveBeenCalled();
259
+ });
260
+
261
+ it('should create an anchor element and click it for a valid platform', () => {
262
+ const url = 'https://example.com';
263
+ const platform = 'reddit';
264
+
265
+ const mockLink = {
266
+ setAttribute: jest.fn(),
267
+ click: jest.fn(),
268
+ };
269
+
270
+ document.createElement = jest.fn(() => mockLink);
271
+
272
+ sharePage(url, platform);
273
+
274
+ expect(document.createElement).toHaveBeenCalledWith('a');
275
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
276
+ 1,
277
+ 'href',
278
+ `https://reddit.com/submit?url=${url}`,
279
+ );
280
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
281
+ 2,
282
+ 'target',
283
+ '_blank',
284
+ );
285
+ expect(mockLink.setAttribute).toHaveBeenNthCalledWith(
286
+ 3,
287
+ 'rel',
288
+ 'noreferrer',
289
+ );
290
+ expect(mockLink.click).toHaveBeenCalled();
291
+ });
292
+ });
@@ -0,0 +1,69 @@
1
+ import React from 'react';
2
+ import { render } from '@testing-library/react';
3
+ import { Default, Inverted, Link, Labeled } from './CallToAction.stories';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+
6
+ describe('Link', () => {
7
+ it('renders correctly', () => {
8
+ const { container } = render(<Link {...Link.args} />);
9
+ expect(
10
+ container.querySelector(`a[href="${Link.args.href}"]`),
11
+ ).toBeInTheDocument();
12
+ });
13
+ });
14
+
15
+ describe('Labeled', () => {
16
+ it('renders correctly', () => {
17
+ const { container, getByText } = render(<Labeled {...Labeled.args} />);
18
+ expect(
19
+ container.querySelector(`a[href="${Labeled.args.href}"]`),
20
+ ).toBeInTheDocument();
21
+ expect(getByText(Labeled.args.label)).toBeInTheDocument();
22
+ });
23
+
24
+ it('renders correctly', () => {
25
+ const { container, getByText } = render(
26
+ <Labeled {...Labeled.args} variant={'default'} />,
27
+ );
28
+ expect(
29
+ container.querySelector(`a[href="${Labeled.args.href}"]`),
30
+ ).toBeInTheDocument();
31
+ expect(getByText(Labeled.args.label)).toBeInTheDocument();
32
+ });
33
+ });
34
+
35
+ describe('Inverted', () => {
36
+ it('renders correctly', () => {
37
+ const { container } = render(<Inverted {...Inverted.args} />);
38
+ expect(
39
+ container.querySelector(`a[href="${Inverted.args.href}"]`),
40
+ ).toBeInTheDocument();
41
+ });
42
+
43
+ it('renders correctly', () => {
44
+ const { container } = render(
45
+ <Inverted {...Inverted.args} variant={'default'} />,
46
+ );
47
+ expect(
48
+ container.querySelector(`a[href="${Inverted.args.href}"]`),
49
+ ).toBeInTheDocument();
50
+ });
51
+ });
52
+
53
+ describe('Default', () => {
54
+ it('renders correctly', () => {
55
+ const { container } = render(<Default {...Default.args} />);
56
+ expect(
57
+ container.querySelector(`a[href="${Default.args.href}"]`),
58
+ ).toBeInTheDocument();
59
+ });
60
+
61
+ it('renders correctly', () => {
62
+ const { container } = render(
63
+ <Default {...Default.args} variant={'default'} />,
64
+ );
65
+ expect(
66
+ container.querySelector(`a[href="${Default.args.href}"]`),
67
+ ).toBeInTheDocument();
68
+ });
69
+ });