diff --git a/components/AlgoliaSearch.js b/components/AlgoliaSearch.js index 2eafb6b2446..96a98dcc273 100644 --- a/components/AlgoliaSearch.js +++ b/components/AlgoliaSearch.js @@ -162,6 +162,7 @@ export function SearchButton({ children, indexName = INDEX_NAME, ...props }) { onOpen(indexName); }} {...props} + data-testid="Search-Button" > {typeof children === 'function' ? children({ actionKey }) : children} diff --git a/components/AuthorAvatars.js b/components/AuthorAvatars.js index c3e740ff212..0ce49ba1fc4 100644 --- a/components/AuthorAvatars.js +++ b/components/AuthorAvatars.js @@ -1,15 +1,25 @@ +import React from 'react' export default function AuthorAvatars({ authors = [] }) { return ( authors.map((author, index) => { - let avatar = 0 ? `absolute left-${index * 7} top-0` : `relative mr-${(authors.length - 1) * 7}`} z-${(authors.length - 1 - index) * 10} h-10 w-10 border-2 border-white rounded-full object-cover hover:z-50`} - src={author.photo} - loading="lazy" - /> + let avatar = ( + 0 ? `absolute left-${index * 7} top-0` : `relative mr-${(authors.length - 1) * 7}`} z-${(authors.length - 1 - index) * 10} h-10 w-10 border-2 border-white rounded-full object-cover hover:z-50`} + src={author.photo} + loading="lazy" + data-testid="AuthorAvatars-img" + /> + ); - return author.link ? {avatar} : {avatar} + return author.link ? ( + + {avatar} + + ) : ( + {avatar} + ); }) - ) -} \ No newline at end of file + ); +} diff --git a/components/Feedback.js b/components/Feedback.js index 555ec8424c1..d369b7a9e65 100644 --- a/components/Feedback.js +++ b/components/Feedback.js @@ -50,7 +50,7 @@ export default function Feedback(className = '') {
-
+
Thank you for your feedback!
@@ -71,7 +71,7 @@ export default function Feedback(className = '') {
-
+
Oops! Something went wrong...
diff --git a/components/Figure.js b/components/Figure.js index 35887e0726a..ed5c75dc6db 100644 --- a/components/Figure.js +++ b/components/Figure.js @@ -12,9 +12,9 @@ export default function Figure ({ src, caption, widthClass, className, float, al } return ( -
+
- {alt} + {alt} { caption && ({caption}) }
diff --git a/components/Hero.js b/components/Hero.js index 471441ecb50..b6327942d60 100644 --- a/components/Hero.js +++ b/components/Hero.js @@ -6,7 +6,7 @@ import DemoAnimation from './DemoAnimation' import AnnouncementHero from '../components/campaigns/AnnoucementHero' import Heading from './typography/Heading' import Paragraph from './typography/Paragraph' -import { SearchButton } from './AlgoliaSearch'; +import AlgoliaSearch, { SearchButton } from './AlgoliaSearch'; // Import AlgoliaSearch component import IconLoupe from './icons/Loupe'; export default function Hero({ className = ''}) { @@ -28,28 +28,32 @@ export default function Hero({ className = ''}) { industry standard for defining asynchronous APIs.
-
Proud to be part of the {" "} @@ -66,3 +70,4 @@ export default function Hero({ className = ''}) { ); } + diff --git a/components/Meeting.js b/components/Meeting.js index 0aeb336b44b..75de7580ec0 100644 --- a/components/Meeting.js +++ b/components/Meeting.js @@ -14,13 +14,13 @@ export default function Meeting({ }) { return ( - +
-

{name}

-
+

{name}

+
{purpose} @@ -28,7 +28,7 @@ export default function Meeting({
- Host: + Host: {hostProfile ? ( setOpen(!open)}>
-
+
On this page
@@ -42,10 +42,11 @@ export default function TOC({ > { tocItems.map((item, index) => ( - {item.content.replaceAll('`', '')} diff --git a/cypress/test/AuthorAvatars.cy.js b/cypress/test/AuthorAvatars.cy.js new file mode 100644 index 00000000000..6732bf1a330 --- /dev/null +++ b/cypress/test/AuthorAvatars.cy.js @@ -0,0 +1,65 @@ +import React from 'react'; +import { mount } from 'cypress/react' +import AuthorAvatars from '../../components/AuthorAvatars'; + +describe('AuthorAvatars', () => { + const authors = [ + { + name: 'John Doe', + photo: 'https://example.com/john-doe.jpg', + link: 'https://example.com/john-doe' + }, + { + name: 'Jane Smith', + photo: 'https://example.com/jane-smith.jpg', + link: 'https://example.com/jane-smith' + } + ]; + + + it('renders the author avatars without links', () => { + const authorsWithoutLinks = [ + { + name: 'John Doe', + photo: 'https://example.com/john-doe.jpg', + link: null + }, + { + name: 'Jane Smith', + photo: 'https://example.com/jane-smith.jpg', + link: null + }, + ]; + mount(); + authorsWithoutLinks.forEach((author, index) => { + cy.get('[data-testid="AuthorAvatars-link"]') + .should('not.exist'); + + cy.get('[data-testid="AuthorAvatars-img"]') + .eq(index) + .should('have.attr', 'src', author.photo) + .should('have.attr', 'title', author.name) + .should('have.class', index > 0 ? `absolute left-${index * 7} top-0` : `relative mr-${(authorsWithoutLinks.length - 1) * 7}`) + .should('have.class', `z-${(authorsWithoutLinks.length - 1 - index) * 10}`) + .should('have.class', 'h-10 w-10 border-2 border-white rounded-full object-cover hover:z-50'); + }); + }); + + + + it('renders the author avatars with links', () => { + mount(); + authors.forEach((author, index) => { + cy.get(`[data-testid="AuthorAvatars-link"][alt="${author.name}"][href="${author.link}"]`) + .should('have.length', 1) + .within(() => { + cy.get('[data-testid="AuthorAvatars-img"]') + .should('have.attr', 'src', author.photo) + .should('have.attr', 'title', author.name) + .should('have.class', index > 0 ? `absolute left-${index * 7} top-0` : `relative mr-${(authors.length - 1) * 7}`) + .should('have.class', `z-${(authors.length - 1 - index) * 10}`) + .should('have.class', 'h-10 w-10 border-2 border-white rounded-full object-cover hover:z-50'); + }); + }); + }); +}); diff --git a/cypress/test/DemoAnimation.cy.js b/cypress/test/DemoAnimation.cy.js new file mode 100644 index 00000000000..f98f2614116 --- /dev/null +++ b/cypress/test/DemoAnimation.cy.js @@ -0,0 +1,13 @@ +import React from 'react'; +import { mount } from 'cypress/react'; +import DemoAnimation from '../../components/DemoAnimation'; + +describe('DemoAnimation', () => { + it('renders without errors', () => { + mount(); + + cy.wait(100000); + cy.contains('Play with it!').should('be.visible'); + }); + +}); diff --git a/cypress/test/Feedback.cy.js b/cypress/test/Feedback.cy.js new file mode 100644 index 00000000000..bbe4c1c5b65 --- /dev/null +++ b/cypress/test/Feedback.cy.js @@ -0,0 +1,46 @@ +import { mount } from "cypress/react"; +import Feedback from '../../components/Feedback' +import MockRouter from '../../cypress/utils/router' +describe('Meeting component', () => { + beforeEach(() => { + mount( + + ); + }); + + it('shows success message on correct request', () => { + cy.get('textarea').type('Sample feedback'); + cy.intercept('POST', '/.netlify/functions/github_discussions', (req) => { + req.reply({ + statusCode: 200, + body: { + message: 'Feedback submitted successfully', + }, + headers: { + 'content-type': 'application/json', + }, + }); + }).as('submitFeedback'); + cy.get('form').submit(); + cy.wait('@submitFeedback'); + cy.get('[data-testid="Feedback-div"]').should('contain.text', 'Thank you for your feedback!'); + + }); + it('should display error message on failed submission', () => { + cy.get('textarea').type('Sample feedback'); + cy.intercept('POST', '/.netlify/functions/github_discussions', (req) => { + req.reply({ + statusCode: 500, + body: { + message: 'We were unable to process your feedback', + }, + headers: { + 'content-type': 'application/json', + }, + }); + }).as('submitFeedback'); + cy.get('form').submit(); + cy.wait('@submitFeedback'); + cy.get('[data-testid="Feedback-error"]').should('contain.text', 'Oops! Something went wrong...'); + }); +}); diff --git a/cypress/test/Figure.cy.js b/cypress/test/Figure.cy.js new file mode 100644 index 00000000000..fb8df1d961d --- /dev/null +++ b/cypress/test/Figure.cy.js @@ -0,0 +1,38 @@ +import React from 'react'; +import { mount } from 'cypress/react'; +import Figure from '../../components/Figure'; + +describe('Figure', () => { + it('renders the figure with the image and caption', () => { + const src = '/img/posts/2020-summary/active-members.webp'; + const caption = 'Figure 1: Slack active members weekly'; + const widthClass = 'w-50'; + const className = 'custom-class'; + const float = 'left'; + const altOnly = 'Alt Text'; + const imageClass = 'custom-image-class'; + + mount( +
+ ); + + cy.get('[data-testid="Figure-div"]').should('have.class', className); + cy.get('[data-testid="Figure-div"]').should('have.class', `float-${float}`); + cy.get('[data-testid="Figure-div"]').should('have.class', widthClass); + + cy.get('[data-testid="Figure-img"]').should('have.attr', 'src', src); + cy.get('[data-testid="Figure-img"]').should('have.attr', 'alt', altOnly); + cy.get('[data-testid="Figure-img"]').should('have.class', imageClass); + + cy.contains(caption).should('be.visible'); + cy.contains(caption).should('have.text', caption); + }); +}); diff --git a/cypress/test/Hero.cy.js b/cypress/test/Hero.cy.js new file mode 100644 index 00000000000..d01ce53a0ed --- /dev/null +++ b/cypress/test/Hero.cy.js @@ -0,0 +1,32 @@ +import { mount } from 'cypress/react'; +import Hero from '../../components/Hero'; + +describe('Hero Component', () => { + it('displays the correct content', () => { + mount(); + + cy.contains('Building the future of'); + cy.contains('Event-Driven Architectures (EDA)'); + cy.contains('Open-Source tools to easily build and maintain your event-driven architecture.'); + cy.contains('Read the docs'); + cy.contains('Quick search...'); + cy.contains('Proud to be part of the Linux Foundation'); + }); + + it('navigates to the documentation page when "Read the docs" button is clicked', () => { + mount(); + cy.get('[data-testid="Button-link"]').contains('Read the docs'); + + }); + + it('performs a search when the search button is clicked', () => { + mount(); + + cy.get('[data-testid="Search-Button"]').contains('Quick search...').click(); + + // Type a search query and validate the results + const searchQuery = 'example'; + cy.get('input[type="search"]').type(searchQuery); + + }); +}); diff --git a/cypress/test/Meeting.cy.js b/cypress/test/Meeting.cy.js new file mode 100644 index 00000000000..938794b3be2 --- /dev/null +++ b/cypress/test/Meeting.cy.js @@ -0,0 +1,23 @@ +import { mount } from "cypress/react"; +import Meeting from "../../components/Meeting"; +describe('Meeting component', () => { + it('renders correctly with provided props', () => { + const props = { + name: 'Example Meeting', + purpose: 'Discuss important topics', + host: 'John Doe', + hostProfile: 'https://example.com/profile', + youtube: 'https://www.youtube.com/watch?v=ABC123', + bg: 'blue', + }; + + mount(); + + cy.get('[data-testid="Meeting-heading"]').should('have.text', 'Example Meeting'); + cy.get('[ data-testid="Meeting-paragraph"]').contains('Discuss important topics'); + cy.get('[ data-testid="Meeting-host"]').contains('Host:'); + cy.get('[ data-testid="Meeting-link"]').should('have.attr', 'href', 'https://www.youtube.com/watch?v=ABC123'); + + }); + }); + \ No newline at end of file diff --git a/cypress/test/TOC.cy.js b/cypress/test/TOC.cy.js new file mode 100644 index 00000000000..696ac1a96c7 --- /dev/null +++ b/cypress/test/TOC.cy.js @@ -0,0 +1,70 @@ +import { mount } from '@cypress/react'; +import TOC from '../../components/TOC'; + +describe('TOC', () => { + const toc = [ + { + lvl: 1, + content: '

Introduction

', + slug: 'introduction', + slugWithATag: 'introduction', + }, + { + lvl: 2, + content: '

Getting Started

', + slug: 'getting-started', + slugWithATag: 'getting-started', + }, + { + lvl: 2, + content: '

Installation

', + slug: 'installation', + slugWithATag: 'installation', + }, + { + lvl: 3, + content: '

Step 1: Download

', + slug: 'step-1-download', + slugWithATag: 'step-1-download', + }, + { + lvl: 3, + content: '

Step 2: Install Dependencies

', + slug: 'step-2-install-dependencies', + slugWithATag: 'step-2-install-dependencies', + }, + ]; + it('renders the TOC correctly with empty content', () => { + mount(); + + cy.get('.hidden').should('not.exist'); + }); + it('renders the TOC correctly', () => { + mount(); + + // Add assertions to verify the rendering of TOC items + cy.get('[data-testid="TOC-Heading"]').should('contain', 'On this page'); + cy.get('[data-testid="TOC-Link"]').should('have.length', toc.length); + }); + + it('expands and collapses the TOC on click', () => { + mount(); + + // Verify initial state + cy.get('.hidden').should('exist'); // TOC content should be hidden + + // Click on the TOC header + cy.get('[data-testid="TOC-Heading"]').click(); + + // Verify expanded state + cy.get('.hidden').should('not.exist'); // TOC content should be visible + + // Click again on the TOC header + cy.get('[data-testid="TOC-Heading"]').click(); + + // Verify collapsed state + cy.get('.hidden').should('exist'); // TOC content should be hidden + }); + + + });