From 92d76fb6f43b2b2e1acd2b0e82abf106d021c337 Mon Sep 17 00:00:00 2001 From: Vim <86254807+vim-usds@users.noreply.github.com> Date: Wed, 13 Oct 2021 14:06:05 -0700 Subject: [PATCH] Gherkin workflows for desktop (#788) * Add gherkin tests for page navigation links - test that every page will load when navigating from any other page - update snapshots * Add gherkin workflows 2 - 5 - add test for Federal program officer key information and CTA - add test for Community members key information and CTA - add test for Send feedback - add test for Join the Open Source community - update snapshots * Add gherkin tests for footer links - add footerlinks feature gherkin file - adds a comment to the hyphenizeString() - adds keyword functions for footer - adds data-cy tags to footer component - updates snapshots * Adds workflow to learn more about EO * Add gherkin test for dataset links - add data-cy tags to dataset sections - modify Cy command functions names - update snapshots * Add cypress test to deploy_staging.yml * Add working directory env * Remove keywords.js from cypress test * Add a Then step to all About and Footer tests * Refactor step definitions - use globalStepDefinitions - rename keywords to commonSteps - remove keyword from exclusion list --- .github/workflows/deploy_staging.yml | 7 ++ client/cypress/integration/About.feature | 23 ++++--- client/cypress/integration/About/about.js | 32 ---------- client/cypress/integration/AboutLinks.feature | 30 +++++++++ client/cypress/integration/Contact.feature | 16 +++++ .../cypress/integration/DatasetLinks.feature | 11 ++++ client/cypress/integration/Explore.feature | 16 +++++ .../cypress/integration/FooterLinks.feature | 25 ++++++++ .../integration/LegacyTests/constants.js | 2 +- .../cypress/integration/Methodology.feature | 16 +++++ client/cypress/integration/common/helpers.js | 16 +++++ .../common/i_see_string_in_the_title.js | 4 -- client/cypress/support/commands.js | 10 ++- .../support/step_definitions/commonSteps.js | 64 +++++++++++++++++++ client/package.json | 2 +- client/src/components/AboutCard/AboutCard.tsx | 6 +- .../__snapshots__/AboutCard.test.tsx.snap | 1 + .../src/components/DatasetContainer/index.tsx | 9 ++- .../datasetContainer.test.tsx.snap | 2 + client/src/components/J40Footer.tsx | 20 ++++-- client/src/components/J40Header.tsx | 2 +- .../src/components/J40MainGridContainer.tsx | 13 ++-- .../__snapshots__/J40Footer.spec.tsx.snap | 5 ++ client/src/data/copy/common.tsx | 5 ++ .../pages/__snapshots__/contact.test.tsx.snap | 7 +- .../pages/__snapshots__/index.test.tsx.snap | 13 +++- .../__snapshots__/methodology.test.tsx.snap | 9 ++- 27 files changed, 295 insertions(+), 71 deletions(-) delete mode 100644 client/cypress/integration/About/about.js create mode 100644 client/cypress/integration/AboutLinks.feature create mode 100644 client/cypress/integration/Contact.feature create mode 100644 client/cypress/integration/DatasetLinks.feature create mode 100644 client/cypress/integration/Explore.feature create mode 100644 client/cypress/integration/FooterLinks.feature create mode 100644 client/cypress/integration/Methodology.feature create mode 100644 client/cypress/integration/common/helpers.js delete mode 100644 client/cypress/integration/common/i_see_string_in_the_title.js create mode 100644 client/cypress/support/step_definitions/commonSteps.js diff --git a/.github/workflows/deploy_staging.yml b/.github/workflows/deploy_staging.yml index 836fdd60..78a59cda 100644 --- a/.github/workflows/deploy_staging.yml +++ b/.github/workflows/deploy_staging.yml @@ -9,6 +9,7 @@ on: - "client/**/*" env: PR_NUMBER: ${{github.event.pull_request.number}} + WORKING_DIRECTORY: ./client jobs: build: runs-on: ubuntu-latest @@ -48,6 +49,12 @@ jobs: run: npm test - name: Check for security vulnerabilities run: npm audit --production + - name: Cypress / Gherkin integration tests 🌃 + uses: cypress-io/github-action@v2 + with: + working-directory: ${{env.WORKING_DIRECTORY}} + start: npm start + wait-on: 'http://localhost:8000' - name: Upload Artifact uses: actions/upload-artifact@v2 with: diff --git a/client/cypress/integration/About.feature b/client/cypress/integration/About.feature index da3e61f4..720808aa 100644 --- a/client/cypress/integration/About.feature +++ b/client/cypress/integration/About.feature @@ -1,17 +1,16 @@ -Feature: Does the About page open? - I want to open the about page +Feature: The About page will open from all other pages - Scenario: About page FROM Explore Tool page - Given I am on the Explore Tool page + Scenario: About page open when navigating from Explore the Tool page + Given I am on the "Explore the tool" page When I click on the "About" page in the navigation Then I see "About" in the title - Scenario: About page FROM Methodology page - Given I am on the Explore Tool page - When I click on the "Methodology" page in the navigation - Then I see "Data and Methodology" in the title + Scenario: About page open when navigating from Methodology page + Given I am on the "Methodology" page + When I click on the "About" page in the navigation + Then I see "About" in the title - Scenario: About page FROM Contact page - Given I am on the Explore Tool page - When I click on the "Contact" page in the navigation - Then I see "Contact" in the title \ No newline at end of file + Scenario: About page open when navigating from Contact page + Given I am on the "Contact" page + When I click on the "About" page in the navigation + Then I see "About" in the title diff --git a/client/cypress/integration/About/about.js b/client/cypress/integration/About/about.js deleted file mode 100644 index ed3835dc..00000000 --- a/client/cypress/integration/About/about.js +++ /dev/null @@ -1,32 +0,0 @@ -// / -import {Given, When} from 'cypress-cucumber-preprocessor/steps'; -import {ENDPOINTS} from '../LegacyTests/constants'; - -// eslint-disable-next-line new-cap -Given('I am on the About page', () => { - cy.viewport(1060, 800); - cy.visit(ENDPOINTS.ABOUT); -}); - -// eslint-disable-next-line new-cap -Given('I am on the Explore Tool page', () => { - cy.viewport(1060, 800); - cy.visit(ENDPOINTS.EXPLORE_THE_TOOL); -}); - -// eslint-disable-next-line new-cap -Given('I am on the Data & Methodology page', () => { - cy.viewport(1060, 800); - cy.visit(ENDPOINTS.METHODOLOGY); -}); - -// eslint-disable-next-line new-cap -Given('I open the Contact page', () => { - cy.viewport(1060, 800); - cy.visit(ENDPOINTS.CONTACT); -}); - -// eslint-disable-next-line new-cap -When(`I click on the {string} page in the navigation`, (page) => { - cy.get(`[data-cy="nav-link-${page.toLowerCase()}"]`).click(); -}); diff --git a/client/cypress/integration/AboutLinks.feature b/client/cypress/integration/AboutLinks.feature new file mode 100644 index 00000000..fa41eb9e --- /dev/null +++ b/client/cypress/integration/AboutLinks.feature @@ -0,0 +1,30 @@ +Feature: All links on About page are functional + + Scenario: Visitors can learn more about the J40 EO + Given I am on the "About" page + When I look for the "The Justice40 Initiative" CTA + And I click on the "The Justice40 Initiative" "external" link + Then the link should respond successfully + + Scenario: Federal program officer can find and click on their CTA + Given I am on the "About" page + When I look for the "Federal program managers" CTA + And I click on the "Federal program managers" "internal" link + Then I see "Methodology" in the title + + Scenario: Community members can find and click on their CTA + Given I am on the "About" page + When I look for the "Community members" CTA + And I click on the "Community members" "internal" link + Then I see "Explore the tool" in the title + + Scenario: People can find how to Send feedback + Given I am on the "About" page + When I look for the "Send feedback" CTA + Then the link should allow client to send an email to "screeningtool.feedback@usds.gov" + + Scenario: Open source community can find and click on their CTA + Given I am on the "About" page + When I look for the "Join the open source community" CTA + And I click on the "Join the open source community" "external" link + Then the link should respond successfully diff --git a/client/cypress/integration/Contact.feature b/client/cypress/integration/Contact.feature new file mode 100644 index 00000000..1a26d887 --- /dev/null +++ b/client/cypress/integration/Contact.feature @@ -0,0 +1,16 @@ +Feature: The Contact page will open from all other pages + + Scenario: Contact page open when navigating from About page + Given I am on the "About" page + When I click on the "Contact" page in the navigation + Then I see "Contact" in the title + + Scenario: Contact page open when navigating from Explore the tool page + Given I am on the "Explore the tool" page + When I click on the "Contact" page in the navigation + Then I see "Contact" in the title + + Scenario: Contact page open when navigating from Methodology page + Given I am on the "Methodology" page + When I click on the "Contact" page in the navigation + Then I see "Contact" in the title \ No newline at end of file diff --git a/client/cypress/integration/DatasetLinks.feature b/client/cypress/integration/DatasetLinks.feature new file mode 100644 index 00000000..67dedf0f --- /dev/null +++ b/client/cypress/integration/DatasetLinks.feature @@ -0,0 +1,11 @@ +Feature: All links on the dataset cards should be functional + + Scenario: If I click on any link in the indicators dataset, they should work + Given I am on the "Methodology" page + When I look for the "Datasets used in methodology" CTA + Then All links under "Datasets used in methodology" should work + + Scenario: If I click on any link in the additional indicators dataset, they should work + Given I am on the "Methodology" page + When I look for the "Additional Indicators" CTA + Then All links under "Additional Indicators" should work diff --git a/client/cypress/integration/Explore.feature b/client/cypress/integration/Explore.feature new file mode 100644 index 00000000..faf66661 --- /dev/null +++ b/client/cypress/integration/Explore.feature @@ -0,0 +1,16 @@ +Feature: The Explore the tool page will open from all other pages + + Scenario: Explore the tool page open when navigating from About page + Given I am on the "About" page + When I click on the "Explore the tool" page in the navigation + Then I see "Explore the tool" in the title + + Scenario: Explore the tool page open when navigating from Methodology page + Given I am on the "Methodology" page + When I click on the "Explore the tool" page in the navigation + Then I see "Explore the tool" in the title + + Scenario: Explore the tool page open when navigating from Contact page + Given I am on the "Contact" page + When I click on the "Explore the tool" page in the navigation + Then I see "Explore the tool" in the title \ No newline at end of file diff --git a/client/cypress/integration/FooterLinks.feature b/client/cypress/integration/FooterLinks.feature new file mode 100644 index 00000000..08d9699b --- /dev/null +++ b/client/cypress/integration/FooterLinks.feature @@ -0,0 +1,25 @@ +Feature: All links in the Footer are functional + + Scenario: I can find more information on the Whitehouse + Given I am on the "About" page + When I look for the "footer" + And I click on the "Whitehouse.gov" footer link + Then the link should respond successfully + + Scenario: I can find more information on FOIA + Given I am on the "About" page + When I look for the "footer" + And I click on the "Freedom of Information Act (FOIA)" footer link + Then the link should respond successfully + + Scenario: I can find more information on the Privacy Policy + Given I am on the "About" page + When I look for the "footer" + And I click on the "Privacy Policy" footer link + Then the link should respond successfully + + Scenario: I can find find a contact at USA.gov + Given I am on the "About" page + When I look for the "footer" + And I click on the "Find a contact at USA.gov" footer link + Then the link should respond successfully \ No newline at end of file diff --git a/client/cypress/integration/LegacyTests/constants.js b/client/cypress/integration/LegacyTests/constants.js index 8af41130..3ae562fb 100644 --- a/client/cypress/integration/LegacyTests/constants.js +++ b/client/cypress/integration/LegacyTests/constants.js @@ -1,5 +1,5 @@ export const ENDPOINTS = { - ABOUT: 'en', + ABOUT: 'en/', EXPLORE_THE_TOOL: '/en/cejst', METHODOLOGY: '/en/methodology', CONTACT: 'en/contact', diff --git a/client/cypress/integration/Methodology.feature b/client/cypress/integration/Methodology.feature new file mode 100644 index 00000000..17589eb4 --- /dev/null +++ b/client/cypress/integration/Methodology.feature @@ -0,0 +1,16 @@ +Feature: The Methodology page will open from all other pages + + Scenario: Methodology page open when navigating from About page + Given I am on the "About" page + When I click on the "Methodology" page in the navigation + Then I see "Methodology" in the title + + Scenario: Methodology page open when navigating from Explore the tool page + Given I am on the "Explore the tool" page + When I click on the "Methodology" page in the navigation + Then I see "Methodology" in the title + + Scenario: Methodology page open when navigating from Contact page + Given I am on the "Contact" page + When I click on the "Methodology" page in the navigation + Then I see "Methodology" in the title \ No newline at end of file diff --git a/client/cypress/integration/common/helpers.js b/client/cypress/integration/common/helpers.js new file mode 100644 index 00000000..574b7d21 --- /dev/null +++ b/client/cypress/integration/common/helpers.js @@ -0,0 +1,16 @@ +// Helper functions that need to be shared between both the src codebase +// and the cypress tests + +/** + * This function will take a string and hyphenize it. + * For example: + * Whitehouse.gov => whitehouse-gov + * Privacy Policy => privacy-policy + * + * @param {string} string + * @return {string} + */ +export const hyphenizeString = (string) => { + return string.split(/\.| /).join('-').toLowerCase(); +}; + diff --git a/client/cypress/integration/common/i_see_string_in_the_title.js b/client/cypress/integration/common/i_see_string_in_the_title.js deleted file mode 100644 index bfdc0b48..00000000 --- a/client/cypress/integration/common/i_see_string_in_the_title.js +++ /dev/null @@ -1,4 +0,0 @@ -// eslint-disable-next-line new-cap -Then(`I see {string} in the title`, (title) => { - cy.title().should('include', title); -}); diff --git a/client/cypress/support/commands.js b/client/cypress/support/commands.js index 6b9a3fce..faf5201b 100644 --- a/client/cypress/support/commands.js +++ b/client/cypress/support/commands.js @@ -1,4 +1,4 @@ -/* MAP */ +import {hyphenizeString} from '../integration/common/helpers'; // For some interactions, we need access to the underlying map // Below adapted from https://github.com/codeforcologne/edelgard-map @@ -26,3 +26,11 @@ Cypress.Commands.add('waitForMapIdle', (map) => { map.once('idle', resolve); }); }); + +Cypress.Commands.add('testExternalLinks', (string) => { + return cy.get(`[data-cy="${hyphenizeString(string)}-block"] a`).each((link) => { + cy.request(link.prop('href')) + .its('status') + .should('eq', 200); + }); +}); diff --git a/client/cypress/support/step_definitions/commonSteps.js b/client/cypress/support/step_definitions/commonSteps.js new file mode 100644 index 00000000..191d9285 --- /dev/null +++ b/client/cypress/support/step_definitions/commonSteps.js @@ -0,0 +1,64 @@ +/* eslint-disable new-cap */ + +// Common step definitions for Gherkin + +import {ENDPOINTS} from '../../integration/LegacyTests/constants'; +import {hyphenizeString} from '../../integration/common/helpers'; + +// Common Givens: +Given('I am on the {string} page', (page) => { + const pageArray = page.split(' '); + cy.viewport(1060, 800); + cy.visit(ENDPOINTS[pageArray.join('_').toUpperCase()]); +}); + +// Common Whens: +When(`I click on the {string} page in the navigation`, (page) => { + const pageHyphenCase = hyphenizeString(page); + cy.get(`[data-cy="nav-link-${pageHyphenCase}"]`).click(); +}); + +When(`I look for the {string} CTA`, (ctaString) => { + cy.get(`[data-cy="${hyphenizeString(ctaString)}-block"]`).as('CTA_block'); + cy.get('@CTA_block').scrollIntoView().should('be.visible'); +}); + +When(`I look for the {string}`, (footer) => { + cy.get(`[data-cy="${hyphenizeString(footer)}-primary-block"]`).scrollIntoView().should('be.visible'); +}); + +// Common Thens: +Then(`I see {string} in the title`, (title) => { + cy.title().should('include', title); +}); + +Then(`All links under {string} should work`, (title) => { + cy.testExternalLinks(title); +}); + +Then(`the link should allow client to send an email to {string}`, (email) => { + cy.get(`@CTA_block`).find('a').invoke('attr', 'href').should('eq', `mailto:${email}`); +}); + +Then(`the link should respond successfully`, () => { + cy.get(`@externalLink`).then((link) => { + cy.request(link.prop('href')) + .its('status') + .should('eq', 200); + }); +}); + +// Common Ands: +And(`I click on the {string} {string} link`, (ctaString, type) => { + const CTALinkSelector = `[data-cy="${hyphenizeString(ctaString)}-block"] a`; + + if (type === 'internal') { + cy.get(CTALinkSelector).click(); + } else { + cy.get(CTALinkSelector).as('externalLink'); + }; +}); + +And(`I click on the {string} footer link`, (string) => { + cy.get(`[data-cy="${hyphenizeString(string)}"]`).as('externalLink'); +}); diff --git a/client/package.json b/client/package.json index 5577e780..72df1c79 100644 --- a/client/package.json +++ b/client/package.json @@ -93,6 +93,6 @@ "uswds": "^2.10.3" }, "cypress-cucumber-preprocessor": { - "nonGlobalStepDefinitions": true + "nonGlobalStepDefinitions": false } } diff --git a/client/src/components/AboutCard/AboutCard.tsx b/client/src/components/AboutCard/AboutCard.tsx index e7200c2e..8860e351 100644 --- a/client/src/components/AboutCard/AboutCard.tsx +++ b/client/src/components/AboutCard/AboutCard.tsx @@ -1,6 +1,8 @@ import React from 'react'; import {Grid} from '@trussworks/react-uswds'; + import LinkTypeWrapper from '../LinkTypeWrapper'; +import {hyphenizeString} from '../../../cypress/integration/common/helpers'; // the "body" section is the child object to allow for html versus just text interface AboutCardProps { @@ -29,7 +31,7 @@ const AboutCard = (props: React.PropsWithChildren) => { src={props.imgSrc}/> - +

{props.header}

{props.children} @@ -52,7 +54,7 @@ const AboutCard = (props: React.PropsWithChildren) => { src={props.imgSrc}/>
- +

{props.header}

{props.children} diff --git a/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap b/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap index 98a8ce76..a46ab072 100644 --- a/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap +++ b/client/src/components/AboutCard/__snapshots__/AboutCard.test.tsx.snap @@ -22,6 +22,7 @@ exports[`rendering of the AboutCard checks if component renders 1`] = `
{ return ( <> - + @@ -42,8 +44,9 @@ const DatasetContainer = () => { - - + + diff --git a/client/src/components/DatasetContainer/tests/__snapshots__/datasetContainer.test.tsx.snap b/client/src/components/DatasetContainer/tests/__snapshots__/datasetContainer.test.tsx.snap index b092aebd..9afe1d04 100644 --- a/client/src/components/DatasetContainer/tests/__snapshots__/datasetContainer.test.tsx.snap +++ b/client/src/components/DatasetContainer/tests/__snapshots__/datasetContainer.test.tsx.snap @@ -7,6 +7,7 @@ exports[`rendering of the DatasetContainer checks if various text fields are vis >
{ key={'whitehouselink2'} href={'https://www.whitehouse.gov/'} target={'_blank'} - rel={'noreferrer'}>Whitehouse.gov, + rel={'noreferrer'} + data-cy={hyphenizeString(COMMON_COPY.FOOTER.WHITEHOUSE.defaultMessage)}> + {intl.formatMessage(COMMON_COPY.FOOTER.WHITEHOUSE)} + , + href={'https://www.whitehouse.gov/ceq/foia'} + data-cy={hyphenizeString(COMMON_COPY.FOOTER.FOIA.defaultMessage)}> {intl.formatMessage(COMMON_COPY.FOOTER.FOIA)} , + href={'https://www.whitehouse.gov/privacy/'} + data-cy={hyphenizeString(COMMON_COPY.FOOTER.PRIVACY.defaultMessage)}> {intl.formatMessage(COMMON_COPY.FOOTER.PRIVACY)} , ], @@ -58,7 +64,8 @@ const J40Footer = () => { + href={'https://www.usa.gov/'} + data-cy={hyphenizeString(COMMON_COPY.FOOTER.CONTACT_LINK.defaultMessage)}> {intl.formatMessage(COMMON_COPY.FOOTER.CONTACT_LINK)} , ], @@ -71,11 +78,12 @@ const J40Footer = () => { // `className="mobile-lg:grid-col-6 desktop:grid-col-3">` needs to be // `className="mobile-lg:grid-col-12 desktop:grid-col-4">` ugh.