From 3c35c6c8aebe9c0da7de32d8c3b12e8214b19e58 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 27 Aug 2021 17:27:41 -0500 Subject: [PATCH 1/5] Add basic accessibility scan for most public pages. Disable any a11y tests with known issues --- cypress/integration/breadcrumbs.spec.ts | 23 +++++++++++++ cypress/integration/collection-page.spec.ts | 23 +++++++++++++ .../integration/collection-statistics.spec.ts | 32 +++++++++++++++++++ cypress/integration/community-list.spec.ts | 25 +++++++++++++++ cypress/integration/community-page.spec.ts | 23 +++++++++++++ .../integration/community-statistics.spec.ts | 32 +++++++++++++++++++ cypress/integration/footer.spec.ts | 12 +++++++ cypress/integration/header.spec.ts | 18 +++++++++++ .../integration/homepage-statistics.spec.ts | 18 +++++++++++ cypress/integration/homepage.spec.ts | 21 +++++------- cypress/integration/item-page.spec.ts | 30 +++++++++++++---- cypress/integration/item-statistics.spec.ts | 31 ++++++++++++------ cypress/support/index.ts | 5 +++ 13 files changed, 264 insertions(+), 29 deletions(-) create mode 100644 cypress/integration/breadcrumbs.spec.ts create mode 100644 cypress/integration/collection-page.spec.ts create mode 100644 cypress/integration/collection-statistics.spec.ts create mode 100644 cypress/integration/community-list.spec.ts create mode 100644 cypress/integration/community-page.spec.ts create mode 100644 cypress/integration/community-statistics.spec.ts create mode 100644 cypress/integration/footer.spec.ts create mode 100644 cypress/integration/header.spec.ts create mode 100644 cypress/integration/homepage-statistics.spec.ts diff --git a/cypress/integration/breadcrumbs.spec.ts b/cypress/integration/breadcrumbs.spec.ts new file mode 100644 index 0000000000..8fed83bacb --- /dev/null +++ b/cypress/integration/breadcrumbs.spec.ts @@ -0,0 +1,23 @@ +import { Options } from "cypress-axe"; +import { TEST_ENTITY_PUBLICATION } from "cypress/support"; + +describe('Breadcrumbs', () => { + it('should pass accessibility tests', () => { + // Visit an Item, as those have more breadcrumbs + cy.visit('/entities/publication/' + TEST_ENTITY_PUBLICATION); + cy.injectAxe(); + + // Wait for breadcrumbs to be visible + cy.get('ds-breadcrumbs').should('be.visible'); + + // Analyze for accessibility + // Disable color-contrast checks until #1149 is fixed + cy.checkA11y('ds-breadcrumbs', + { + rules: { + 'color-contrast': { enabled: false } + } + } as Options + ); + }); +}); diff --git a/cypress/integration/collection-page.spec.ts b/cypress/integration/collection-page.spec.ts new file mode 100644 index 0000000000..11babe76d2 --- /dev/null +++ b/cypress/integration/collection-page.spec.ts @@ -0,0 +1,23 @@ +import { Options } from "cypress-axe"; +import { TEST_COLLECTION } from "cypress/support"; + +describe('Collection Page', () => { + + it('should pass accessibility tests', () => { + cy.visit('/collections/' + TEST_COLLECTION); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-collection-page').should('exist'); + + // Analyze for accessibility issues + // Disable color-contrast checks until it is fixed (see #1202 and #1178) + cy.checkA11y('ds-collection-page', + { + rules: { + 'color-contrast': { enabled: false } + } + } as Options + ); + }); +}); diff --git a/cypress/integration/collection-statistics.spec.ts b/cypress/integration/collection-statistics.spec.ts new file mode 100644 index 0000000000..c6f6082101 --- /dev/null +++ b/cypress/integration/collection-statistics.spec.ts @@ -0,0 +1,32 @@ +import { TEST_COLLECTION } from "cypress/support"; + +describe('Collection Statistics Page', () => { + const COLLECTIONSTATISTICSPAGE = '/statistics/collections/' + TEST_COLLECTION; + + it('should load if you click on "Statistics" from a Collection page', () => { + cy.visit('/collections/' + TEST_COLLECTION); + cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); + cy.location('pathname').should('eq', COLLECTIONSTATISTICSPAGE); + }); + + it('should contain a "Total visits" section', () => { + cy.visit(COLLECTIONSTATISTICSPAGE); + cy.get('.' + TEST_COLLECTION + '_TotalVisits').should('exist'); + }); + + it('should contain a "Total visits per month" section', () => { + cy.visit(COLLECTIONSTATISTICSPAGE); + cy.get('.' + TEST_COLLECTION + '_TotalVisitsPerMonth').should('exist'); + }); + + it('should pass accessibility tests', () => { + cy.visit(COLLECTIONSTATISTICSPAGE); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-collection-statistics-page').should('exist'); + + // Analyze for accessibility issues + cy.checkA11y('ds-collection-statistics-page'); + }); +}); diff --git a/cypress/integration/community-list.spec.ts b/cypress/integration/community-list.spec.ts new file mode 100644 index 0000000000..1d6f9ff849 --- /dev/null +++ b/cypress/integration/community-list.spec.ts @@ -0,0 +1,25 @@ +import { Options } from "cypress-axe"; + +describe('Community List Page', () => { + + it('should pass accessibility tests', () => { + cy.visit('/community-list'); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-community-list-page').should('exist'); + + // Open first Community (to show Collections)...that way we scan sub-elements as well + cy.get('ds-community-list :nth-child(1) > .btn-group > .btn').click(); + + // Analyze for accessibility issues + // Disable heading-order checks until it is fixed + cy.checkA11y('ds-community-list-page', + { + rules: { + 'heading-order': { enabled: false } + } + } as Options + ); + }); +}); diff --git a/cypress/integration/community-page.spec.ts b/cypress/integration/community-page.spec.ts new file mode 100644 index 0000000000..60641120a0 --- /dev/null +++ b/cypress/integration/community-page.spec.ts @@ -0,0 +1,23 @@ +import { Options } from "cypress-axe"; +import { TEST_COMMUNITY } from "cypress/support"; + +describe('Community Page', () => { + + it('should pass accessibility tests', () => { + cy.visit('/communities/' + TEST_COMMUNITY); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-community-page').should('exist'); + + // Analyze for accessibility issues + // Disable color-contrast checks until it is fixed (see #1202 and #1178) + cy.checkA11y('ds-community-page', + { + rules: { + 'color-contrast': { enabled: false } + } + } as Options + ); + }); +}); diff --git a/cypress/integration/community-statistics.spec.ts b/cypress/integration/community-statistics.spec.ts new file mode 100644 index 0000000000..555667a96e --- /dev/null +++ b/cypress/integration/community-statistics.spec.ts @@ -0,0 +1,32 @@ +import { TEST_COMMUNITY } from "cypress/support"; + +describe('Community Statistics Page', () => { + const COMMUNITYSTATISTICSPAGE = '/statistics/communities/' + TEST_COMMUNITY; + + it('should load if you click on "Statistics" from a Community page', () => { + cy.visit('/communities/' + TEST_COMMUNITY); + cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); + cy.location('pathname').should('eq', COMMUNITYSTATISTICSPAGE); + }); + + it('should contain a "Total visits" section', () => { + cy.visit(COMMUNITYSTATISTICSPAGE); + cy.get('.' + TEST_COMMUNITY + '_TotalVisits').should('exist'); + }); + + it('should contain a "Total visits per month" section', () => { + cy.visit(COMMUNITYSTATISTICSPAGE); + cy.get('.' + TEST_COMMUNITY + '_TotalVisitsPerMonth').should('exist'); + }); + + it('should pass accessibility tests', () => { + cy.visit(COMMUNITYSTATISTICSPAGE); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-community-statistics-page').should('exist'); + + // Analyze for accessibility issues + cy.checkA11y('ds-community-statistics-page'); + }); +}); diff --git a/cypress/integration/footer.spec.ts b/cypress/integration/footer.spec.ts new file mode 100644 index 0000000000..25d1ec8c94 --- /dev/null +++ b/cypress/integration/footer.spec.ts @@ -0,0 +1,12 @@ +describe('Footer', () => { + it('should pass accessibility tests', () => { + cy.visit('/'); + cy.injectAxe(); + + // Footer must first be visible + cy.get('ds-footer').should('be.visible'); + + // Analyze for accessibility + cy.checkA11y('ds-footer'); + }); +}); \ No newline at end of file diff --git a/cypress/integration/header.spec.ts b/cypress/integration/header.spec.ts new file mode 100644 index 0000000000..75e1837c36 --- /dev/null +++ b/cypress/integration/header.spec.ts @@ -0,0 +1,18 @@ +describe('Header', () => { + it('should pass accessibility tests', () => { + cy.visit('/'); + cy.injectAxe(); + + // Header must first be visible + cy.get('ds-header').should('be.visible'); + + // Analyze for accessibility + cy.checkA11y({ + include: ['ds-header'], + exclude: [ + ['#search-navbar-container'], // search in navbar has duplicative ID. Will be fixed in #1174 + ['.dropdownLogin'] // "Log in" link has color contrast issues. Will be fixed in #1149 + ], + }); + }); +}); \ No newline at end of file diff --git a/cypress/integration/homepage-statistics.spec.ts b/cypress/integration/homepage-statistics.spec.ts new file mode 100644 index 0000000000..b479d7b300 --- /dev/null +++ b/cypress/integration/homepage-statistics.spec.ts @@ -0,0 +1,18 @@ +describe('Site Statistics Page', () => { + it('should load if you click on "Statistics" from homepage', () => { + cy.visit('/'); + cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); + cy.location('pathname').should('eq', '/statistics'); + }); + + it('should pass accessibility tests', () => { + cy.visit('/statistics'); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-site-statistics-page').should('exist'); + + // Analyze for accessibility issues + cy.checkA11y('ds-site-statistics-page'); + }); +}); diff --git a/cypress/integration/homepage.spec.ts b/cypress/integration/homepage.spec.ts index e6c28156bb..25494d4164 100644 --- a/cypress/integration/homepage.spec.ts +++ b/cypress/integration/homepage.spec.ts @@ -20,18 +20,13 @@ describe('Homepage', () => { cy.url().should('include', 'query=' + encodeURI(queryString)); }); - // it('should pass accessibility tests', () => { - // // first must inject Axe into current page - // cy.injectAxe(); + it('should pass accessibility tests', () => { + cy.injectAxe(); - // // Analyze entire page for accessibility issues - // // NOTE: this test checks accessibility of header/footer as well - // cy.checkA11y({ - // exclude: [ - // ['#klaro'], // Klaro plugin (privacy policy popup) has color contrast issues - // ['#search-navbar-container'], // search in navbar has duplicative ID. Will be fixed in #1174 - // ['.dropdownLogin'] // "Log in" link in header has color contrast issues - // ], - // }); - // }); + // Wait for homepage tag to appear + cy.get('ds-home-page').should('be.visible'); + + // Analyze for accessibility issues + cy.checkA11y('ds-home-page'); + }); }); diff --git a/cypress/integration/item-page.spec.ts b/cypress/integration/item-page.spec.ts index bd91b6506c..2009623dce 100644 --- a/cypress/integration/item-page.spec.ts +++ b/cypress/integration/item-page.spec.ts @@ -1,15 +1,31 @@ -describe('Item Page', () => { - const ITEMPAGE = '/items/e98b0f27-5c19-49a0-960d-eb6ad5287067'; - const ENTITYPAGE = '/entities/publication/e98b0f27-5c19-49a0-960d-eb6ad5287067'; +import { Options } from "cypress-axe"; +import { TEST_ENTITY_PUBLICATION } from "cypress/support"; - it('should contain element ds-item-page when navigating to an item page', () => { - cy.visit(ENTITYPAGE); - cy.get('ds-item-page').should('exist'); - }); +describe('Item Page', () => { + const ITEMPAGE = '/items/' + TEST_ENTITY_PUBLICATION; + const ENTITYPAGE = '/entities/publication/' + TEST_ENTITY_PUBLICATION; // Test that entities will redirect to /entities/[type]/[uuid] when accessed via /items/[uuid] it('should redirect to the entity page when navigating to an item page', () => { cy.visit(ITEMPAGE); cy.location('pathname').should('eq', ENTITYPAGE); }); + + it('should pass accessibility tests', () => { + cy.visit(ENTITYPAGE); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-item-page').should('exist'); + + // Analyze for accessibility issues + // Disable heading-order checks until it is fixed + cy.checkA11y('ds-item-page', + { + rules: { + 'heading-order': { enabled: false } + } + } as Options + ); + }); }); diff --git a/cypress/integration/item-statistics.spec.ts b/cypress/integration/item-statistics.spec.ts index f90195c9fa..1d60a015dc 100644 --- a/cypress/integration/item-statistics.spec.ts +++ b/cypress/integration/item-statistics.spec.ts @@ -1,6 +1,13 @@ +import { TEST_ENTITY_PUBLICATION } from "cypress/support"; + describe('Item Statistics Page', () => { - const ITEMUUID = 'e98b0f27-5c19-49a0-960d-eb6ad5287067'; - const ITEMSTATISTICSPAGE = '/statistics/items/' + ITEMUUID; + const ITEMSTATISTICSPAGE = '/statistics/items/' + TEST_ENTITY_PUBLICATION; + + it('should load if you click on "Statistics" from an Item/Entity page', () => { + cy.visit('/entities/publication/' + TEST_ENTITY_PUBLICATION); + cy.get('ds-navbar ds-link-menu-item a[title="Statistics"]').click(); + cy.location('pathname').should('eq', ITEMSTATISTICSPAGE); + }); it('should contain element ds-item-statistics-page when navigating to an item statistics page', () => { cy.visit(ITEMSTATISTICSPAGE); @@ -8,18 +15,24 @@ describe('Item Statistics Page', () => { cy.get('ds-item-page').should('not.exist'); }); - it('should contain the item statistics page url when navigating to an item statistics page', () => { - cy.visit(ITEMSTATISTICSPAGE); - cy.location('pathname').should('eq', ITEMSTATISTICSPAGE); - }); - it('should contain a "Total visits" section', () => { cy.visit(ITEMSTATISTICSPAGE); - cy.get('.' + ITEMUUID + '_TotalVisits').should('exist'); + cy.get('.' + TEST_ENTITY_PUBLICATION + '_TotalVisits').should('exist'); }); it('should contain a "Total visits per month" section', () => { cy.visit(ITEMSTATISTICSPAGE); - cy.get('.' + ITEMUUID + '_TotalVisitsPerMonth').should('exist'); + cy.get('.' + TEST_ENTITY_PUBLICATION + '_TotalVisitsPerMonth').should('exist'); + }); + + it('should pass accessibility tests', () => { + cy.visit(ITEMSTATISTICSPAGE); + cy.injectAxe(); + + // tag must be loaded + cy.get('ds-item-statistics-page').should('exist'); + + // Analyze for accessibility issues + cy.checkA11y('ds-item-statistics-page'); }); }); diff --git a/cypress/support/index.ts b/cypress/support/index.ts index a1456bfcd4..479212333a 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -19,3 +19,8 @@ // Import Cypress Axe tools for all tests // https://github.com/component-driven/cypress-axe import 'cypress-axe'; + +// Global constants used in tests +export const TEST_COLLECTION = '282164f5-d325-4740-8dd1-fa4d6d3e7200'; +export const TEST_COMMUNITY = '0958c910-2037-42a9-81c7-dca80e3892b4'; +export const TEST_ENTITY_PUBLICATION = 'e98b0f27-5c19-49a0-960d-eb6ad5287067'; \ No newline at end of file From fad74a4ca28fe5ff5ce1b6ca507f6ad386ca068e Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 13 Sep 2021 17:11:31 -0500 Subject: [PATCH 2/5] Upgrade Cypress --- package.json | 2 +- yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 66ef13f471..87fdcb51f0 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "copy-webpack-plugin": "^6.4.1", "css-loader": "3.4.0", "cssnano": "^4.1.10", - "cypress": "8.3.1", + "cypress": "8.4.0", "cypress-axe": "^0.13.0", "deep-freeze": "0.0.1", "dotenv": "^8.2.0", diff --git a/yarn.lock b/yarn.lock index 40658e305f..5d6ba9f67f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4153,10 +4153,10 @@ cypress-axe@^0.13.0: resolved "https://registry.yarnpkg.com/cypress-axe/-/cypress-axe-0.13.0.tgz#3234e1a79a27701f2451fcf2f333eb74204c7966" integrity sha512-fCIy7RiDCm7t30U3C99gGwQrUO307EYE1QqXNaf9ToK4DVqW8y5on+0a/kUHMrHdlls2rENF6TN9ZPpPpwLrnw== -cypress@8.3.1: - version "8.3.1" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.3.1.tgz#c6760dbb907df2570b0e1ac235fa31c30f9260a6" - integrity sha512-1v6pfx+/5cXhaT5T6QKOvnkawmEHWHLiVzm3MYMoQN1fkX2Ma1C32STd3jBStE9qT5qPSTILjGzypVRxCBi40g== +cypress@8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.4.0.tgz#09ec06a73f1cb10121c103cba15076e659e24876" + integrity sha512-RtVgGFR06ikyMaq/VqapeqOjGaIA42PpK7F0qe1MCiFArfUuJECsLmeYaOA+1TlmNUgJNMSF5fWKkZIJr5Uc7w== dependencies: "@cypress/request" "^2.88.6" "@cypress/xvfb" "^1.2.4" From 4faa850fbaced4405793f376c7970bbbca0d1246 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Mon, 13 Sep 2021 17:11:53 -0500 Subject: [PATCH 3/5] Add logging for violations & testA11y() in utils.ts. Use that method everywhere else --- cypress/integration/breadcrumbs.spec.ts | 14 ++---- cypress/integration/collection-page.spec.ts | 14 ++---- .../integration/collection-statistics.spec.ts | 6 +-- cypress/integration/community-list.spec.ts | 6 +-- cypress/integration/community-page.spec.ts | 14 ++---- .../integration/community-statistics.spec.ts | 6 +-- cypress/integration/footer.spec.ts | 7 +-- cypress/integration/header.spec.ts | 7 +-- .../integration/homepage-statistics.spec.ts | 5 ++- cypress/integration/homepage.spec.ts | 6 +-- cypress/integration/item-page.spec.ts | 8 ++-- cypress/integration/item-statistics.spec.ts | 6 +-- cypress/plugins/index.ts | 17 +++++-- cypress/support/index.ts | 2 +- cypress/support/utils.ts | 44 +++++++++++++++++++ cypress/tsconfig.json | 3 +- 16 files changed, 100 insertions(+), 65 deletions(-) create mode 100644 cypress/support/utils.ts diff --git a/cypress/integration/breadcrumbs.spec.ts b/cypress/integration/breadcrumbs.spec.ts index 8fed83bacb..62b9a8ad1d 100644 --- a/cypress/integration/breadcrumbs.spec.ts +++ b/cypress/integration/breadcrumbs.spec.ts @@ -1,23 +1,15 @@ -import { Options } from "cypress-axe"; -import { TEST_ENTITY_PUBLICATION } from "cypress/support"; +import { TEST_ENTITY_PUBLICATION } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Breadcrumbs', () => { it('should pass accessibility tests', () => { // Visit an Item, as those have more breadcrumbs cy.visit('/entities/publication/' + TEST_ENTITY_PUBLICATION); - cy.injectAxe(); // Wait for breadcrumbs to be visible cy.get('ds-breadcrumbs').should('be.visible'); // Analyze for accessibility - // Disable color-contrast checks until #1149 is fixed - cy.checkA11y('ds-breadcrumbs', - { - rules: { - 'color-contrast': { enabled: false } - } - } as Options - ); + testA11y('ds-breadcrumbs'); }); }); diff --git a/cypress/integration/collection-page.spec.ts b/cypress/integration/collection-page.spec.ts index 11babe76d2..a0140d8faf 100644 --- a/cypress/integration/collection-page.spec.ts +++ b/cypress/integration/collection-page.spec.ts @@ -1,23 +1,15 @@ -import { Options } from "cypress-axe"; -import { TEST_COLLECTION } from "cypress/support"; +import { TEST_COLLECTION } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Collection Page', () => { it('should pass accessibility tests', () => { cy.visit('/collections/' + TEST_COLLECTION); - cy.injectAxe(); // tag must be loaded cy.get('ds-collection-page').should('exist'); // Analyze for accessibility issues - // Disable color-contrast checks until it is fixed (see #1202 and #1178) - cy.checkA11y('ds-collection-page', - { - rules: { - 'color-contrast': { enabled: false } - } - } as Options - ); + testA11y('ds-collection-page'); }); }); diff --git a/cypress/integration/collection-statistics.spec.ts b/cypress/integration/collection-statistics.spec.ts index c6f6082101..90b569c824 100644 --- a/cypress/integration/collection-statistics.spec.ts +++ b/cypress/integration/collection-statistics.spec.ts @@ -1,4 +1,5 @@ -import { TEST_COLLECTION } from "cypress/support"; +import { TEST_COLLECTION } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Collection Statistics Page', () => { const COLLECTIONSTATISTICSPAGE = '/statistics/collections/' + TEST_COLLECTION; @@ -21,12 +22,11 @@ describe('Collection Statistics Page', () => { it('should pass accessibility tests', () => { cy.visit(COLLECTIONSTATISTICSPAGE); - cy.injectAxe(); // tag must be loaded cy.get('ds-collection-statistics-page').should('exist'); // Analyze for accessibility issues - cy.checkA11y('ds-collection-statistics-page'); + testA11y('ds-collection-statistics-page'); }); }); diff --git a/cypress/integration/community-list.spec.ts b/cypress/integration/community-list.spec.ts index 1d6f9ff849..a7ba72b74a 100644 --- a/cypress/integration/community-list.spec.ts +++ b/cypress/integration/community-list.spec.ts @@ -1,10 +1,10 @@ -import { Options } from "cypress-axe"; +import { Options } from 'cypress-axe'; +import { testA11y } from 'cypress/support/utils'; describe('Community List Page', () => { it('should pass accessibility tests', () => { cy.visit('/community-list'); - cy.injectAxe(); // tag must be loaded cy.get('ds-community-list-page').should('exist'); @@ -14,7 +14,7 @@ describe('Community List Page', () => { // Analyze for accessibility issues // Disable heading-order checks until it is fixed - cy.checkA11y('ds-community-list-page', + testA11y('ds-community-list-page', { rules: { 'heading-order': { enabled: false } diff --git a/cypress/integration/community-page.spec.ts b/cypress/integration/community-page.spec.ts index 60641120a0..79e21431ad 100644 --- a/cypress/integration/community-page.spec.ts +++ b/cypress/integration/community-page.spec.ts @@ -1,23 +1,15 @@ -import { Options } from "cypress-axe"; -import { TEST_COMMUNITY } from "cypress/support"; +import { TEST_COMMUNITY } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Community Page', () => { it('should pass accessibility tests', () => { cy.visit('/communities/' + TEST_COMMUNITY); - cy.injectAxe(); // tag must be loaded cy.get('ds-community-page').should('exist'); // Analyze for accessibility issues - // Disable color-contrast checks until it is fixed (see #1202 and #1178) - cy.checkA11y('ds-community-page', - { - rules: { - 'color-contrast': { enabled: false } - } - } as Options - ); + testA11y('ds-community-page',); }); }); diff --git a/cypress/integration/community-statistics.spec.ts b/cypress/integration/community-statistics.spec.ts index 555667a96e..cbf1783c0b 100644 --- a/cypress/integration/community-statistics.spec.ts +++ b/cypress/integration/community-statistics.spec.ts @@ -1,4 +1,5 @@ -import { TEST_COMMUNITY } from "cypress/support"; +import { TEST_COMMUNITY } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Community Statistics Page', () => { const COMMUNITYSTATISTICSPAGE = '/statistics/communities/' + TEST_COMMUNITY; @@ -21,12 +22,11 @@ describe('Community Statistics Page', () => { it('should pass accessibility tests', () => { cy.visit(COMMUNITYSTATISTICSPAGE); - cy.injectAxe(); // tag must be loaded cy.get('ds-community-statistics-page').should('exist'); // Analyze for accessibility issues - cy.checkA11y('ds-community-statistics-page'); + testA11y('ds-community-statistics-page'); }); }); diff --git a/cypress/integration/footer.spec.ts b/cypress/integration/footer.spec.ts index 25d1ec8c94..656e9d4701 100644 --- a/cypress/integration/footer.spec.ts +++ b/cypress/integration/footer.spec.ts @@ -1,12 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + describe('Footer', () => { it('should pass accessibility tests', () => { cy.visit('/'); - cy.injectAxe(); // Footer must first be visible cy.get('ds-footer').should('be.visible'); // Analyze for accessibility - cy.checkA11y('ds-footer'); + testA11y('ds-footer'); }); -}); \ No newline at end of file +}); diff --git a/cypress/integration/header.spec.ts b/cypress/integration/header.spec.ts index 75e1837c36..236208db68 100644 --- a/cypress/integration/header.spec.ts +++ b/cypress/integration/header.spec.ts @@ -1,13 +1,14 @@ +import { testA11y } from 'cypress/support/utils'; + describe('Header', () => { it('should pass accessibility tests', () => { cy.visit('/'); - cy.injectAxe(); // Header must first be visible cy.get('ds-header').should('be.visible'); // Analyze for accessibility - cy.checkA11y({ + testA11y({ include: ['ds-header'], exclude: [ ['#search-navbar-container'], // search in navbar has duplicative ID. Will be fixed in #1174 @@ -15,4 +16,4 @@ describe('Header', () => { ], }); }); -}); \ No newline at end of file +}); diff --git a/cypress/integration/homepage-statistics.spec.ts b/cypress/integration/homepage-statistics.spec.ts index b479d7b300..fe0311f87e 100644 --- a/cypress/integration/homepage-statistics.spec.ts +++ b/cypress/integration/homepage-statistics.spec.ts @@ -1,3 +1,5 @@ +import { testA11y } from 'cypress/support/utils'; + describe('Site Statistics Page', () => { it('should load if you click on "Statistics" from homepage', () => { cy.visit('/'); @@ -7,12 +9,11 @@ describe('Site Statistics Page', () => { it('should pass accessibility tests', () => { cy.visit('/statistics'); - cy.injectAxe(); // tag must be loaded cy.get('ds-site-statistics-page').should('exist'); // Analyze for accessibility issues - cy.checkA11y('ds-site-statistics-page'); + testA11y('ds-site-statistics-page'); }); }); diff --git a/cypress/integration/homepage.spec.ts b/cypress/integration/homepage.spec.ts index 25494d4164..ddde260bc7 100644 --- a/cypress/integration/homepage.spec.ts +++ b/cypress/integration/homepage.spec.ts @@ -1,3 +1,5 @@ +import { testA11y } from 'cypress/support/utils'; + describe('Homepage', () => { beforeEach(() => { // All tests start with visiting homepage @@ -21,12 +23,10 @@ describe('Homepage', () => { }); it('should pass accessibility tests', () => { - cy.injectAxe(); - // Wait for homepage tag to appear cy.get('ds-home-page').should('be.visible'); // Analyze for accessibility issues - cy.checkA11y('ds-home-page'); + testA11y('ds-home-page'); }); }); diff --git a/cypress/integration/item-page.spec.ts b/cypress/integration/item-page.spec.ts index 2009623dce..6a454b678d 100644 --- a/cypress/integration/item-page.spec.ts +++ b/cypress/integration/item-page.spec.ts @@ -1,5 +1,6 @@ -import { Options } from "cypress-axe"; -import { TEST_ENTITY_PUBLICATION } from "cypress/support"; +import { Options } from 'cypress-axe'; +import { TEST_ENTITY_PUBLICATION } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Item Page', () => { const ITEMPAGE = '/items/' + TEST_ENTITY_PUBLICATION; @@ -13,14 +14,13 @@ describe('Item Page', () => { it('should pass accessibility tests', () => { cy.visit(ENTITYPAGE); - cy.injectAxe(); // tag must be loaded cy.get('ds-item-page').should('exist'); // Analyze for accessibility issues // Disable heading-order checks until it is fixed - cy.checkA11y('ds-item-page', + testA11y('ds-item-page', { rules: { 'heading-order': { enabled: false } diff --git a/cypress/integration/item-statistics.spec.ts b/cypress/integration/item-statistics.spec.ts index 1d60a015dc..66ebc228db 100644 --- a/cypress/integration/item-statistics.spec.ts +++ b/cypress/integration/item-statistics.spec.ts @@ -1,4 +1,5 @@ -import { TEST_ENTITY_PUBLICATION } from "cypress/support"; +import { TEST_ENTITY_PUBLICATION } from 'cypress/support'; +import { testA11y } from 'cypress/support/utils'; describe('Item Statistics Page', () => { const ITEMSTATISTICSPAGE = '/statistics/items/' + TEST_ENTITY_PUBLICATION; @@ -27,12 +28,11 @@ describe('Item Statistics Page', () => { it('should pass accessibility tests', () => { cy.visit(ITEMSTATISTICSPAGE); - cy.injectAxe(); // tag must be loaded cy.get('ds-item-statistics-page').should('exist'); // Analyze for accessibility issues - cy.checkA11y('ds-item-statistics-page'); + testA11y('ds-item-statistics-page'); }); }); diff --git a/cypress/plugins/index.ts b/cypress/plugins/index.ts index c106e08011..c6eb874232 100644 --- a/cypress/plugins/index.ts +++ b/cypress/plugins/index.ts @@ -1,5 +1,16 @@ // Plugins enable you to tap into, modify, or extend the internal behavior of Cypress // For more info, visit https://on.cypress.io/plugins-api -/* tslint:disable:no-empty */ -module.exports = (on, config) => { }; -/* tslint:enable:no-empty */ +module.exports = (on, config) => { + // Define "log" and "table" tasks, used for logging accessibility errors during CI + // Borrowed from https://github.com/component-driven/cypress-axe#in-cypress-plugins-file + on('task', { + log(message: string) { + console.log(message); + return null; + }, + table(message: string) { + console.table(message); + return null; + } + }); +}; diff --git a/cypress/support/index.ts b/cypress/support/index.ts index 479212333a..e8b10b9cfb 100644 --- a/cypress/support/index.ts +++ b/cypress/support/index.ts @@ -23,4 +23,4 @@ import 'cypress-axe'; // Global constants used in tests export const TEST_COLLECTION = '282164f5-d325-4740-8dd1-fa4d6d3e7200'; export const TEST_COMMUNITY = '0958c910-2037-42a9-81c7-dca80e3892b4'; -export const TEST_ENTITY_PUBLICATION = 'e98b0f27-5c19-49a0-960d-eb6ad5287067'; \ No newline at end of file +export const TEST_ENTITY_PUBLICATION = 'e98b0f27-5c19-49a0-960d-eb6ad5287067'; diff --git a/cypress/support/utils.ts b/cypress/support/utils.ts new file mode 100644 index 0000000000..96575969e8 --- /dev/null +++ b/cypress/support/utils.ts @@ -0,0 +1,44 @@ +import { Result } from 'axe-core'; +import { Options } from 'cypress-axe'; + +// Log violations to terminal/commandline in a table format. +// Uses 'log' and 'table' tasks defined in ../plugins/index.ts +// Borrowed from https://github.com/component-driven/cypress-axe#in-your-spec-file +function terminalLog(violations: Result[]) { + cy.task( + 'log', + `${violations.length} accessibility violation${violations.length === 1 ? '' : 's'} ${violations.length === 1 ? 'was' : 'were'} detected` + ); + // pluck specific keys to keep the table readable + const violationData = violations.map( + ({ id, impact, description, helpUrl, nodes }) => ({ + id, + impact, + description, + helpUrl, + nodes: nodes.length, + html: nodes.map(node => node.html) + }) + ); + + // Print violations as an array, since 'node.html' above often breaks table alignment + cy.task('log', violationData); + // Optionally, uncomment to print as a table + // cy.task('table', violationData); + +} + +// Custom "testA11y()" method which checks accessibility using cypress-axe +// while also ensuring any violations are logged to the terminal (see terminalLog above) +// This method MUST be called after cy.visit(), as cy.injectAxe() must be called after page load +export const testA11y = (context?: any, options?: Options) => { + cy.injectAxe(); + cy.configureAxe({ + rules: [ + // Disable color contrast checks as they are inaccurate / result in a lot of false positives + // See also open issues in axe-core: https://github.com/dequelabs/axe-core/labels/color%20contrast + { id: 'color-contrast', enabled: false }, + ] + }); + cy.checkA11y(context, options, terminalLog); +}; diff --git a/cypress/tsconfig.json b/cypress/tsconfig.json index 39f88f8210..58083003cd 100644 --- a/cypress/tsconfig.json +++ b/cypress/tsconfig.json @@ -6,7 +6,8 @@ "compilerOptions": { "types": [ "cypress", - "cypress-axe" + "cypress-axe", + "node" ] } } \ No newline at end of file From 305571bc25de109355965a7046fb50e9cd70a678 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Tue, 14 Sep 2021 09:53:10 -0500 Subject: [PATCH 4/5] Add accessibility tests for search/browse --- cypress/integration/browse-by-author.spec.ts | 13 +++++ .../integration/browse-by-dateissued.spec.ts | 13 +++++ cypress/integration/browse-by-subject.spec.ts | 13 +++++ cypress/integration/browse-by-title.spec.ts | 13 +++++ cypress/integration/search-page.spec.ts | 53 +++++++++++++++++++ 5 files changed, 105 insertions(+) create mode 100644 cypress/integration/browse-by-author.spec.ts create mode 100644 cypress/integration/browse-by-dateissued.spec.ts create mode 100644 cypress/integration/browse-by-subject.spec.ts create mode 100644 cypress/integration/browse-by-title.spec.ts diff --git a/cypress/integration/browse-by-author.spec.ts b/cypress/integration/browse-by-author.spec.ts new file mode 100644 index 0000000000..07c20ad7c9 --- /dev/null +++ b/cypress/integration/browse-by-author.spec.ts @@ -0,0 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + +describe('Browse By Author', () => { + it('should pass accessibility tests', () => { + cy.visit('/browse/author'); + + // Wait for to be visible + cy.get('ds-browse-by-metadata-page').should('be.visible'); + + // Analyze for accessibility + testA11y('ds-browse-by-metadata-page'); + }); +}); diff --git a/cypress/integration/browse-by-dateissued.spec.ts b/cypress/integration/browse-by-dateissued.spec.ts new file mode 100644 index 0000000000..4d22420227 --- /dev/null +++ b/cypress/integration/browse-by-dateissued.spec.ts @@ -0,0 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + +describe('Browse By Date Issued', () => { + it('should pass accessibility tests', () => { + cy.visit('/browse/dateissued'); + + // Wait for to be visible + cy.get('ds-browse-by-date-page').should('be.visible'); + + // Analyze for accessibility + testA11y('ds-browse-by-date-page'); + }); +}); diff --git a/cypress/integration/browse-by-subject.spec.ts b/cypress/integration/browse-by-subject.spec.ts new file mode 100644 index 0000000000..89b791f03c --- /dev/null +++ b/cypress/integration/browse-by-subject.spec.ts @@ -0,0 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + +describe('Browse By Subject', () => { + it('should pass accessibility tests', () => { + cy.visit('/browse/subject'); + + // Wait for to be visible + cy.get('ds-browse-by-metadata-page').should('be.visible'); + + // Analyze for accessibility + testA11y('ds-browse-by-metadata-page'); + }); +}); diff --git a/cypress/integration/browse-by-title.spec.ts b/cypress/integration/browse-by-title.spec.ts new file mode 100644 index 0000000000..e4e027586a --- /dev/null +++ b/cypress/integration/browse-by-title.spec.ts @@ -0,0 +1,13 @@ +import { testA11y } from 'cypress/support/utils'; + +describe('Browse By Title', () => { + it('should pass accessibility tests', () => { + cy.visit('/browse/title'); + + // Wait for to be visible + cy.get('ds-browse-by-title-page').should('be.visible'); + + // Analyze for accessibility + testA11y('ds-browse-by-title-page'); + }); +}); diff --git a/cypress/integration/search-page.spec.ts b/cypress/integration/search-page.spec.ts index d124f16982..a2bfbe6a5b 100644 --- a/cypress/integration/search-page.spec.ts +++ b/cypress/integration/search-page.spec.ts @@ -1,3 +1,6 @@ +import { Options } from 'cypress-axe'; +import { testA11y } from 'cypress/support/utils'; + describe('Search Page', () => { // unique ID of the search form (for selecting specific elements below) const SEARCHFORM_ID = '#search-form'; @@ -16,4 +19,54 @@ describe('Search Page', () => { cy.get(SEARCHFORM_ID + ' button.search-button').click(); cy.url().should('include', 'query=' + encodeURI(queryString)); }); + + it('should pass accessibility tests', () => { + cy.visit('/search'); + + // tag must be loaded + cy.get('ds-search-page').should('exist'); + + // Click each filter toggle to open *every* filter + // (As we want to scan filter section for accessibility issues as well) + cy.get('.filter-toggle').click({ multiple: true }); + + // Analyze for accessibility issues + testA11y( + { + include: ['ds-search-page'], + exclude: [ + ['nouislider'] // Date filter slider is missing ARIA labels. Will be fixed by #1175 + ], + }, + { + rules: { + // Search filters fail these two "moderate" impact rules + 'heading-order': { enabled: false }, + 'landmark-unique': { enabled: false } + } + } as Options + ); + }); + + it('should pass accessibility tests in Grid view', () => { + cy.visit('/search'); + + // Click to display grid view + // TODO: These buttons should likely have an easier way to uniquely select + cy.get('#search-sidebar-content > ds-view-mode-switch > .btn-group > [href="/search?spc.sf=score&spc.sd=DESC&view=grid"] > .fas').click(); + + // tag must be loaded + cy.get('ds-search-page').should('exist'); + + // Analyze for accessibility issues + testA11y('ds-search-page', + { + rules: { + // Search filters fail these two "moderate" impact rules + 'heading-order': { enabled: false }, + 'landmark-unique': { enabled: false } + } + } as Options + ); + }); }); From 8a1ff1ef70eaced1da16269a3f481f5f828948c9 Mon Sep 17 00:00:00 2001 From: Tim Donohue Date: Fri, 15 Oct 2021 16:03:43 -0500 Subject: [PATCH 5/5] Update to latest Cypress --- package.json | 2 +- yarn.lock | 14 ++++++++++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 87fdcb51f0..f6d7314243 100644 --- a/package.json +++ b/package.json @@ -152,7 +152,7 @@ "copy-webpack-plugin": "^6.4.1", "css-loader": "3.4.0", "cssnano": "^4.1.10", - "cypress": "8.4.0", + "cypress": "8.6.0", "cypress-axe": "^0.13.0", "deep-freeze": "0.0.1", "dotenv": "^8.2.0", diff --git a/yarn.lock b/yarn.lock index 5d6ba9f67f..7f5bd9b2f6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4153,10 +4153,10 @@ cypress-axe@^0.13.0: resolved "https://registry.yarnpkg.com/cypress-axe/-/cypress-axe-0.13.0.tgz#3234e1a79a27701f2451fcf2f333eb74204c7966" integrity sha512-fCIy7RiDCm7t30U3C99gGwQrUO307EYE1QqXNaf9ToK4DVqW8y5on+0a/kUHMrHdlls2rENF6TN9ZPpPpwLrnw== -cypress@8.4.0: - version "8.4.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.4.0.tgz#09ec06a73f1cb10121c103cba15076e659e24876" - integrity sha512-RtVgGFR06ikyMaq/VqapeqOjGaIA42PpK7F0qe1MCiFArfUuJECsLmeYaOA+1TlmNUgJNMSF5fWKkZIJr5Uc7w== +cypress@8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-8.6.0.tgz#8d02fa58878b37cfc45bbfce393aa974fa8a8e22" + integrity sha512-F7qEK/6Go5FsqTueR+0wEw2vOVKNgk5847Mys8vsWkzPoEKdxs+7N9Y1dit+zhaZCLtMPyrMwjfA53ZFy+lSww== dependencies: "@cypress/request" "^2.88.6" "@cypress/xvfb" "^1.2.4" @@ -4192,6 +4192,7 @@ cypress@8.4.0: minimist "^1.2.5" ospath "^1.2.2" pretty-bytes "^5.6.0" + proxy-from-env "1.0.0" ramda "~0.27.1" request-progress "^3.0.0" supports-color "^8.1.1" @@ -9839,6 +9840,11 @@ proxy-addr@~2.0.5: forwarded "~0.1.2" ipaddr.js "1.9.1" +proxy-from-env@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.0.0.tgz#33c50398f70ea7eb96d21f7b817630a55791c7ee" + integrity sha1-M8UDmPcOp+uW0h97gXYwpVeRx+4= + prr@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"