@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
package/CHANGELOG.md CHANGED
@@ -4,6 +4,63 @@ 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.18.0](https://github.com/eea/volto-eea-design-system/compare/1.17.0...1.18.0) - 1 September 2023
8
+
9
+ #### :bug: Bug Fixes
10
+
11
+ - fix(accordion): fix accordion filtering size and color #387 from eea/accordion-filter [ichim-david - [`0356c1c`](https://github.com/eea/volto-eea-design-system/commit/0356c1c5de27bd9a7bfbddf7d07d7247d485fe0f)]
12
+ - fix(accordion): fix filtering text color [kreafox - [`e6b6ebc`](https://github.com/eea/volto-eea-design-system/commit/e6b6ebc176b82cca7c25a5af0cc563e7560557b8)]
13
+ - fix(accordion): fix accordion filtering size and color [kreafox - [`a4abb86`](https://github.com/eea/volto-eea-design-system/commit/a4abb86ce8d196483b0df13f848a533ed12ea797)]
14
+
15
+ #### :nail_care: Enhancements
16
+
17
+ - perf(site): optimize footer svg using svgomg dropping size from 868kb to 422kb [David Ichim - [`5118c62`](https://github.com/eea/volto-eea-design-system/commit/5118c62883c83883ef3c7cead137ddc45f471eaf)]
18
+ - change(item): added column widths for flex-item-wrapper [David Ichim - [`0e0e894`](https://github.com/eea/volto-eea-design-system/commit/0e0e894dedb0edec0fd3209b890a6f0b722b7217)]
19
+
20
+ #### :house: Internal changes
21
+
22
+ - chore: lint fix [David Ichim - [`43fc96d`](https://github.com/eea/volto-eea-design-system/commit/43fc96d9da6de4eec1aed36c4d7e75b650709bd9)]
23
+
24
+ #### :hammer_and_wrench: Others
25
+
26
+ - bump package version [David Ichim - [`f4006b8`](https://github.com/eea/volto-eea-design-system/commit/f4006b8c98658236e9a9d5a69919ca2752aba599)]
27
+ - perf(site): optimize footer svg using svgomg dropping size from 868kb to 422kb [David Ichim - [`5118c62`](https://github.com/eea/volto-eea-design-system/commit/5118c62883c83883ef3c7cead137ddc45f471eaf)]
28
+ - test: fix tests failing #388 from eea/fix-tests [ichim-david - [`cfb0213`](https://github.com/eea/volto-eea-design-system/commit/cfb0213686d7e0ef92058956a090eb36cb0195f3)]
29
+ - prettier fix [David Ichim - [`8480802`](https://github.com/eea/volto-eea-design-system/commit/848080233fb761649174e9abdb2d1f3cabcb9568)]
30
+ - lint fix [David Ichim - [`4ec6099`](https://github.com/eea/volto-eea-design-system/commit/4ec6099685f93c58a858282d3791643931d7cb64)]
31
+ - test: fix tests failing [ana-oprea - [`f00f4e3`](https://github.com/eea/volto-eea-design-system/commit/f00f4e36f14898c4c5bdd647828a89a04b0f5941)]
32
+ - fix error reading baseWidth less variable [David Ichim - [`f83dcb1`](https://github.com/eea/volto-eea-design-system/commit/f83dcb16017c368acb8e612a8f34c93d195fec64)]
33
+ ### [1.17.0](https://github.com/eea/volto-eea-design-system/compare/1.16.0...1.17.0) - 29 August 2023
34
+
35
+ #### :rocket: New Features
36
+
37
+ - 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)]
38
+
39
+ #### :bug: Bug Fixes
40
+
41
+ - 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)]
42
+ - fix(sharing): button placement and styling [David Ichim - [`15ecefc`](https://github.com/eea/volto-eea-design-system/commit/15ecefcb4e0a2fcc99d585bf0c913ea515b3f676)]
43
+
44
+ #### :nail_care: Enhancements
45
+
46
+ - change(accordion): removed listitem role from mobile accordion links [David Ichim - [`8b85dac`](https://github.com/eea/volto-eea-design-system/commit/8b85dac5451b10968275c9ed46a0b4cfc0ccd442)]
47
+ - change(mega-menu): mobile accordions now have aria expanded support [David Ichim - [`e0dbb3f`](https://github.com/eea/volto-eea-design-system/commit/e0dbb3f533c9022308527d2d44d32831f66b389f)]
48
+
49
+ #### :house: Internal changes
50
+
51
+ - chore: Remove i18n.js script [Alin Voinea - [`701b82a`](https://github.com/eea/volto-eea-design-system/commit/701b82a67dc97f774c6250d45f159c61b9c7bfec)]
52
+
53
+ #### :hammer_and_wrench: Others
54
+
55
+ - i18n: Add en [Alin Voinea - [`4584295`](https://github.com/eea/volto-eea-design-system/commit/458429530d993c27cfb962ddfe2f376f3568bf01)]
56
+ - Release 1.17.0 [Alin Voinea - [`e3c25ee`](https://github.com/eea/volto-eea-design-system/commit/e3c25eeeca5e863244faae396b5aa915d0702633)]
57
+ - test: add unit tests for DS components - refs #254313 [ana-oprea - [`0c4d4d1`](https://github.com/eea/volto-eea-design-system/commit/0c4d4d118b8e13082c576dc5c2dce6a715f49006)]
58
+ - 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)]
59
+ - fix popper [Dobricean Ioan Dorian - [`005f2be`](https://github.com/eea/volto-eea-design-system/commit/005f2be705136eebd5f8f4ae4dd5e27d9fbff15d)]
60
+ - fix [Dobricean Ioan Dorian - [`615e67f`](https://github.com/eea/volto-eea-design-system/commit/615e67ff3c9a0fbd6cc7cadbb0c845bf09eec4f0)]
61
+ - remove [Dobricean Ioan Dorian - [`bf3974b`](https://github.com/eea/volto-eea-design-system/commit/bf3974be18225c893fd09814cb2aca9a84ba0ece)]
62
+ - fix popper [Dobricean Ioan Dorian - [`762f199`](https://github.com/eea/volto-eea-design-system/commit/762f199ff5725e7ad1fb788feb4f7b7548d1ee44)]
63
+ - test: Update Makefile and docker-compose to align it with Jenkinsfile [valentinab25 - [`b7eea21`](https://github.com/eea/volto-eea-design-system/commit/b7eea21fd4e71c4f420cd061717166483082dd6e)]
7
64
  ### [1.16.0](https://github.com/eea/volto-eea-design-system/compare/1.15.0...1.16.0) - 17 August 2023
8
65
 
9
66
  #### :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.18.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
+ });