From 0c4d4d118b8e13082c576dc5c2dce6a715f49006 Mon Sep 17 00:00:00 2001 From: ana-oprea <80201759+ana-oprea@users.noreply.github.com> Date: Tue, 29 Aug 2023 18:16:25 +0300 Subject: [PATCH] test: add unit tests for DS components - refs #254313 * test: add e2e tests for Card.stories, Header, HeaderMenuPopUp, HeaderSearchPopUp - refs #254313 * chore: ESlint code cleanup - refs #254313 * test: add unit tests for Banner, Card and Header - refs #254313 * chore: fix ESlint failing - refs #254313 * test: add unit tests for Button - refs #254313 * test: add unit tests for Statistic - refs #254313 * test: add unit tests for Popup - refs #254313 * test: add unit tests for Message - refs #254313 * test: add unit tests for RelatedContent - refs #254313 * chore: cleanup code for Card tests - refs #254313 * chore: fix Jenkins unit tests failing - refs #254313 * test: add unit tests for LanguageLabeledIcon - refs #254313 * test: add unit tests for Table - refs #254313 * chore: fix failing Jenkins test - refs #254313 * test: add unit tests for Radio, Input - refs #254313 * test: add unit tests for Timeline - refs #254313 * test: add unit tests for Item - refs #254313 * test: add unit tests for CallToAction - refs #254313 * refactor: delete content.hidden from LanguageLabeledIcon - refs #254313 * test: add unit tests for Checkbox - refs #254313 * test: add unit tests for Footer - refs #254313 * test: add unit tests for Logo - refs #254313 * test: add unit tests for Accordion - refs #254313 * test: add unit tests for ItemGroupWithIcons - refs #254313 * test: add unit tests for useFirstVisited, Confirm, DownloadLabeledIcon, Dropdown, InpageNavigation, Label, Progress - refs #254313 * chore: fix ESlint - refs #254313 * test: add unit tests - refs #254313 * chore: fix ESlint - refs #254313 --- src/helpers/useClickOutside.test.js | 63 ++++ src/helpers/useFirstVisited.test.js | 54 ++++ src/ui/Accordion/Accordion.stories.test.js | 45 +++ src/ui/Banner/Banner.test.jsx | 292 +++++++++++++++++ .../CallToAction.stories.test.jsx | 69 +++++ src/ui/Card/Card.stories.test.jsx | 82 +++++ .../Card/IconCard/IconCard.stories.test.jsx | 64 ++++ src/ui/Card/RelatedContent/RelatedContent.jsx | 2 +- .../RelatedContent/RelatedContent.stories.jsx | 4 +- .../RelatedContent.stories.test.jsx | 65 ++++ src/ui/Confirm/Confirm.stories.test.js | 27 ++ .../ContextNavigation.stories.test.jsx | 170 ++++++++++ src/ui/Divider/Divider.stories.test.jsx | 44 +++ .../DownloadLabeledIcon.stories.test.jsx | 24 ++ src/ui/Footer/Description.test.jsx | 11 + src/ui/Footer/Footer.stories.test.js | 131 ++++++++ src/ui/Footer/Social.test.jsx | 11 + src/ui/Form/Button/Button.stories.test.jsx | 55 ++++ src/ui/Form/Checkbox.stories.test.js | 79 +++++ src/ui/Form/Dropdown.stories.test.js | 24 ++ src/ui/Form/Radio.stories.test.js | 55 ++++ src/ui/Form/Textarea.stories.test.js | 41 +++ src/ui/Form/input.stories.test.js | 52 ++++ src/ui/Grid/ComponentGrid.stories.test.js | 21 ++ src/ui/Header/Header.stories.test.js | 158 ++++++++++ src/ui/Header/Header.test.jsx | 293 ++++++++++++++++++ src/ui/Header/HeaderSearchPopUp.test.js | 113 +++++++ src/ui/Hero/Hero.stories.test.jsx | 67 ++++ .../InpageNavigation.stories.test.jsx | 10 + .../InpageNavigation.test.jsx | 87 ++++++ src/ui/Item/Item.stories.test.js | 39 +++ .../Item/ItemGroupWithIcons.stories.test.js | 119 +++++++ src/ui/Label/Label.stories.test.js | 76 +++++ .../LabeledIconGroup.stories.test.jsx | 19 ++ .../LanguageLabeledIcon.jsx | 5 +- .../LanguangeLabeledIcon.test.jsx | 60 ++++ src/ui/Loader/Loader.stories.test.jsx | 30 ++ src/ui/Logo/Logo.stories.test.jsx | 81 +++++ src/ui/Media/Image.stories.test.js | 35 +++ src/ui/Message/Message.stories.test.js | 44 +++ src/ui/Modal/Modal.stories.test.js | 45 +++ src/ui/Popup/Popup.test.jsx | 60 ++++ src/ui/Progress/Progress.stories.test.js | 30 ++ .../Testimonial/Testimonial.stories.test.jsx | 18 ++ src/ui/Statistic/Statistic.stories.test.js | 69 +++++ src/ui/Table/Table.stories.test.js | 54 ++++ src/ui/Timeline/Timeline.stories.test.jsx | 43 +++ 47 files changed, 3035 insertions(+), 5 deletions(-) create mode 100644 src/helpers/useClickOutside.test.js create mode 100644 src/helpers/useFirstVisited.test.js create mode 100644 src/ui/Accordion/Accordion.stories.test.js create mode 100644 src/ui/Banner/Banner.test.jsx create mode 100644 src/ui/CallToAction/CallToAction.stories.test.jsx create mode 100644 src/ui/Card/Card.stories.test.jsx create mode 100644 src/ui/Card/IconCard/IconCard.stories.test.jsx create mode 100644 src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx create mode 100644 src/ui/Confirm/Confirm.stories.test.js create mode 100644 src/ui/ContextNavigation/ContextNavigation.stories.test.jsx create mode 100644 src/ui/Divider/Divider.stories.test.jsx create mode 100644 src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx create mode 100644 src/ui/Footer/Description.test.jsx create mode 100644 src/ui/Footer/Footer.stories.test.js create mode 100644 src/ui/Footer/Social.test.jsx create mode 100644 src/ui/Form/Button/Button.stories.test.jsx create mode 100644 src/ui/Form/Checkbox.stories.test.js create mode 100644 src/ui/Form/Dropdown.stories.test.js create mode 100644 src/ui/Form/Radio.stories.test.js create mode 100644 src/ui/Form/Textarea.stories.test.js create mode 100644 src/ui/Form/input.stories.test.js create mode 100644 src/ui/Grid/ComponentGrid.stories.test.js create mode 100644 src/ui/Header/Header.stories.test.js create mode 100644 src/ui/Header/Header.test.jsx create mode 100644 src/ui/Header/HeaderSearchPopUp.test.js create mode 100644 src/ui/Hero/Hero.stories.test.jsx create mode 100644 src/ui/InpageNavigation/InpageNavigation.stories.test.jsx create mode 100644 src/ui/InpageNavigation/InpageNavigation.test.jsx create mode 100644 src/ui/Item/Item.stories.test.js create mode 100644 src/ui/Item/ItemGroupWithIcons.stories.test.js create mode 100644 src/ui/Label/Label.stories.test.js create mode 100644 src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx create mode 100644 src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx create mode 100644 src/ui/Loader/Loader.stories.test.jsx create mode 100644 src/ui/Logo/Logo.stories.test.jsx create mode 100644 src/ui/Media/Image.stories.test.js create mode 100644 src/ui/Message/Message.stories.test.js create mode 100644 src/ui/Modal/Modal.stories.test.js create mode 100644 src/ui/Popup/Popup.test.jsx create mode 100644 src/ui/Progress/Progress.stories.test.js create mode 100644 src/ui/Quote/Testimonial/Testimonial.stories.test.jsx create mode 100644 src/ui/Statistic/Statistic.stories.test.js create mode 100644 src/ui/Table/Table.stories.test.js create mode 100644 src/ui/Timeline/Timeline.stories.test.jsx diff --git a/src/helpers/useClickOutside.test.js b/src/helpers/useClickOutside.test.js new file mode 100644 index 0000000000..07bdfd0387 --- /dev/null +++ b/src/helpers/useClickOutside.test.js @@ -0,0 +1,63 @@ +import { act, renderHook } from '@testing-library/react-hooks'; +import useClickOutside from './useClickOutside'; +import { doesNodeContainClick } from 'semantic-ui-react/dist/commonjs/lib'; + +jest.mock('semantic-ui-react/dist/commonjs/lib', () => ({ + doesNodeContainClick: jest.fn(), +})); + +describe('useClickOutside', () => { + let ref; + let callback; + + beforeEach(() => { + ref = { current: {} }; + callback = jest.fn(); + }); + + it('does not call callback function when clicked inside', () => { + doesNodeContainClick.mockImplementation(() => true); + + const { rerender } = renderHook(() => + useClickOutside({ targetRefs: [ref], callback }), + ); + + act(() => { + document.dispatchEvent(new MouseEvent('mousedown')); + }); + + rerender(); + + expect(callback).not.toHaveBeenCalled(); + }); + + it('calls callback function when clicked outside', () => { + doesNodeContainClick.mockImplementation(() => false); + + const { rerender } = renderHook(() => + useClickOutside({ targetRefs: [ref], callback }), + ); + + act(() => { + document.dispatchEvent(new MouseEvent('mousedown')); + }); + + rerender(); + + expect(callback).toHaveBeenCalled(); + }); + + it('calls callback function when clicked outside and no refs', () => { + doesNodeContainClick.mockImplementation(() => false); + + const { rerender } = renderHook(() => useClickOutside({ callback })); + + act(() => { + document.dispatchEvent(new MouseEvent('mousedown')); + }); + + rerender(); + + expect(callback).toHaveBeenCalled(); + }); +}); diff --git a/src/helpers/useFirstVisited.test.js b/src/helpers/useFirstVisited.test.js new file mode 100644 index 0000000000..c3d0fbc619 --- /dev/null +++ b/src/helpers/useFirstVisited.test.js @@ -0,0 +1,54 @@ +import { renderHook } from '@testing-library/react-hooks'; +import useFirstVisited from './useFirstVisited'; + +describe('useFirstVisited', () => { + let observe; + let unobserve; + let callback; + let disconnect; + + beforeEach(() => { + observe = jest.fn(); + unobserve = jest.fn(); + disconnect = jest.fn(); + + window.IntersectionObserver = jest.fn(function (cb) { + this.observe = observe; + this.unobserve = unobserve; + this.disconnect = disconnect; + callback = cb; + }); + }); + it('should set intersected to true when element is intersecting', async () => { + const ref = { current: document.createElement('div') }; + const { result } = renderHook(() => useFirstVisited(ref)); + const entry = { isIntersecting: true }; + + expect(result.current).toBe(false); // Initial state + callback([entry]); + expect(result.current).toBe(true); + }); + + it('should unobserve and disconnect when ref changes or component unmounts', () => { + const ref = { current: document.createElement('div') }; + const newRef = { current: document.createElement('div') }; + const { unmount, rerender } = renderHook( + ({ ref }) => useFirstVisited(ref), + { + initialProps: { ref }, + }, + ); + + expect(unobserve).not.toHaveBeenCalled(); + expect(disconnect).not.toHaveBeenCalled(); + + rerender({ ref: newRef }); + expect(unobserve).toHaveBeenCalled(); + expect(disconnect).toHaveBeenCalled(); + + unmount(); + + expect(unobserve).toHaveBeenCalledTimes(2); + expect(disconnect).toHaveBeenCalledTimes(2); + }); +}); diff --git a/src/ui/Accordion/Accordion.stories.test.js b/src/ui/Accordion/Accordion.stories.test.js new file mode 100644 index 0000000000..a8bff1d194 --- /dev/null +++ b/src/ui/Accordion/Accordion.stories.test.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { Default } from './Accordion.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders correctly and fires keyDown Enter events', () => { + const { getByText, getAllByText } = render(); + + Default.args.panels.forEach((panel) => { + expect(getByText(panel.title)).toBeInTheDocument(); + }); + + expect(getAllByText(Default.args.panels[0].content)).toHaveLength(3); + fireEvent.keyDown(getByText(Default.args.panels[0].title), { + key: 'Enter', + code: 'Enter', + keyCode: 13, + charCode: 13, + }); + + fireEvent.keyDown(getByText(Default.args.panels[0].title), { + key: 'Enter', + code: 'Enter', + keyCode: 13, + charCode: 13, + }); + }); + + it('renders correctly and fires keyDown A event', () => { + const { getByText, getAllByText } = render( + , + ); + + Default.args.panels.forEach((panel) => { + expect(getByText(panel.title)).toBeInTheDocument(); + }); + + expect(getAllByText(Default.args.panels[0].content)).toHaveLength(3); + fireEvent.keyDown(getByText(Default.args.panels[0].title), { + key: 'A', + code: 'KeyA', + }); + }); +}); diff --git a/src/ui/Banner/Banner.test.jsx b/src/ui/Banner/Banner.test.jsx new file mode 100644 index 0000000000..376f9ec570 --- /dev/null +++ b/src/ui/Banner/Banner.test.jsx @@ -0,0 +1,292 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import Banner from './Banner'; +import { sharePage } from './Banner'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Banner', () => { + it('renders without errors', () => { + const { container } = render(); + expect(container).toBeInTheDocument(); + }); + + it('renders the children when image prop is not provided', () => { + const image = 'image-url'; + const properties = {}; + const { getByText } = render( + +
Content
+
, + ); + expect(getByText('Content')).toBeInTheDocument(); + }); + + it('renders the image and children when image prop is provided', () => { + const image = 'image-url'; + const metadata = { + image: { + scales: { + huge: { + download: 'image-url', + }, + }, + }, + }; + const { container, getByText } = render( + +
Content
+
, + ); + const imageElement = container.querySelector('.eea.banner .image'); + expect(imageElement).toBeInTheDocument(); + expect(imageElement.style.backgroundImage).toBe(`url(${image})`); + expect(getByText('Content')).toBeInTheDocument(); + }); + + it('calls the onClick function when an action button is clicked', () => { + const onClick = jest.fn(); + const { getByText } = render( + , + ); + const actionButton = getByText('Action'); + fireEvent.click(actionButton); + expect(onClick).toHaveBeenCalled(); + }); + + it('renders only the gradient and children when image prop is not provided', () => { + const { container, getByText } = render( + +
Content
+
, + ); + const imageElement = container.querySelector('.eea.banner .image'); + expect(imageElement).not.toBeInTheDocument(); + const gradientElement = container.querySelector('.eea.banner .gradient'); + expect(gradientElement).toBeInTheDocument(); + expect(getByText('Content')).toBeInTheDocument(); + }); + + it('calls the onClick handler when the action button is clicked', () => { + const onClick = jest.fn(); + const { getByText } = render( + , + ); + const actionButton = getByText('Action'); + fireEvent.click(actionButton); + expect(onClick).toHaveBeenCalledTimes(1); + }); + + it('renders the content and actions correctly', () => { + const { getByText } = render( + <> + Test Banner Title + Test Banner Subtitle + Test Banner Metadata + + Actions}> +
Content
+
+ , + ); + expect(getByText('Content')).toBeInTheDocument(); + expect(getByText('Actions')).toBeInTheDocument(); + expect(getByText('Test Banner Title')).toBeInTheDocument(); + expect(getByText('Test Banner Subtitle')).toBeInTheDocument(); + expect(getByText('Test Banner Metadata')).toBeInTheDocument(); + }); + + it('renders the content and actions correctly', () => { + const { getByText } = render( + <> + Test Banner Title + Test Banner Subtitle + Test Banner Metadata + + Actions}> +
Content
+
+ , + ); + expect(getByText('Content')).toBeInTheDocument(); + expect(getByText('Actions')).toBeInTheDocument(); + expect(getByText('Test Banner Title')).toBeInTheDocument(); + expect(getByText('Test Banner Subtitle')).toBeInTheDocument(); + expect(getByText('Test Banner Metadata')).toBeInTheDocument(); + }); + + it('renders the content and actions correctly', () => { + const { getByText } = render( + <> + Test Banner Title + Test Banner Subtitle + Test Banner Metadata + + Actions}> +
Content
+
+ , + ); + expect(getByText('Content')).toBeInTheDocument(); + expect(getByText('Actions')).toBeInTheDocument(); + expect(getByText('Test Banner Title')).toBeInTheDocument(); + expect(getByText('Test Banner Subtitle')).toBeInTheDocument(); + expect(getByText('Test Banner Metadata')).toBeInTheDocument(); + }); +}); + +describe('sharePage', () => { + it('should not do anything if an invalid platform is provided', () => { + document.createElement = jest.fn(); + sharePage('https://example.com', 'invalidPlatform'); + expect(document.createElement).not.toHaveBeenCalled(); + }); + + it('should create an anchor element and click it for a valid platform', () => { + const url = 'https://example.com'; + const platform = 'facebook'; + + const mockLink = { + setAttribute: jest.fn(), + click: jest.fn(), + }; + + document.createElement = jest.fn(() => mockLink); + + sharePage(url, platform); + + expect(document.createElement).toHaveBeenCalledWith('a'); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 1, + 'href', + `https://facebook.com/sharer.php?u=${url}`, + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 2, + 'target', + '_blank', + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 3, + 'rel', + 'noreferrer', + ); + expect(mockLink.click).toHaveBeenCalled(); + }); + + it('should create an anchor element and click it for a valid platform', () => { + const url = 'https://example.com'; + const platform = 'twitter'; + + const mockLink = { + setAttribute: jest.fn(), + click: jest.fn(), + }; + + document.createElement = jest.fn(() => mockLink); + + sharePage(url, platform); + + expect(document.createElement).toHaveBeenCalledWith('a'); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 1, + 'href', + `https://www.twitter.com/share?url=${url}`, + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 2, + 'target', + '_blank', + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 3, + 'rel', + 'noreferrer', + ); + expect(mockLink.click).toHaveBeenCalled(); + }); + + it('should create an anchor element and click it for a valid platform', () => { + const url = 'https://example.com'; + const platform = 'linkedin'; + + const mockLink = { + setAttribute: jest.fn(), + click: jest.fn(), + }; + + document.createElement = jest.fn(() => mockLink); + + sharePage(url, platform); + + expect(document.createElement).toHaveBeenCalledWith('a'); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 1, + 'href', + `https://www.linkedin.com/sharing/share-offsite/?url=${url}`, + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 2, + 'target', + '_blank', + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 3, + 'rel', + 'noreferrer', + ); + expect(mockLink.click).toHaveBeenCalled(); + }); + + it('should create an anchor element and click it for a valid platform', () => { + const url = 'https://example.com'; + const platform = 'reddit'; + + const mockLink = { + setAttribute: jest.fn(), + click: jest.fn(), + }; + + document.createElement = jest.fn(() => mockLink); + + sharePage(url, platform); + + expect(document.createElement).toHaveBeenCalledWith('a'); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 1, + 'href', + `https://reddit.com/submit?url=${url}`, + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 2, + 'target', + '_blank', + ); + expect(mockLink.setAttribute).toHaveBeenNthCalledWith( + 3, + 'rel', + 'noreferrer', + ); + expect(mockLink.click).toHaveBeenCalled(); + }); +}); diff --git a/src/ui/CallToAction/CallToAction.stories.test.jsx b/src/ui/CallToAction/CallToAction.stories.test.jsx new file mode 100644 index 0000000000..483226bdaa --- /dev/null +++ b/src/ui/CallToAction/CallToAction.stories.test.jsx @@ -0,0 +1,69 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default, Inverted, Link, Labeled } from './CallToAction.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Link', () => { + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector(`a[href="${Link.args.href}"]`), + ).toBeInTheDocument(); + }); +}); + +describe('Labeled', () => { + it('renders correctly', () => { + const { container, getByText } = render(); + expect( + container.querySelector(`a[href="${Labeled.args.href}"]`), + ).toBeInTheDocument(); + expect(getByText(Labeled.args.label)).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + expect( + container.querySelector(`a[href="${Labeled.args.href}"]`), + ).toBeInTheDocument(); + expect(getByText(Labeled.args.label)).toBeInTheDocument(); + }); +}); + +describe('Inverted', () => { + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector(`a[href="${Inverted.args.href}"]`), + ).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container } = render( + , + ); + expect( + container.querySelector(`a[href="${Inverted.args.href}"]`), + ).toBeInTheDocument(); + }); +}); + +describe('Default', () => { + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector(`a[href="${Default.args.href}"]`), + ).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container } = render( + , + ); + expect( + container.querySelector(`a[href="${Default.args.href}"]`), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Card/Card.stories.test.jsx b/src/ui/Card/Card.stories.test.jsx new file mode 100644 index 0000000000..5f2a737e33 --- /dev/null +++ b/src/ui/Card/Card.stories.test.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { + TeaserCardGrid, + CarouselCards, + FluidGrid, + CardGrid, + Default, +} from './Card.stories'; + +describe('TeaserCardGrid component', () => { + it('renders the teaser card grid with correct number of cards', () => { + const { container } = render(); + const teaserCards = container.querySelectorAll('.column.grid-block-teaser'); + expect(teaserCards.length).toBe(3); + }); + + it('displays the correct title on each card', () => { + const { container } = render(); + const cardTitles = container.querySelectorAll('.content .header a'); + const expectedTitles = [ + "State of Europe's environment", + 'Climate', + 'Economy and resources', + ]; + cardTitles.forEach((titleElement, index) => { + expect(titleElement.textContent).toBe(expectedTitles[index]); + }); + }); +}); + +describe('CarouselCards component', () => { + it('renders the carousel with correct number of cards', () => { + const { container } = render(); + const carouselCards = container.querySelectorAll( + '.cards-carousel .slick-slide:not(.slick-cloned) .content .header', + ); + expect(carouselCards.length).toBe(5); + }); + + it('calls the slickPrev function when the previous arrow is clicked', () => { + const { getByLabelText } = render( + , + ); + const prevArrowButton = getByLabelText('Previous slide'); + fireEvent.click(prevArrowButton); + + const nextArrowButton = getByLabelText('Next slide'); + fireEvent.click(nextArrowButton); + }); +}); + +describe('FluidGrid component', () => { + it('renders fluid grid with correct number of cards', () => { + const { container } = render(); + const fluidGridCards = container.querySelectorAll( + '.fluid-card-row .fluid.card .header', + ); + + expect(fluidGridCards.length).toBe(3); + }); +}); + +describe('CardGrid component', () => { + it('renders the card grid with correct number of cards', () => { + const { container } = render(); + const cardGridCards = container.querySelectorAll( + '.ui.fluid.card .content .header', + ); + expect(cardGridCards.length).toBe(3); + }); +}); + +describe('Default component', () => { + it('renders the default with correct number of cards', () => { + const { container } = render(); + const defaultCards = container.querySelectorAll( + '.ui.card.default .content .header', + ); + expect(defaultCards.length).toBe(1); + }); +}); diff --git a/src/ui/Card/IconCard/IconCard.stories.test.jsx b/src/ui/Card/IconCard/IconCard.stories.test.jsx new file mode 100644 index 0000000000..a7713b835a --- /dev/null +++ b/src/ui/Card/IconCard/IconCard.stories.test.jsx @@ -0,0 +1,64 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { GridIconCard, Default } from './IconCard.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('GridIconCard component', () => { + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + GridIconCard.args.cards.forEach((card) => { + expect(getByText(card.title)).toBeInTheDocument(); + expect( + container.querySelector(`.${card.size}.${card.icon}`), + ).toBeInTheDocument(); + }); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + GridIconCard.args.cards.forEach((card) => { + expect(getByText(card.title)).toBeInTheDocument(); + expect( + container.querySelector(`.${card.size}.${card.icon}`), + ).toBeInTheDocument(); + }); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { container, getByText } = render(); + + expect(getByText(Default.args.title)).toBeInTheDocument(); + expect( + container.querySelector(`.${Default.args.size}.${Default.args.icon}`), + ).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText(Default.args.title)).toBeInTheDocument(); + expect( + container.querySelector(`.${Default.args.size}.${Default.args.icon}`), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Card/RelatedContent/RelatedContent.jsx b/src/ui/Card/RelatedContent/RelatedContent.jsx index aeb6fda7f3..620c5ce672 100644 --- a/src/ui/Card/RelatedContent/RelatedContent.jsx +++ b/src/ui/Card/RelatedContent/RelatedContent.jsx @@ -83,7 +83,7 @@ RelatedContent.Grid = ({ children, ...rest }) => { ))} {rest.showButton && rest.publicationCards.length > 4 && ( - +
diff --git a/src/ui/Card/RelatedContent/RelatedContent.stories.jsx b/src/ui/Card/RelatedContent/RelatedContent.stories.jsx index 4682c9e753..801d9ae4b1 100644 --- a/src/ui/Card/RelatedContent/RelatedContent.stories.jsx +++ b/src/ui/Card/RelatedContent/RelatedContent.stories.jsx @@ -42,14 +42,14 @@ DefaultEven.args = { { tag: '#Publication', description: - 'Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. ', + 'Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat.', image: imageUrl, href: '/#', }, { tag: '#Publication', description: - 'Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. ', + 'Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis. Leo fermentum sollicitudin suspendisse iaculis feugiat. Eget tellus blandit aenean mattis.', image: imageUrl, href: '/#', }, diff --git a/src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx b/src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx new file mode 100644 index 0000000000..c799523291 --- /dev/null +++ b/src/ui/Card/RelatedContent/RelatedContent.stories.test.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + RelatedContentInTab, + DefaultOdd, + DefaultEven, +} from './RelatedContent.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('RelatedContentInTab component', () => { + it('renders corectly', () => { + const { getByText } = render( + , + ); + + RelatedContentInTab.args.panes.forEach((element) => + expect(getByText(element.menuItem)).toBeInTheDocument(), + ); + }); + + it('renders corectly', () => { + render( + , + ); + }); +}); + +describe('DefaultOdd component', () => { + it('renders corectly', () => { + const { getByText, getAllByText } = render( + , + ); + + expect(getAllByText(DefaultOdd.args.publicationCards[0].tag)).toHaveLength( + 3, + ); + expect( + getByText(DefaultOdd.args.publicationCards[0].description), + ).toBeInTheDocument(); + }); +}); + +describe('DefaultEven component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + DefaultEven.args.publicationCards.forEach((element) => { + expect(getByText(element.description)).toBeInTheDocument(); + }); + + expect(getByText(DefaultEven.args.buttonText)).toBeInTheDocument(); + }); + + it('renders corectly without the button', () => { + const { getByText, queryByText } = render( + , + ); + + DefaultEven.args.publicationCards.forEach((element) => { + expect(getByText(element.description)).toBeInTheDocument(); + }); + + expect(queryByText(DefaultEven.args.buttonText)).toBeNull(); + }); +}); diff --git a/src/ui/Confirm/Confirm.stories.test.js b/src/ui/Confirm/Confirm.stories.test.js new file mode 100644 index 0000000000..cf4a4e6215 --- /dev/null +++ b/src/ui/Confirm/Confirm.stories.test.js @@ -0,0 +1,27 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { Default } from './Confirm.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders correctly', () => { + const { container, getByText, queryByText } = render( + , + ); + + expect(getByText('Show Confirmation')).toBeInTheDocument(); + expect(container.querySelector('.ui.primary.button')).toBeInTheDocument(); + + fireEvent.click(container.querySelector('.ui.primary.button')); + expect(getByText(Default.args.confirmHeader)).toBeInTheDocument(); + expect(getByText(Default.args.content)).toBeInTheDocument(); + expect(getByText(Default.args.cancelButton)).toBeInTheDocument(); + expect(getByText(Default.args.confirmButton)).toBeInTheDocument(); + + fireEvent.click(getByText(Default.args.cancelButton)); + expect(queryByText(Default.args.confirmHeader)).toBeNull(); + expect(queryByText(Default.args.content)).toBeNull(); + expect(queryByText(Default.args.cancelButton)).toBeNull(); + expect(queryByText(Default.args.confirmButton)).toBeNull(); + }); +}); diff --git a/src/ui/ContextNavigation/ContextNavigation.stories.test.jsx b/src/ui/ContextNavigation/ContextNavigation.stories.test.jsx new file mode 100644 index 0000000000..ce5de6c35a --- /dev/null +++ b/src/ui/ContextNavigation/ContextNavigation.stories.test.jsx @@ -0,0 +1,170 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default } from './ContextNavigation.stories'; +import '@testing-library/jest-dom/extend-expect'; + +const sidenavItems = [ + { + '@id': 'Gravida', + items: [ + { + '@id': 'Lorem-ipsum-0', + description: '', + items: [], + review_state: null, + title: 'Item 1', + url: '/#', + is_current: true, + }, + { + '@id': 'item-2', + description: '', + items: [], + review_state: null, + title: 'Item 2', + url: '/#', + }, + { + '@id': 'item-3', + description: '', + items: [], + review_state: null, + title: 'Item 3', + url: '/#', + }, + ], + review_state: null, + title: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + url: '/#', + }, + { + '@id': 'Signals-2021', + description: '', + items: [], + review_state: null, + title: 'Signals 2021', + url: '/#', + }, + { + '@id': 'Articles', + description: '', + items: [], + review_state: null, + title: 'Articles', + url: '/#', + }, + { + '@id': 'Infographics', + items: [ + { + '@id': 'Lorem-ipsum-1', + description: '', + items: [], + review_state: null, + title: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.', + url: '/#', + }, + { + '@id': 'Signals-2021-infographics', + description: '', + items: [], + review_state: null, + title: 'Signals 2021', + url: '/#', + }, + { + '@id': 'Articles', + description: '', + items: [ + { + '@id': 'article-1', + description: '', + items: [], + review_state: null, + title: 'Summer 2022: Living in a state of multiple crises', + url: '/#', + is_current: true, + }, + { + '@id': 'article-2', + description: '', + items: [], + review_state: null, + title: + 'Interview — Prosumers and the energy crisis: citizens contributing to Europe’s energy transition', + url: '/#', + }, + ], + review_state: null, + title: 'Articles', + url: '/#', + is_in_path: true, + }, + { + '@id': 'Infographics-overview', + description: '', + items: [], + review_state: null, + title: 'Infographics', + url: '/#', + }, + ], + review_state: null, + title: 'Infographics', + url: '/#', + is_in_path: true, + }, + { + '@id': 'About', + review_state: null, + title: 'About', + items: [], + url: '/#', + is_in_path: true, + is_current: true, + }, +]; + +describe('Default component', () => { + it('renders corectly', () => { + const { container, getByText } = render(); + + expect(getByText('Navigation')).toBeInTheDocument(); + expect(getByText('Navigation')).toHaveClass('context-navigation-header'); + + Default.args.sidenavItems.forEach((item) => { + expect(container.querySelector(`#${item['@id']}`).textContent).toMatch( + item.title, + ); + item.items.forEach((subitem) => { + expect( + container.querySelector(`#${subitem['@id']}`).textContent, + ).toMatch(subitem.title); + }); + }); + }); + + it('renders corectly', () => { + const { container, getByText, queryByText } = render( + , + ); + + expect(queryByText('Navigation')).toBeNull(); + expect(getByText('Test Header')).toBeInTheDocument(); + + Default.args.sidenavItems.forEach((item) => { + expect(container.querySelector(`#${item['@id']}`).textContent).toMatch( + item.title, + ); + item.items.forEach((subitem) => { + expect( + container.querySelector(`#${subitem['@id']}`).textContent, + ).toMatch(subitem.title); + }); + }); + }); +}); diff --git a/src/ui/Divider/Divider.stories.test.jsx b/src/ui/Divider/Divider.stories.test.jsx new file mode 100644 index 0000000000..79b92ae122 --- /dev/null +++ b/src/ui/Divider/Divider.stories.test.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { DividerWithContent, Default } from './Divider.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('DividerWithContent component', () => { + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText('Divider Content')).toBeInTheDocument(); + expect(container.querySelector('.ui.container p')).toBeInTheDocument(); + expect(container.querySelector('.ui.divider')).toBeInTheDocument(); + }); + + it('renders correctly with className', () => { + const { container, getByText } = render( + , + ); + + expect(getByText('Divider Content')).toBeInTheDocument(); + expect(container.querySelector('.ui.container p')).toBeInTheDocument(); + expect(container.querySelector('.ui.divider.primary')).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { container } = render(); + + expect(container.querySelector('.ui.container p')).toBeInTheDocument(); + expect(container.querySelector('.ui.divider')).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container } = render( + , + ); + + expect(container.querySelector('.ui.container p')).toBeInTheDocument(); + expect(container.querySelector('.ui.divider')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx b/src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx new file mode 100644 index 0000000000..44c4ffe4bf --- /dev/null +++ b/src/ui/DownloadLabeledIcon/DownloadLabeledIcon.stories.test.jsx @@ -0,0 +1,24 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default } from './DownloadLabeledIcon.stories'; +import DownloadLabeledIcon from './DownloadLabeledIcon'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText('Download')).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + Default.args.links.forEach((item) => { + expect(getByText(item.linkName)).toBeInTheDocument(); + }); + expect( + container.querySelectorAll(`.${Default.args.downloadIcon}`), + ).toHaveLength(3); + }); +}); diff --git a/src/ui/Footer/Description.test.jsx b/src/ui/Footer/Description.test.jsx new file mode 100644 index 0000000000..3158334762 --- /dev/null +++ b/src/ui/Footer/Description.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Description from './Description'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Description component', () => { + it('renders corectly with children', () => { + const { getByText } = render(Description Test); + expect(getByText('Description Test')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Footer/Footer.stories.test.js b/src/ui/Footer/Footer.stories.test.js new file mode 100644 index 0000000000..41fb55620f --- /dev/null +++ b/src/ui/Footer/Footer.stories.test.js @@ -0,0 +1,131 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import { Default } from './Footer.stories'; +import Footer from './Footer'; +import '@testing-library/jest-dom/extend-expect'; + +jest.mock('react-lazy-load-image-component', () => { + return { + LazyLoadComponent: ({ children }) => <>{children}, + }; +}); + +describe('Default', () => { + let history; + let observe; + let unobserve; + + beforeEach(() => { + history = createMemoryHistory(); + observe = jest.fn(); + unobserve = jest.fn(); + + window.IntersectionObserver = jest.fn(function () { + this.observe = observe; + this.unobserve = unobserve; + }); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + + + , + ); + + expect(container.querySelector('#footer')).toBeInTheDocument(); + expect(container.querySelector('.footer-wrapper-nobg')).toBeInTheDocument(); + + expect(container.querySelector('.subfooter')).toBeInTheDocument(); + expect(container.querySelector('.site.logo')).toBeInTheDocument(); + expect(container.querySelector('.contact')).toBeInTheDocument(); + expect(container.querySelector('.social')).toBeInTheDocument(); + + expect(container.querySelector('.actions')).toBeInTheDocument(); + expect(container.querySelector('a[href="/privacy"]')).toBeInTheDocument(); + expect(container.querySelector('a[href="/sitemap"]')).toBeInTheDocument(); + expect( + container.querySelector('a[href="https://www.eea.europa.eu/en/login"]'), + ).toBeInTheDocument(); + expect(container.querySelector('.actions')).toBeInTheDocument(); + + expect(container.querySelector('.footer-header')).toBeInTheDocument(); + expect(getByText('Environmental information systems')).toBeInTheDocument(); + + expect(container.querySelector('.theme-sites')).toBeInTheDocument(); + Default.args.sites.map((site) => + expect( + container.querySelector(`a[href="${site.url}"] img[src="${site.src}"]`), + ).toBeInTheDocument(), + ); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + +
+ +
SubFooter test
+
+ {Default.args.header} + +
Sites test
+
+ +
+
, + ); + + expect(container.querySelector('#footer')).toBeInTheDocument(); + expect(container.querySelector('.footer-wrapper-nobg')).toBeInTheDocument(); + + expect(container.querySelector('.actions')).toBeInTheDocument(); + expect(container.querySelector('a[href="/privacy"]')).toBeInTheDocument(); + expect(container.querySelector('a[href="/sitemap"]')).toBeInTheDocument(); + expect( + container.querySelector('a[href="https://www.eea.europa.eu/en/login"]'), + ).toBeInTheDocument(); + expect(container.querySelector('.actions')).toBeInTheDocument(); + + expect(container.querySelector('.footer-header')).toBeInTheDocument(); + expect(getByText('Environmental information systems')).toBeInTheDocument(); + + expect(getByText('Sites test')).toBeInTheDocument(); + expect(getByText('SubFooter test')).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + +
+ + {Default.args.header} + + +
Actions test
+
+
+
, + ); + + expect(container.querySelector('#footer')).toBeInTheDocument(); + expect(container.querySelector('.footer-wrapper-nobg')).toBeInTheDocument(); + + expect(container.querySelector('.footer-header')).toBeInTheDocument(); + expect(getByText('Environmental information systems')).toBeInTheDocument(); + + expect(getByText('Actions test')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Footer/Social.test.jsx b/src/ui/Footer/Social.test.jsx new file mode 100644 index 0000000000..6905095fd2 --- /dev/null +++ b/src/ui/Footer/Social.test.jsx @@ -0,0 +1,11 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import Social from './Social'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Social component', () => { + it('renders corectly with children', () => { + const { getByText } = render(Social Test); + expect(getByText('Social Test')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Form/Button/Button.stories.test.jsx b/src/ui/Form/Button/Button.stories.test.jsx new file mode 100644 index 0000000000..2d6733c6e8 --- /dev/null +++ b/src/ui/Form/Button/Button.stories.test.jsx @@ -0,0 +1,55 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + Text, + Labeled, + Inverted, + Secondary, + Primary, + Default, +} from './Button.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Text component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Text.args.label)).toBeInTheDocument(); + }); +}); + +describe('Labeled component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Labeled.args.label)).toBeInTheDocument(); + }); +}); + +describe('Inverted component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Inverted.args.button1)).toBeInTheDocument(); + expect(getByText(Inverted.args.button2)).toBeInTheDocument(); + expect(getByText(Inverted.args.button3)).toBeInTheDocument(); + }); +}); + +describe('Secondary component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Secondary.args.label)).toBeInTheDocument(); + }); +}); + +describe('Primary component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Primary.args.label)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + expect(getByText(Default.args.label)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Form/Checkbox.stories.test.js b/src/ui/Form/Checkbox.stories.test.js new file mode 100644 index 0000000000..70763b9f0f --- /dev/null +++ b/src/ui/Form/Checkbox.stories.test.js @@ -0,0 +1,79 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { + single as Single, + optional as Optional, + invalid as Invalid, +} from './Checkbox.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Single', () => { + it('renders correctly', () => { + const { container, getByText, queryByText } = render( + , + ); + expect(getByText(Single.args.label)).toBeInTheDocument(); + expect(queryByText(Single.args.requiredText)).toEqual(null); + + fireEvent.click(container.querySelector('#field4')); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + expect(getByText(Single.args.label)).toBeInTheDocument(); + expect(getByText(Single.args.requiredText)).toBeInTheDocument(); + + fireEvent.click(container.querySelector('#field4')); + }); +}); + +describe('Optional', () => { + it('renders correctly', () => { + const { container, getByText, queryByText } = render( + , + ); + expect(getByText(Optional.args.label)).toBeInTheDocument(); + expect(queryByText(Optional.args.requiredText)).toEqual(null); + + fireEvent.click(container.querySelector('#field1')); + fireEvent.click(container.querySelector('#field2')); + fireEvent.click(container.querySelector('#field3')); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + expect(getByText(Optional.args.label)).toBeInTheDocument(); + expect(getByText(Optional.args.requiredText)).toBeInTheDocument(); + + fireEvent.click(container.querySelector('#field1')); + fireEvent.click(container.querySelector('#field2')); + fireEvent.click(container.querySelector('#field3')); + }); +}); + +describe('Invalid', () => { + it('renders correctly', () => { + const { container, getByText } = render(); + expect(getByText(Invalid.args.label)).toBeInTheDocument(); + + fireEvent.click(container.querySelector('#field1')); + fireEvent.click(container.querySelector('#field2')); + fireEvent.click(container.querySelector('#field3')); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + expect(getByText(Invalid.args.label)).toBeInTheDocument(); + expect(getByText(Invalid.args.requiredText)).toBeInTheDocument(); + + fireEvent.click(container.querySelector('#field1')); + fireEvent.click(container.querySelector('#field2')); + fireEvent.click(container.querySelector('#field3')); + }); +}); diff --git a/src/ui/Form/Dropdown.stories.test.js b/src/ui/Form/Dropdown.stories.test.js new file mode 100644 index 0000000000..3741df45ce --- /dev/null +++ b/src/ui/Form/Dropdown.stories.test.js @@ -0,0 +1,24 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { ErrorDropdown, Default } from './Dropdown.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('ErrorDropdown component', () => { + it('renders correctly', () => { + const { getByText } = render(); + ErrorDropdown.args.options.forEach((item) => { + expect(getByText(item.value)).toBeInTheDocument(); + }); + expect(getByText(ErrorDropdown.args.placeholder)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { getByText } = render(); + Default.args.options.forEach((item) => { + expect(getByText(item.value)).toBeInTheDocument(); + }); + expect(getByText(Default.args.placeholder)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Form/Radio.stories.test.js b/src/ui/Form/Radio.stories.test.js new file mode 100644 index 0000000000..3dde154ec3 --- /dev/null +++ b/src/ui/Form/Radio.stories.test.js @@ -0,0 +1,55 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { Default, invalid as Invalid, BinaryRadio } from './Radio.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('BinaryRadio component', () => { + it('renders corectly', () => { + const { container, getByText, queryByText } = render( + , + ); + + expect(getByText(BinaryRadio.args.label)).toBeInTheDocument(); + expect(queryByText(BinaryRadio.args.requiredText)).toEqual(null); + + fireEvent.click(container.querySelector('#radio-yes')); + }); + + it('renders corectly', () => { + const { getByText } = render( + , + ); + + expect(getByText(BinaryRadio.args.label)).toBeInTheDocument(); + expect(getByText(BinaryRadio.args.requiredText)).toBeInTheDocument(); + }); +}); + +describe('Invalid component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(Invalid.args.label)).toBeInTheDocument(); + expect(getByText(Invalid.args.requiredText)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(Default.args.label)).toBeInTheDocument(); + expect(getByText(Default.args.requiredText)).toBeInTheDocument(); + }); + + it('renders corectly', () => { + const { container, getByText, queryByText } = render( + , + ); + + expect(getByText(Default.args.label)).toBeInTheDocument(); + expect(queryByText(Default.args.requiredText)).toEqual(null); + + fireEvent.click(container.querySelector('#field1')); + }); +}); diff --git a/src/ui/Form/Textarea.stories.test.js b/src/ui/Form/Textarea.stories.test.js new file mode 100644 index 0000000000..ab4f64525b --- /dev/null +++ b/src/ui/Form/Textarea.stories.test.js @@ -0,0 +1,41 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { ErrorTextArea, LabeledTextArea, Default } from './Textarea.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('ErrorTextArea component', () => { + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText(ErrorTextArea.args.label)).toBeInTheDocument(); + expect(getByText('This is a mandatory field')).toBeInTheDocument(); + expect( + container.querySelector('textarea[placeholder="Type here..."]'), + ).toBeInTheDocument(); + }); +}); + +describe('LabeledTextArea component', () => { + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText(LabeledTextArea.args.label)).toBeInTheDocument(); + expect( + container.querySelector('textarea[placeholder="Type here..."]'), + ).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { container } = render(); + + expect( + container.querySelector('textarea[placeholder="Type here..."]'), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Form/input.stories.test.js b/src/ui/Form/input.stories.test.js new file mode 100644 index 0000000000..a83fa99350 --- /dev/null +++ b/src/ui/Form/input.stories.test.js @@ -0,0 +1,52 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + Default, + StandardInput, + DisabledInput, + LoadingInput, + ErrorInput, +} from './Input.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('ErrorInput component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(ErrorInput.args.label)).toBeInTheDocument(); + }); +}); + +describe('LoadingInput component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(LoadingInput.args.label)).toBeInTheDocument(); + }); +}); + +describe('DisabledInput component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(DisabledInput.args.label)).toBeInTheDocument(); + }); +}); + +describe('StandardInput component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(StandardInput.args.label)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders corectly', () => { + const { container } = render(); + + expect( + container.querySelector('input#temp-id[placeholder="Placeholder"]'), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Grid/ComponentGrid.stories.test.js b/src/ui/Grid/ComponentGrid.stories.test.js new file mode 100644 index 0000000000..57eae93455 --- /dev/null +++ b/src/ui/Grid/ComponentGrid.stories.test.js @@ -0,0 +1,21 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { GridExamples, Basic12 } from './ComponentGrid.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('GridExamples component', () => { + it('renders corectly', () => { + const { getAllByText } = render(); + + expect(getAllByText('12/2')).toHaveLength(3); + expect(getAllByText('12/3')).toHaveLength(3); + expect(getAllByText('12/4')).toHaveLength(6); + expect(getAllByText('12/5')).toHaveLength(5); + }); +}); + +describe('Basic12 component', () => { + it('renders corectly', () => { + render(); + }); +}); diff --git a/src/ui/Header/Header.stories.test.js b/src/ui/Header/Header.stories.test.js new file mode 100644 index 0000000000..b45e7ae544 --- /dev/null +++ b/src/ui/Header/Header.stories.test.js @@ -0,0 +1,158 @@ +import React from 'react'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import { render, fireEvent, act } from '@testing-library/react'; +import { Default } from './Header.stories'; +import '@testing-library/jest-dom/extend-expect'; + +global.ResizeObserver = require('resize-observer-polyfill'); + +const history = createMemoryHistory(); + +const links = [ + { title: 'EEA Main Portal', href: '/#portal' }, + { title: 'Biodiversity Information System for Europe', href: '/#bise' }, + { title: 'Forest Information System for Europe', href: '/#Fise' }, + { title: 'Marine Water Information System for Europe', href: '/#marine' }, + { title: 'Fresh Water Information System for Europe', href: '/#freshwater' }, +]; + +const languages = [ + { name: 'Български', code: 'bg' }, + { name: 'čeština', code: 'cs' }, + { name: 'Hrvatski', code: 'hr' }, + { name: 'dansk', code: 'da' }, + { name: 'Nederlands', code: 'nl' }, + { name: 'ελληνικά', code: 'el' }, + { name: 'English', code: 'en' }, + { name: 'eesti', code: 'et' }, + { name: 'Suomi', code: 'fi' }, + { name: 'Français', code: 'fr' }, + { name: 'Deutsch', code: 'de' }, + { name: 'magyar', code: 'hu' }, + { name: 'Íslenska', code: 'is' }, + { name: 'italiano', code: 'it' }, + { name: 'Latviešu', code: 'lv' }, + { name: 'lietuvių', code: 'lt' }, + { name: 'Malti', code: 'mt' }, + { name: 'Norsk', code: 'no' }, + { name: 'polski', code: 'pl' }, + { name: 'Português', code: 'pt' }, + { name: 'Română', code: 'ro' }, + { name: 'slovenčina', code: 'sk' }, + { name: 'Slovenščina', code: 'sl' }, + { name: 'Español', code: 'es' }, + { name: 'Svenska', code: 'sv' }, + { name: 'Türkçe', code: 'tr' }, +]; + +const menuItems = [ + { + '@id': 'Topics', + items: [ + { + '@id': 'At-a-glance', + description: '', + items: [ + { + '@id': 'State-of-Europe’s-environment', + description: '', + items: [], + review_state: null, + title: 'State of Europe’s environment', + url: '/#', + }, + { + '@id': 'Climate', + description: '', + items: [], + review_state: null, + title: 'Climate', + url: '/#', + }, + { + '@id': 'Economy-and-resources', + description: '', + items: [], + review_state: null, + title: 'Economy and resources', + url: '/#', + }, + { + '@id': 'Health', + description: '', + items: [], + review_state: null, + title: 'Health', + url: '/#', + }, + { + '@id': 'Nature', + description: '', + items: [], + review_state: null, + title: 'Nature', + url: '/#', + }, + { + '@id': 'Sustainability', + description: '', + items: [], + review_state: null, + title: 'Sustainability', + url: '/#', + }, + ], + review_state: null, + title: 'At a glance', + url: '/#', + }, + ], + review_state: null, + title: 'Topics', + url: '/#', + }, +]; + +describe('Default component', () => { + const args = { + linksMenuTitle: 'Environmental information systems', + tabletLinksMenuTitle: 'EEA information systems', + mobileLinksMenuTitle: 'EEA information systems', + hasLanguageDropdown: true, + links, + languages, + menuItems, + transparency: false, + inverted: false, + }; + + it('renders the default with correct number of cards', () => { + const { container, getByText } = render( + + + , + ); + const dropdown = container.querySelector('.official-union .content'); + fireEvent.click(dropdown); + act(() => { + fireEvent(window, new Event('resize')); + }); + expect(getByText('EEA Main Portal')).toBeInTheDocument(); + expect( + getByText('Biodiversity Information System for Europe'), + ).toBeInTheDocument(); + expect( + getByText('Forest Information System for Europe'), + ).toBeInTheDocument(); + expect( + getByText('Marine Water Information System for Europe'), + ).toBeInTheDocument(); + expect( + getByText('Fresh Water Information System for Europe'), + ).toBeInTheDocument(); + + fireEvent.click(container.querySelector('a[href="/#bise"]')); + fireEvent.click(container.querySelector('.language-link')); + }); +}); diff --git a/src/ui/Header/Header.test.jsx b/src/ui/Header/Header.test.jsx new file mode 100644 index 0000000000..2c75e03722 --- /dev/null +++ b/src/ui/Header/Header.test.jsx @@ -0,0 +1,293 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import Header from './Header'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Header component', () => { + let history; + + beforeEach(() => { + history = createMemoryHistory(); + }); + + it('renders without crashing', () => { + render(
); + }); + + it('renders children correctly', () => { + render(
Test Children
); + expect(screen.getByText('Test Children')).toBeInTheDocument(); + }); + + it('renders without crashing', () => { + render( +
+ + +

Test

+
+ + +
Language Switcher
+
+
+
+ + item.title !== 'Home' && ( + { + e.preventDefault(); + onClick(e, item); + }} + > + {item.title} + + ) + } + renderMenuItem={(item, options, props) => { + return ( + + {props?.iconPosition !== 'right' && props?.children} + {item.nav_title || item.title} + {props?.iconPosition === 'right' && props?.children} + + ); + }} + /> +
, + ); + }); + + it('renders without crashing', () => { + render( +
+ + + +
No Language Switcher
+
+
+
+ + item.title !== 'Home' && ( + { + e.preventDefault(); + onClick(e, item); + }} + > + {item.title} + + ) + } + renderMenuItem={(item, options, props) => { + return ( + + {props?.iconPosition !== 'right' && props?.children} + {item.nav_title || item.title} + {props?.iconPosition === 'right' && props?.children} + + ); + }} + /> +
, + ); + }); + + it('renders without crashing', () => { + const { getByText, getAllByText, container } = render( + +
+ + + +
No Language Switcher
+
+
+
+ + item.title !== 'Home' && ( + { + e.preventDefault(); + onClick(e, item); + }} + > + {item.title} + + ) + } + renderMenuItem={(item, options, props) => { + return ( + + {props?.iconPosition !== 'right' && props?.children} + {item.nav_title || item.title} + {props?.iconPosition === 'right' && props?.children} + + ); + }} + /> +
+
, + ); + const menuItemsWithInternalUrl = getAllByText('Test Click 2'); + const menuItemsWithExternalUrl = getAllByText('Test Click 3'); + const menuItemsWithCountries = getAllByText('Countries'); + const menuItemsWithTopics = getAllByText('Topics'); + + fireEvent.click(getByText('Test Click')); + fireEvent.click(menuItemsWithInternalUrl[0]); + fireEvent.click(container.querySelector('.search-action')); + fireEvent.click(menuItemsWithExternalUrl[0]); + fireEvent.click(menuItemsWithCountries[0]); + fireEvent.click(menuItemsWithTopics[0]); + fireEvent.keyDown(getByText('No Language Switcher'), { + key: 'Enter', + code: 'Enter', + }); + }); +}); diff --git a/src/ui/Header/HeaderSearchPopUp.test.js b/src/ui/Header/HeaderSearchPopUp.test.js new file mode 100644 index 0000000000..df08390144 --- /dev/null +++ b/src/ui/Header/HeaderSearchPopUp.test.js @@ -0,0 +1,113 @@ +import React from 'react'; +import { render, screen, fireEvent } from '@testing-library/react'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import HeaderSearchPopUp from './HeaderSearchPopUp'; +import '@testing-library/jest-dom/extend-expect'; + +describe('HeaderSearchPopUp', () => { + let history; + const mockOnClose = jest.fn(); + const sampleHeaderSearchBox = [ + { + path: '/search', + buttonTitle: 'Advanced Search', + buttonUrl: '/advanced-search', + description: 'Sample description', + placeholder: 'Search', + searchSuggestions: { + suggestionsTitle: 'Suggestions Title', + suggestions: ['suggestion 1', 'suggestion 2', 'suggestion 3'], + maxToShow: 3, + }, + isDefault: true, + }, + ]; + + const sampleHeaderSearchBoxWithMatchpath = [ + { + matchpath: '/search', + buttonTitle: 'Advanced Search', + buttonUrl: undefined, + description: 'Sample description', + placeholder: 'Search', + searchSuggestions: { + suggestionsTitle: 'Suggestions Title', + suggestions: ['suggestion 1', 'suggestion 2', 'suggestion 3'], + maxToShow: 3, + }, + isDefault: true, + }, + ]; + + beforeEach(() => { + history = createMemoryHistory(); + }); + + afterEach(() => { + jest.clearAllMocks(); + }); + + it('should render HeaderSearchPopUp', () => { + render( + + + , + ); + expect(screen.getByPlaceholderText('Search')).toBeInTheDocument(); + }); + + it('should update search text on change', () => { + render( + + + , + ); + const input = screen.getByPlaceholderText('Search'); + fireEvent.change(input, { target: { value: 'New text' } }); + expect(input.value).toBe('New text'); + }); + + it('should submit the form with search text', () => { + window.searchContext = { resetSearch: jest.fn() }; + + const { container } = render( + + + , + ); + const input = screen.getByPlaceholderText('Search'); + fireEvent.change(input, { target: { value: 'Search text' } }); + fireEvent.submit(container.querySelector('form')); + expect(history.location.pathname).toBe('/search'); + expect(history.location.search).toBe('?q=Search text'); + }); + + it('should navigate to the suggestion when a suggestion is clicked', () => { + window.searchContext = { resetSearch: jest.fn() }; + + render( + + + , + ); + fireEvent.click(screen.getByText('suggestion 1')); + expect(history.location.pathname).toBe('/'); + expect(history.location.search).toBe('?q=suggestion 1'); + }); +}); diff --git a/src/ui/Hero/Hero.stories.test.jsx b/src/ui/Hero/Hero.stories.test.jsx new file mode 100644 index 0000000000..6cfa0a6a3f --- /dev/null +++ b/src/ui/Hero/Hero.stories.test.jsx @@ -0,0 +1,67 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Playground, Default } from './Hero.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Playground component', () => { + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText(Playground.args.text)).toBeInTheDocument(); + expect(getByText(Playground.args.buttonLabel)).toBeInTheDocument(); + expect(getByText(Playground.args.buttonLabel)).toHaveClass( + 'ui inverted button primary', + ); + expect(container.querySelector('.eea.copyright')).toBeInTheDocument(); + expect(getByText(Playground.args.copyrightPrefix)).toHaveClass( + 'icon-prefix', + ); + expect( + container.querySelector(`.icon.${Playground.args.copyrightIcon}`), + ).toBeInTheDocument(); + expect(getByText(Playground.args.copyright)).toHaveClass('icon-content'); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { container, getByText } = render(); + + expect(getByText(Default.args.text)).toBeInTheDocument(); + expect(getByText(Default.args.buttonLabel)).toBeInTheDocument(); + expect(getByText(Default.args.buttonLabel)).toHaveClass( + 'ui inverted button primary', + ); + expect(container.querySelector('.eea.copyright')).toBeInTheDocument(); + expect(getByText(Default.args.copyrightPrefix)).toHaveClass('icon-prefix'); + expect( + container.querySelector(`.icon.${Default.args.copyrightIcon}`), + ).toBeInTheDocument(); + expect(getByText(Default.args.copyright)).toHaveClass('icon-content'); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + + expect(getByText(Default.args.text)).toBeInTheDocument(); + expect(getByText(Default.args.buttonLabel)).toBeInTheDocument(); + expect(getByText(Default.args.buttonLabel)).toHaveClass( + 'ui inverted button primary', + ); + expect(container.querySelector('.eea.copyright')).toBeInTheDocument(); + expect(getByText(Default.args.copyrightPrefix)).toHaveClass('icon-prefix'); + expect( + container.querySelector(`.icon.${Default.args.copyrightIcon}`), + ).toBeInTheDocument(); + expect(getByText(Default.args.copyright)).toHaveClass('icon-content'); + }); +}); diff --git a/src/ui/InpageNavigation/InpageNavigation.stories.test.jsx b/src/ui/InpageNavigation/InpageNavigation.stories.test.jsx new file mode 100644 index 0000000000..9bfbfe1763 --- /dev/null +++ b/src/ui/InpageNavigation/InpageNavigation.stories.test.jsx @@ -0,0 +1,10 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default } from './InpageNavigation.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders correctly', () => { + render(); + }); +}); diff --git a/src/ui/InpageNavigation/InpageNavigation.test.jsx b/src/ui/InpageNavigation/InpageNavigation.test.jsx new file mode 100644 index 0000000000..260bd6bc3b --- /dev/null +++ b/src/ui/InpageNavigation/InpageNavigation.test.jsx @@ -0,0 +1,87 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import InpageNavigation from './InpageNavigation'; +import '@testing-library/jest-dom/extend-expect'; + +describe('InpageNavigation', () => { + let scrollToMock; + + beforeEach(() => { + scrollToMock = jest.fn(); + global.window.scrollTo = scrollToMock; + }); + + afterEach(() => { + scrollToMock.mockClear(); + delete global.window.scrollTo; + }); + + it('should scroll to top on button click', () => { + const { getByTitle } = render(); + const button = getByTitle('Go to top'); + + fireEvent.click(button); + + expect(scrollToMock).toHaveBeenCalledWith({ + top: 0, + behavior: 'smooth', + }); + }); + + it('should hide the button when scroll position is less than or equal to 50', () => { + Object.defineProperty(window, 'scrollY', { value: 30 }); + + const { getByTitle } = render(); + const button = getByTitle('Go to top'); + + expect(button).toHaveClass('hidden'); + }); + + it('should render the correct button content for different screen sizes', () => { + const { container } = render(); + const mobileTabletOnlyContent = container.querySelector( + '.mobile.tablet.only', + ); + const tabletOrLowerHiddenContent = container.querySelector( + '.tablet.or.lower.hidden', + ); + + expect(mobileTabletOnlyContent).toBeInTheDocument(); + expect(tabletOrLowerHiddenContent).toBeInTheDocument(); + expect(container.querySelector('.text')).toBeInTheDocument(); + }); + + it('should scroll to top on button click', () => { + const { getByTitle } = render(); + const button = getByTitle('Go to top'); + + fireEvent.click(button); + + expect(scrollToMock).toHaveBeenCalledWith({ + top: 0, + behavior: 'smooth', + }); + }); + + it('should show the button when scroll position is greater than 50', () => { + Object.defineProperty(window, 'scrollY', { value: 100 }); + + const { getByTitle } = render(); + const button = getByTitle('Go to top'); + + expect(button).toHaveStyle('display: inline-block;'); + }); + + it('should update button visibility based on scroll position', () => { + const { getByTitle } = render(); + const button = getByTitle('Go to top'); + + Object.defineProperty(window, 'scrollY', { value: 100 }); + fireEvent.scroll(window); + + expect(button).toHaveStyle('display: inline-block;'); + + Object.defineProperty(window, 'scrollY', { value: 30 }); + fireEvent.scroll(window); + }); +}); diff --git a/src/ui/Item/Item.stories.test.js b/src/ui/Item/Item.stories.test.js new file mode 100644 index 0000000000..cbc54cf636 --- /dev/null +++ b/src/ui/Item/Item.stories.test.js @@ -0,0 +1,39 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { DefaultGroup, DefaultItem, Default } from './Item.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('DefaultGroup Component', () => { + it('renders correctly', () => { + const { container } = render(); + DefaultGroup.args.items.forEach((element) => { + expect( + container.querySelector(`img[src="${element.image}"]`), + ).toBeInTheDocument(); + }); + expect(container.querySelector('.header')).toBeInTheDocument(); + expect(container.querySelector('.meta')).toBeInTheDocument(); + expect(container.querySelector('.description')).toBeInTheDocument(); + expect(container.querySelector('.extra')).toBeInTheDocument(); + }); +}); + +describe('DefaultItem Component', () => { + it('renders correclty', () => { + const { container } = render(); + expect(container.querySelector('.header')).toBeInTheDocument(); + expect(container.querySelector('.meta')).toBeInTheDocument(); + expect(container.querySelector('.description')).toBeInTheDocument(); + expect(container.querySelector('.extra')).toBeInTheDocument(); + }); +}); + +describe('Default Component', () => { + it('renders correclty', () => { + const { container } = render(); + expect(container.querySelector('.header')).toBeInTheDocument(); + expect(container.querySelector('.meta')).toBeInTheDocument(); + expect(container.querySelector('.description')).toBeInTheDocument(); + expect(container.querySelector('.extra')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Item/ItemGroupWithIcons.stories.test.js b/src/ui/Item/ItemGroupWithIcons.stories.test.js new file mode 100644 index 0000000000..bb77bab255 --- /dev/null +++ b/src/ui/Item/ItemGroupWithIcons.stories.test.js @@ -0,0 +1,119 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + FlexGroup, + DefaultGroup, + DefaultItem, +} from './ItemGroupWithIcons.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('FlexGroup component', () => { + it('renders correctly', () => { + const { container, queryAllByText } = render( + , + ); + + expect( + container.querySelector('.ui.unstackable.items.row.flex-items-wrapper'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="globe-eco.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="sustainable.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="data-analytics.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="network.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="globe-eco.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="knowledge.svg"]'), + ).toBeInTheDocument(); + + FlexGroup.args.Items.forEach((item) => { + expect(queryAllByText(item.description)).not.toBeNull(); + }); + }); +}); + +describe('DefaultGroup component', () => { + it('renders correctly', () => { + const { container, queryAllByText } = render( + , + ); + + expect( + container.querySelector('.ui.unstackable.items.row'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="globe-eco.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="sustainable.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="data-analytics.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="network.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="globe-eco.svg"]'), + ).toBeInTheDocument(); + expect( + container.querySelector('img[src="knowledge.svg"]'), + ).toBeInTheDocument(); + + DefaultGroup.args.ColumnLeft.forEach((item) => { + expect(queryAllByText(item.description)).not.toBeNull(); + }); + DefaultGroup.args.ColumnRight.forEach((item) => { + expect(queryAllByText(item.description)).not.toBeNull(); + }); + }); +}); + +describe('DefaultGroup component', () => { + it('renders correctly', () => { + const { container, queryAllByText } = render( + , + ); + + expect( + container.querySelector('.icon.medium.ri-earth-line.secondary'), + ).toBeInTheDocument(); + expect( + container.querySelector('.icon.medium.ri-leaf-line.secondary'), + ).toBeInTheDocument(); + expect( + container.querySelector('.icon.medium.ri-pie-chart-line.secondary'), + ).toBeInTheDocument(); + expect( + container.querySelector('.icon.medium.ri-pin-distance-line.secondary'), + ).toBeInTheDocument(); + expect( + container.querySelector('.icon.medium.ri-line-chart-line.secondary'), + ).toBeInTheDocument(); + + DefaultGroup.args.ColumnLeft.forEach((item) => { + expect(queryAllByText(item.description)).not.toBeNull(); + }); + DefaultGroup.args.ColumnRight.forEach((item) => { + expect(queryAllByText(item.description)).not.toBeNull(); + }); + }); +}); + +describe('DefaultItem component', () => { + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector('.ui.unstackable.items.row'), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Label/Label.stories.test.js b/src/ui/Label/Label.stories.test.js new file mode 100644 index 0000000000..9cb2ab346f --- /dev/null +++ b/src/ui/Label/Label.stories.test.js @@ -0,0 +1,76 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default, Basic, Corner, Ribbon } from './Label.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Basic component', () => { + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText(Basic.args.content)).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText(Basic.args.content)).toBeInTheDocument(); + }); +}); + +describe('Corner component', () => { + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector( + 'img[src="https://react.semantic-ui.com/images/wireframe/image.png"]', + ), + ).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container } = render(); + expect( + container.querySelector( + 'img[src="https://react.semantic-ui.com/images/wireframe/image.png"]', + ), + ).toBeInTheDocument(); + }); +}); + +describe('Ribbon component', () => { + it('renders correctly', () => { + const { container, getByText } = render(); + expect(getByText('Ribbon Label')).toBeInTheDocument(); + expect(container.querySelector('.ribbon.label')).toBeInTheDocument(); + expect( + container.querySelector( + 'img[src="https://react.semantic-ui.com/images/wireframe/paragraph.png"]', + ), + ).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { container, getByText } = render( + , + ); + expect(getByText('Ribbon Label')).toBeInTheDocument(); + expect(container.querySelector('.ribbon.label')).toBeInTheDocument(); + expect( + container.querySelector( + 'img[src="https://react.semantic-ui.com/images/wireframe/paragraph.png"]', + ), + ).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText(Default.args.content)).toBeInTheDocument(); + }); + + it('renders correctly', () => { + const { getByText } = render( + , + ); + expect(getByText(Default.args.content)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx b/src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx new file mode 100644 index 0000000000..ecc0cd1fc9 --- /dev/null +++ b/src/ui/LabeledIconGroup/LabeledIconGroup.stories.test.jsx @@ -0,0 +1,19 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default } from './LabeledIconGroup.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders corectly', () => { + const { container, getByText } = render(); + + expect(container.querySelector('.ri-share-box-fill')).toBeInTheDocument(); + expect(getByText('Open in new Tab')).toBeInTheDocument(); + + expect(container.querySelector('.ri-download-2-fill')).toBeInTheDocument(); + expect(getByText('Download')).toBeInTheDocument(); + + expect(container.querySelector('.ri-global-line')).toBeInTheDocument(); + expect(getByText('Language')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx b/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx index 3658b80e53..82ad1fb6d7 100644 --- a/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx +++ b/src/ui/LanguageLabeledIcon/LanguageLabeledIcon.jsx @@ -1,5 +1,6 @@ import React, { useState, useContext, createContext } from 'react'; import { Popup } from 'semantic-ui-react'; +import noop from 'lodash/noop'; const LanguageContext = createContext(); @@ -59,7 +60,7 @@ const Dropdown = ({ children, ...rest }) => {
  • context.setLanguage(item.code.toUpperCase())} - onKeyDown={() => context.setHidden(!context.hidden)} + onKeyDown={noop} role="button" tabIndex={0} > @@ -73,7 +74,7 @@ const Dropdown = ({ children, ...rest }) => {
  • context.setLanguage(item.code.toUpperCase())} - onKeyDown={() => context.setHidden(!context.hidden)} + onKeyDown={noop} role="button" tabIndex={0} > diff --git a/src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx b/src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx new file mode 100644 index 0000000000..273998e133 --- /dev/null +++ b/src/ui/LanguageLabeledIcon/LanguangeLabeledIcon.test.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import LanguageLabeledIcon from './LanguageLabeledIcon'; +import '@testing-library/jest-dom/extend-expect'; + +jest.mock('semantic-ui-react', () => { + return { + Popup: ({ trigger, content }) =>
    {content}
    , + }; +}); + +const items = [ + { + code: 'en', + name: 'English', + }, + { + code: 'ro', + name: 'Romania', + }, +]; + +describe('LanguageLabeledIcon component', () => { + it('renders corectly', () => { + render(); + }); + + it('renders languages dropdown', () => { + const { getByText } = render( + <> + + + +

    Test

    +
    +
    + , + ); + + expect(getByText('English')).toBeInTheDocument(); + expect(getByText('Romania')).toBeInTheDocument(); + expect(getByText('Test')).toBeInTheDocument(); + + fireEvent.click(getByText('EN')); + fireEvent.click(getByText('RO')); + }); + + it('renders languages dropdown', () => { + const { getByText } = render( + <> + + + + , + ); + + expect(getByText('EN')).toBeInTheDocument(); + expect(getByText('testIcon')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Loader/Loader.stories.test.jsx b/src/ui/Loader/Loader.stories.test.jsx new file mode 100644 index 0000000000..5721a59070 --- /dev/null +++ b/src/ui/Loader/Loader.stories.test.jsx @@ -0,0 +1,30 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { FullPageLoader, Default } from './Loader.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('FullPageLoader component', () => { + it('renders corectly', () => { + const { container, getByText } = render( + , + ); + + expect(container.querySelector('.dimmer .loader')).toBeInTheDocument(); + expect(getByText(FullPageLoader.args.content)).toBeInTheDocument(); + expect( + container.querySelector( + 'img[src="https://react.semantic-ui.com/images/wireframe/short-paragraph.png"]', + ), + ).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders corectly', () => { + const { container } = render(); + + expect( + container.querySelector(`.${Default.args.size}.active`), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Logo/Logo.stories.test.jsx b/src/ui/Logo/Logo.stories.test.jsx new file mode 100644 index 0000000000..5a16001ebe --- /dev/null +++ b/src/ui/Logo/Logo.stories.test.jsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Logo } from './Logo.stories'; +import { createMemoryHistory } from 'history'; +import { Router } from 'react-router-dom'; +import '@testing-library/jest-dom/extend-expect'; + +describe('FluidGrid component', () => { + let history; + beforeEach(() => { + history = createMemoryHistory(); + }); + it('renders the correct logo', () => { + const { container } = render( + + + , + ); + + expect( + container.querySelector(`a[href="/${Logo.args.url}"]`), + ).toBeInTheDocument(); + }); + + it('renders the correct logo', () => { + const { container } = render( + + + , + ); + + expect( + container.querySelector(`a[href="/https://biodiversity.europa.eu/"]`), + ).toBeInTheDocument(); + }); + + it('renders the correct logo', () => { + const { container } = render( + + + , + ); + + expect( + container.querySelector(`a[href="/https://water.europa.eu/marine"]`), + ).toBeInTheDocument(); + }); + + it('renders the correct logo', () => { + const { container } = render( + + + , + ); + + expect( + container.querySelector(`a[href="/https://forest.eea.europa.eu/"]`), + ).toBeInTheDocument(); + }); + + it('renders the correct logo', () => { + const { container } = render( + + + , + ); + + expect( + container.querySelector(`a[href="/https://water.europa.eu/freshwater"]`), + ).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Media/Image.stories.test.js b/src/ui/Media/Image.stories.test.js new file mode 100644 index 0000000000..5127359ad4 --- /dev/null +++ b/src/ui/Media/Image.stories.test.js @@ -0,0 +1,35 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Playground, Link, Default } from './Image.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Playground component', () => { + it('renders correctly', () => { + const { container } = render(); + + expect( + container.querySelector('img[alt="playground image"]'), + ).toBeInTheDocument(); + }); +}); + +describe('Link component', () => { + it('renders correctly', () => { + const { container } = render(); + + expect( + container.querySelector(`a[href="${Link.args.href}"]`), + ).toBeInTheDocument(); + expect( + container.querySelector('img[alt="link image"]'), + ).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { container } = render(); + + expect(container.querySelector('img[alt="image"]')).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Message/Message.stories.test.js b/src/ui/Message/Message.stories.test.js new file mode 100644 index 0000000000..9c0bbea7e4 --- /dev/null +++ b/src/ui/Message/Message.stories.test.js @@ -0,0 +1,44 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Info, Error, Warning, Success, Default } from './Message.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Info component', () => { + it('renders a Message component', () => { + const { getByText } = render(); + expect(getByText(Info.args.header)).toBeInTheDocument(); + expect(getByText(Info.args.content)).toBeInTheDocument(); + }); +}); + +describe('Error component', () => { + it('renders a Message component', () => { + const { getByText } = render(); + expect(getByText(Error.args.header)).toBeInTheDocument(); + expect(getByText(Error.args.content)).toBeInTheDocument(); + }); +}); + +describe('Warning component', () => { + it('renders a Message component', () => { + const { getByText } = render(); + expect(getByText(Warning.args.header)).toBeInTheDocument(); + expect(getByText(Warning.args.content)).toBeInTheDocument(); + }); +}); + +describe('Success component', () => { + it('renders a Message component', () => { + const { getByText } = render(); + expect(getByText(Success.args.header)).toBeInTheDocument(); + expect(getByText(Success.args.content)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders a Message component', () => { + const { getByText } = render(); + expect(getByText(Default.args.header)).toBeInTheDocument(); + expect(getByText(Default.args.content)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Modal/Modal.stories.test.js b/src/ui/Modal/Modal.stories.test.js new file mode 100644 index 0000000000..6b71da7ed8 --- /dev/null +++ b/src/ui/Modal/Modal.stories.test.js @@ -0,0 +1,45 @@ +import { render, fireEvent } from '@testing-library/react'; +import { Default } from './Modal.stories'; +import { Button } from 'semantic-ui-react'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Default component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText('Show Modal')).toBeInTheDocument(); + fireEvent.click(getByText('Show Modal')); + expect(getByText('Modal Content')).toBeInTheDocument(); + expect(getByText('No')).toBeInTheDocument(); + expect(getByText('Yes')).toBeInTheDocument(); + + fireEvent.click(getByText('No')); + fireEvent.click(getByText('Show Modal')); + // fireEvent.click( + // container.querySelector('button[title="Close modal dialog"]'), + // ); + }); + + it('renders corectly', () => { + const { getByText } = render( + Show Modal} + />, + ); + + expect(getByText('Show Modal')).toBeInTheDocument(); + fireEvent.click(getByText('Show Modal')); + expect(getByText('Modal Content')).toBeInTheDocument(); + expect(getByText('No')).toBeInTheDocument(); + expect(getByText('Yes')).toBeInTheDocument(); + + fireEvent.click(getByText('Yes')); + fireEvent.click(getByText('Show Modal')); + // fireEvent.click( + // container.querySelector('button[title="Close modal dialog"]'), + // ); + }); +}); diff --git a/src/ui/Popup/Popup.test.jsx b/src/ui/Popup/Popup.test.jsx new file mode 100644 index 0000000000..475dee68a4 --- /dev/null +++ b/src/ui/Popup/Popup.test.jsx @@ -0,0 +1,60 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import Popup from './Popup'; +import '@testing-library/jest-dom/extend-expect'; + +jest.mock('@popperjs/core', () => { + const originalModule = jest.requireActual('@popperjs/core'); + + return { + ...originalModule, + createPopper: jest.fn(() => ({ + forceUpdate: jest.fn(), + destroy: jest.fn(), + })), + }; +}); + +describe('Popup', () => { + const MockTrigger = ({ onClick }) => ( + + ); + + it('should render the popup trigger', () => { + const { getByText } = render( + } content="Popup content" />, + ); + expect(getByText('Trigger')).toBeInTheDocument(); + }); + + it('should render the popup trigger', () => { + const { getByText } = render( + } + content="Popup content" + />, + ); + expect(getByText('Trigger')).toBeInTheDocument(); + }); + + it('should open and close the popup when the trigger is clicked', () => { + const { getByText } = render( + } content="Popup content" />, + ); + fireEvent.click(getByText('Trigger')); + expect(getByText('Popup content')).toBeVisible(); + }); + + it('should close the popup when the Escape key is pressed', () => { + const { getByText } = render( + } content="Popup content" />, + ); + fireEvent.click(getByText('Trigger')); + expect(getByText('Popup content')).toBeVisible(); + + fireEvent.keyDown(document.body, { key: 'Enter' }); + fireEvent.keyDown(document.body, { key: 'Escape' }); + }); +}); diff --git a/src/ui/Progress/Progress.stories.test.js b/src/ui/Progress/Progress.stories.test.js new file mode 100644 index 0000000000..7679141b16 --- /dev/null +++ b/src/ui/Progress/Progress.stories.test.js @@ -0,0 +1,30 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Default, ProgressWithValue, CustomColor } from './Progress.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('CustomColor component', () => { + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText(`${CustomColor.args.value}%`)).toBeInTheDocument(); + expect(getByText(`${CustomColor.args.children}`)).toBeInTheDocument(); + }); +}); + +describe('ProgressWithValue component', () => { + it('renders correctly', () => { + const { getByText } = render( + , + ); + expect(getByText(`${ProgressWithValue.args.value}%`)).toBeInTheDocument(); + expect(getByText(`${ProgressWithValue.args.children}`)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders correctly', () => { + const { getByText } = render(); + expect(getByText(`${Default.args.percent}%`)).toBeInTheDocument(); + expect(getByText(`${Default.args.children}`)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Quote/Testimonial/Testimonial.stories.test.jsx b/src/ui/Quote/Testimonial/Testimonial.stories.test.jsx new file mode 100644 index 0000000000..a554c762dc --- /dev/null +++ b/src/ui/Quote/Testimonial/Testimonial.stories.test.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { Inline } from './Testimonial.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Inline component', () => { + it('renders corectly', () => { + const { container, getByText } = render(); + + expect( + container.querySelector(`div[quote="${Inline.args.quote}"]`), + ).toBeInTheDocument(); + expect(getByText(Inline.args.avatartitle)).toBeInTheDocument(); + expect(getByText(Inline.args.avatarinfo)).toBeInTheDocument(); + expect(getByText(Inline.args.title)).toBeInTheDocument(); + expect(getByText(Inline.args.quote)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Statistic/Statistic.stories.test.js b/src/ui/Statistic/Statistic.stories.test.js new file mode 100644 index 0000000000..ba72b5089a --- /dev/null +++ b/src/ui/Statistic/Statistic.stories.test.js @@ -0,0 +1,69 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + Default, + Group, + Custom, + Animation, + AnimationGroup, +} from './Statistic.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('AnimationGroup component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + + expect( + getByText(AnimationGroup.args.elements[0].label), + ).toBeInTheDocument(); + expect( + getByText(AnimationGroup.args.elements[1].label), + ).toBeInTheDocument(); + expect( + getByText(AnimationGroup.args.elements[2].label), + ).toBeInTheDocument(); + }); +}); + +describe('Animation component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + + expect(getByText('Count up label')).toBeInTheDocument(); + expect(getByText('Start')).toBeInTheDocument(); + expect(getByText('Reset')).toBeInTheDocument(); + expect(getByText('Pause/Resume')).toBeInTheDocument(); + }); +}); + +describe('Custom component', () => { + it('renders a button with label', () => { + const { getByText, getAllByText } = render(); + + Custom.args.elements.forEach((element) => { + expect(getByText(element.value)).toBeInTheDocument(); + expect(getByText(element.label)).toBeInTheDocument(); + }); + expect(getAllByText('Text from slate')).toHaveLength(3); + }); +}); + +describe('Group component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + + Group.args.elements.forEach((element) => { + expect(getByText(element.value)).toBeInTheDocument(); + expect(getByText(element.label)).toBeInTheDocument(); + }); + }); +}); + +describe('Default component', () => { + it('renders a button with label', () => { + const { getByText } = render(); + + expect(getByText(Default.args.label)).toBeInTheDocument(); + expect(getByText(Default.args.value)).toBeInTheDocument(); + }); +}); diff --git a/src/ui/Table/Table.stories.test.js b/src/ui/Table/Table.stories.test.js new file mode 100644 index 0000000000..c5bd12c389 --- /dev/null +++ b/src/ui/Table/Table.stories.test.js @@ -0,0 +1,54 @@ +import React from 'react'; +import { render, fireEvent } from '@testing-library/react'; +import { Default, Sortable, Responsive } from './Table.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('Responsive component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + Responsive.args.headers.forEach((element) => { + expect(getByText(element.name)).toBeInTheDocument(); + }); + + Responsive.args.tableData.forEach((element) => { + expect(getByText(element.col1)).toBeInTheDocument(); + expect(getByText(element.col2)).toBeInTheDocument(); + expect(getByText(element.col3)).toBeInTheDocument(); + }); + }); +}); + +describe('Sortable component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + Sortable.args.headers.forEach((element) => { + expect(getByText(element.name)).toBeInTheDocument(); + }); + + Sortable.args.tableData.forEach((element) => { + expect(getByText(element.col1)).toBeInTheDocument(); + expect(getByText(element.col2)).toBeInTheDocument(); + expect(getByText(element.col3)).toBeInTheDocument(); + }); + + fireEvent.click(getByText(Sortable.args.headers[0].name)); + }); +}); + +describe('Default component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + Default.args.headers.forEach((element) => { + expect(getByText(element.name)).toBeInTheDocument(); + }); + + Default.args.tableData.forEach((element) => { + expect(getByText(element.col1)).toBeInTheDocument(); + expect(getByText(element.col2)).toBeInTheDocument(); + expect(getByText(element.col3)).toBeInTheDocument(); + }); + }); +}); diff --git a/src/ui/Timeline/Timeline.stories.test.jsx b/src/ui/Timeline/Timeline.stories.test.jsx new file mode 100644 index 0000000000..d328ba6781 --- /dev/null +++ b/src/ui/Timeline/Timeline.stories.test.jsx @@ -0,0 +1,43 @@ +import React from 'react'; +import { render } from '@testing-library/react'; +import { + Default, + DefaultReversed, + Multiple, + MultipleReversed, +} from './Timeline.stories'; +import '@testing-library/jest-dom/extend-expect'; + +describe('MultipleReversed component', () => { + it('renders corectly', () => { + const { getAllByText } = render( + , + ); + + expect(getAllByText(MultipleReversed.args.items[0].time)).toHaveLength(3); + }); +}); + +describe('Multiple component', () => { + it('renders corectly', () => { + const { getAllByText } = render(); + + expect(getAllByText(Multiple.args.items[0].time)).toHaveLength(3); + }); +}); + +describe('DefaultReversed component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(DefaultReversed.args.time)).toBeInTheDocument(); + }); +}); + +describe('Default component', () => { + it('renders corectly', () => { + const { getByText } = render(); + + expect(getByText(Default.args.time)).toBeInTheDocument(); + }); +});