diff --git a/cfgov/tccp/jinja2/tccp/includes/card_list.html b/cfgov/tccp/jinja2/tccp/includes/card_list.html index d9eb192df1c..a697155ad82 100644 --- a/cfgov/tccp/jinja2/tccp/includes/card_list.html +++ b/cfgov/tccp/jinja2/tccp/includes/card_list.html @@ -51,9 +51,23 @@
{%- for card in cards %} + {%- set card_purchase_apr = apr_range( + card.purchase_apr_for_tier_min, + card.purchase_apr_for_tier_max, + asterisk=true + ) -%} + {%- set card_account_fee = currency( + card.annual_fee_estimated, + default=('See details' if card.annual_fee_estimated is none and card.periodic_fee_type else '$0') + ) -%} {%- set show_more = loop.index > 11 and ordering_by != 'product_name' -%}
Account fee
- {{ currency(card.annual_fee_estimated, default=('See details' if card.annual_fee_estimated is none and card.periodic_fee_type else '$0')) }} + {{ card_account_fee }}
diff --git a/cfgov/unprocessed/apps/tccp/css/main.less b/cfgov/unprocessed/apps/tccp/css/main.less index dc59233037a..e8b7cdd7664 100644 --- a/cfgov/unprocessed/apps/tccp/css/main.less +++ b/cfgov/unprocessed/apps/tccp/css/main.less @@ -91,6 +91,11 @@ padding: unit((20px / @base-font-size-px), rem); background-color: var(--teal-10); + a { + border-color: var(--pacific-mid-dark); + color: var(--pacific-mid-dark); + } + p { max-width: 100%; } diff --git a/cfgov/unprocessed/apps/tccp/css/tooltip.less b/cfgov/unprocessed/apps/tccp/css/tooltip.less index 8fb2d61db9c..7b0923d7f9d 100644 --- a/cfgov/unprocessed/apps/tccp/css/tooltip.less +++ b/cfgov/unprocessed/apps/tccp/css/tooltip.less @@ -1,58 +1,16 @@ @import (css) '../node_modules/tippy.js/dist/tippy.css'; +@import (css) '../node_modules/tippy.js/dist/border.css'; -// Custom theme, see https://kabbouchi.github.io/tippyjs-v4-docs/themes/ +// Custom theme, see https://atomiks.github.io/tippyjs/v6/themes/ .tippy-box[data-theme='cfpb'] { background-color: var(--gray-5); - background-clip: padding-box; border: 1px solid var(--gray-40); border-radius: 0; color: var(--black); padding: unit((15px / @base-font-size-px), rem); - &[data-placement^='top'] > .tippy-arrow { - &::before { - border-top-color: var(--white); - } - &::after { - border-top-color: rgba(0, 8, 16, 20%); - border-width: 7px 7px 0; - top: 17px; - left: 1px; - } - } - - &[data-placement^='top'] > .tippy-svg-arrow > svg { - top: 16px; - } - - &[data-placement^='top'] > .tippy-svg-arrow::after { - top: 17px; - } - - > .tippy-backdrop { - background-color: var(--white); - } - - > .tippy-arrow::after, - > .tippy-svg-arrow::after { - content: ''; - position: absolute; - z-index: -1; - } - - > .tippy-arrow::after { - border-color: transparent; - border-style: solid; - } - - > .tippy-svg-arrow { - fill: var(--white); - &::after { - background-image: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4='); - background-size: 16px 6px; - width: 16px; - height: 6px; - } + .tippy-arrow { + color: var(--gray-5); } .tippy-heading { diff --git a/cfgov/unprocessed/apps/tccp/js/index.js b/cfgov/unprocessed/apps/tccp/js/index.js index 86600419fa8..8da2b8ab029 100644 --- a/cfgov/unprocessed/apps/tccp/js/index.js +++ b/cfgov/unprocessed/apps/tccp/js/index.js @@ -43,6 +43,28 @@ function initializeTooltips() { container.appendChild(node); return container; }, + // See https://atomiks.github.io/tippyjs/v6/plugins/ + plugins: [ + { + name: 'hideOnEsc', + defaultValue: true, + fn({ hide }) { + function onKeyDown(event) { + if (event.keyCode === 27) { + hide(); + } + } + return { + onShow() { + document.addEventListener('keydown', onKeyDown); + }, + onHide() { + document.removeEventListener('keydown', onKeyDown); + }, + }; + }, + }, + ], }); } diff --git a/npm-packages-offline-cache/axe-core-4.9.1.tgz b/npm-packages-offline-cache/axe-core-4.9.1.tgz new file mode 100644 index 00000000000..71bf23cd5ec Binary files /dev/null and b/npm-packages-offline-cache/axe-core-4.9.1.tgz differ diff --git a/npm-packages-offline-cache/cypress-axe-1.5.0.tgz b/npm-packages-offline-cache/cypress-axe-1.5.0.tgz new file mode 100644 index 00000000000..fcd3a10b09f Binary files /dev/null and b/npm-packages-offline-cache/cypress-axe-1.5.0.tgz differ diff --git a/package.json b/package.json index 6e5c856e2ce..2cf4a5d74b0 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,9 @@ "@cfpb/cfpb-typography": "1.3.2", "@cypress/skip-test": "2.6.1", "autoprefixer": "10.4.19", + "axe-core": "4.9.1", "cfpb-chart-builder": "6.5.0", + "cypress-axe": "1.5.0", "esbuild": "0.23.0", "fancy-log": "2.0.0", "highcharts": "7.2.2", diff --git a/test/cypress/integration/consumer-tools/credit-cards/explore-cards-helpers.cy.js b/test/cypress/integration/consumer-tools/credit-cards/explore-cards-helpers.cy.js index 5fae2ea32bb..c889308bba1 100644 --- a/test/cypress/integration/consumer-tools/credit-cards/explore-cards-helpers.cy.js +++ b/test/cypress/integration/consumer-tools/credit-cards/explore-cards-helpers.cy.js @@ -79,4 +79,9 @@ export class ExploreCreditCards { selectCheckboxFilter(name, value) { cy.get(`input[name=${name}]`).check(value, { force: true }); } + + checkA11y() { + cy.injectAxe(); + cy.checkA11y(); + } } diff --git a/test/cypress/integration/consumer-tools/credit-cards/explore-cards.cy.js b/test/cypress/integration/consumer-tools/credit-cards/explore-cards.cy.js index d17363eb3c4..82adada82f5 100644 --- a/test/cypress/integration/consumer-tools/credit-cards/explore-cards.cy.js +++ b/test/cypress/integration/consumer-tools/credit-cards/explore-cards.cy.js @@ -13,6 +13,7 @@ describe('Explore credit cards landing page', () => { exploreCards.openFilterExpandable(); cy.get('#id_rewards input').should('be.checked'); + exploreCards.checkA11y(); }); it("should show an error message if a location isn't selected", () => { @@ -24,6 +25,7 @@ describe('Explore credit cards landing page', () => { exploreCards.clickSubmitButton(); cy.get('.a-form-alert__text').should('be.visible'); + exploreCards.checkA11y(); exploreCards.selectLocation('NY'); @@ -45,13 +47,23 @@ describe('Explore credit cards results page', () => { it('should not follow card links when tooltips are clicked', () => { exploreCards.openResultsPage(); - cy.get('.m-card--tabular [data-tooltip]').first().click(); + cy.get('.m-card--tabular [data-tooltip]').first().trigger('mouseenter'); cy.get('h1').contains('Explore credit cards').should('exist'); cy.get('h2') .contains('Purchase interest rate and fees') .should('not.exist'); }); + it('should close tooltips when escape key is pressed', () => { + exploreCards.openResultsPage(); + + cy.get('.m-card--tabular [data-tooltip]').first().trigger('mouseenter'); + cy.get('div.tippy-heading').should('be.visible'); + + cy.get('.m-card--tabular [data-tooltip]').first().type('{esc}'); + cy.wait(1000); + cy.get('div.tippy-heading').should('not.exist'); + }); it('should not follow card links when tooltips are open', () => { exploreCards.openResultsPage(); @@ -92,6 +104,7 @@ describe('Explore credit cards results page', () => { exploreCards.selectOrdering('Purchase APR'); cy.get('.htmx-container.htmx-request').should('not.exist'); cy.get('#u-show-more-fade').should('be.visible'); + exploreCards.checkA11y(); exploreCards.selectOrdering('Card name'); cy.get('.htmx-container.htmx-request').should('not.exist'); @@ -159,6 +172,7 @@ describe('Explore credit card details page', () => { .and('contain', 'credit_tier=Credit+score+of+720+or+greater') .and('contain', 'location=NY') .and('contain', 'situations=Earn+rewards'); + exploreCards.checkA11y(); }); it('should have a breadcrumb to full list if the user never filtered', () => { exploreCards.openResultsPage(); diff --git a/test/cypress/support/e2e.js b/test/cypress/support/e2e.js index dc37e4f826a..b123d3832c4 100644 --- a/test/cypress/support/e2e.js +++ b/test/cypress/support/e2e.js @@ -27,3 +27,6 @@ require('@cypress/skip-test/support'); // Fail Cypress tests fast on the first failure. import 'cypress-fail-fast'; + +// Initialize a11y plugin https://github.com/component-driven/cypress-axe +import 'cypress-axe'; diff --git a/yarn.lock b/yarn.lock index 14054623637..5b67d2741fa 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1478,6 +1478,11 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== +axe-core@4.9.1: + version "4.9.1" + resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.9.1.tgz#fcd0f4496dad09e0c899b44f6c4bb7848da912ae" + integrity sha512-QbUdXJVTpvUTHU7871ppZkdOLBeGUKBQWHkHrvN2V9IQWGMt61zf3B45BtzjxEJzYuj0JBjBZP/hmYS/R9pmAw== + axe-core@=4.7.0: version "4.7.0" resolved "https://registry.yarnpkg.com/axe-core/-/axe-core-4.7.0.tgz#34ba5a48a8b564f67e103f0aa5768d76e15bbbbf" @@ -1952,6 +1957,11 @@ cssstyle@^2.3.0: dependencies: cssom "~0.3.6" +cypress-axe@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/cypress-axe/-/cypress-axe-1.5.0.tgz#95082734583da77b51ce9b7784e14a442016c7a1" + integrity sha512-Hy/owCjfj+25KMsecvDgo4fC/781ccL+e8p+UUYoadGVM2ogZF9XIKbiM6KI8Y3cEaSreymdD6ZzccbI2bY0lQ== + cypress-fail-fast@7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/cypress-fail-fast/-/cypress-fail-fast-7.1.0.tgz#36e28e39fffaacf852b4866c8459e5274eb8326d"