From b33cb03a8c589a51fcd11da795757ab47a94c5b3 Mon Sep 17 00:00:00 2001 From: Richard Marsot Date: Fri, 22 Mar 2024 19:00:36 -0400 Subject: [PATCH] Automatically run accessibility tests on each PR run --- .storybook/main.ts | 2 +- .storybook/preview.tsx | 17 ++-- .storybook/test-runner.ts | 32 +++++++ package-lock.json | 87 +++++++++++++++++++ package.json | 2 + .../Pega_Extensions_Calendar/index.tsx | 24 ++++- .../demo.stories.tsx | 17 ++++ .../demo.stories.tsx | 17 ++++ .../demo.stories.tsx | 13 +++ .../demo.stories.tsx | 13 +++ .../Pega_Extensions_Scheduler/index.tsx | 3 +- .../Pega_Extensions_Scheduler/styles.ts | 4 +- .../demo.stories.tsx | 13 +++ 13 files changed, 230 insertions(+), 14 deletions(-) create mode 100644 .storybook/test-runner.ts diff --git a/.storybook/main.ts b/.storybook/main.ts index 19b3d64..36e0119 100644 --- a/.storybook/main.ts +++ b/.storybook/main.ts @@ -7,7 +7,7 @@ const config: StorybookConfig = { framework: '@storybook/react-webpack5', staticDirs: ['./static'], stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'], - addons: ['@storybook/addon-essentials'], + addons: ['@storybook/addon-a11y', '@storybook/addon-essentials'], docs: { autodocs: true }, diff --git a/.storybook/preview.tsx b/.storybook/preview.tsx index 0a09e11..4550ef1 100644 --- a/.storybook/preview.tsx +++ b/.storybook/preview.tsx @@ -11,7 +11,6 @@ import { ModalManager, PopoverManager, Toaster, - LiveLog, Aries2023Theme, Aries2023DarkTheme, ThemeMachine, @@ -74,15 +73,13 @@ const preview: Preview = { disableDefaultFontLoading id='Preview' > - - - - - - - - - + + + + + + + ); }, diff --git a/.storybook/test-runner.ts b/.storybook/test-runner.ts new file mode 100644 index 0000000..aff550a --- /dev/null +++ b/.storybook/test-runner.ts @@ -0,0 +1,32 @@ +import type { TestRunnerConfig } from '@storybook/test-runner'; +import { getStoryContext } from '@storybook/test-runner'; + +import { injectAxe, checkA11y, configureAxe } from 'axe-playwright'; + +/* + * See https://storybook.js.org/docs/writing-tests/test-runner#test-hook-api + * to learn more about the test-runner hooks API. + */ +const config: TestRunnerConfig = { + async preVisit(page) { + await injectAxe(page); + }, + async postVisit(page, context) { + // Get the entire context of a story, including parameters, args, argTypes, etc. + const storyContext = await getStoryContext(page, context); + + // Apply story-level a11y rules + await configureAxe(page, { + rules: storyContext.parameters?.a11y?.config?.rules + }); + + await checkA11y(page, '#storybook-root', { + detailedReport: true, + detailedReportOptions: { + html: true + } + }); + } +}; + +export default config; diff --git a/package-lock.json b/package-lock.json index 56262d0..3d0276b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -37,6 +37,7 @@ "@pega/eslint-config": "^0.7.1", "@pega/pcore-pconnect-typedefs": "^2.1.1", "@pega/tsconfig": "^0.7.1", + "@storybook/addon-a11y": "^7.6.8", "@storybook/addon-essentials": "^7.6.8", "@storybook/manager-api": "^7.6.8", "@storybook/react": "^7.6.16", @@ -51,6 +52,7 @@ "@types/react-dom": "^17.0.25", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^7.0.1", + "axe-playwright": "^2.0.1", "cspell": "^8.3.2", "cspell-dict-lorem-ipsum": "^1.1.2", "eslint": "^8.4.1", @@ -6842,6 +6844,20 @@ "@sinonjs/commons": "^3.0.0" } }, + "node_modules/@storybook/addon-a11y": { + "version": "7.6.17", + "resolved": "https://registry.npmjs.org/@storybook/addon-a11y/-/addon-a11y-7.6.17.tgz", + "integrity": "sha512-UYHJAKQpJMCu4X4O/325UqozYrkhPn2VyQdwPgC+uiOKZvrtni4uRbpOspeyjC0wXH1tDbY8WZvxwvwQryYkpA==", + "dev": true, + "dependencies": { + "@storybook/addon-highlight": "7.6.17", + "axe-core": "^4.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/storybook" + } + }, "node_modules/@storybook/addon-actions": { "version": "7.6.17", "resolved": "https://registry.npmjs.org/@storybook/addon-actions/-/addon-actions-7.6.17.tgz", @@ -9634,6 +9650,12 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/junit-report-builder": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/junit-report-builder/-/junit-report-builder-3.0.2.tgz", + "integrity": "sha512-R5M+SYhMbwBeQcNXYWNCZkl09vkVfAtcPIaCGdzIkkbeaTrVbGQ7HVgi4s+EmM/M1K4ZuWQH0jGcvMvNePfxYA==", + "dev": true + }, "node_modules/@types/lodash": { "version": "4.17.0", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.0.tgz", @@ -11295,6 +11317,38 @@ "node": ">=4" } }, + "node_modules/axe-html-reporter": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/axe-html-reporter/-/axe-html-reporter-2.2.3.tgz", + "integrity": "sha512-io8aCEt4fJvv43W+33n3zEa8rdplH5Ti2v5fOnth3GBKLhLHarNs7jj46xGfpnGnpaNrz23/tXPHC3HbwTzwwA==", + "dev": true, + "dependencies": { + "mustache": "^4.0.1", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=8.9.0" + }, + "peerDependencies": { + "axe-core": ">=3" + } + }, + "node_modules/axe-playwright": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/axe-playwright/-/axe-playwright-2.0.1.tgz", + "integrity": "sha512-MHjNjGARulF9XzqSfspmNjw+tpBz4x9o1VlTuLWEUW9fqzhn+xWa1qEpuOIQPbsRWQiLfooDjQAunLeE0PM5AQ==", + "dev": true, + "dependencies": { + "@types/junit-report-builder": "^3.0.0", + "axe-core": "^4.5.1", + "axe-html-reporter": "2.2.3", + "junit-report-builder": "^3.0.1", + "picocolors": "^1.0.0" + }, + "peerDependencies": { + "playwright": ">1.0.0" + } + }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", @@ -14254,6 +14308,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/date-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", + "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/debug": { "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", @@ -23260,6 +23323,21 @@ "node": ">=4.0" } }, + "node_modules/junit-report-builder": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/junit-report-builder/-/junit-report-builder-3.2.1.tgz", + "integrity": "sha512-IMCp5XyDQ4YESDE4Za7im3buM0/7cMnRfe17k2X8B05FnUl9vqnaliX6cgOEmPIeWKfJrEe/gANRq/XgqttCqQ==", + "dev": true, + "dependencies": { + "date-format": "4.0.3", + "lodash": "^4.17.21", + "make-dir": "^3.1.0", + "xmlbuilder": "^15.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -35957,6 +36035,15 @@ "node": ">=12" } }, + "node_modules/xmlbuilder": { + "version": "15.1.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-15.1.1.tgz", + "integrity": "sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==", + "dev": true, + "engines": { + "node": ">=8.0" + } + }, "node_modules/xmlchars": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", diff --git a/package.json b/package.json index 1e4af4a..189b2df 100644 --- a/package.json +++ b/package.json @@ -65,6 +65,7 @@ "@pega/eslint-config": "^0.7.1", "@pega/pcore-pconnect-typedefs": "^2.1.1", "@pega/tsconfig": "^0.7.1", + "@storybook/addon-a11y": "^7.6.8", "@storybook/addon-essentials": "^7.6.8", "@storybook/manager-api": "^7.6.8", "@storybook/react": "^7.6.16", @@ -79,6 +80,7 @@ "@types/react-dom": "^17.0.25", "@types/styled-components": "^5.1.26", "@typescript-eslint/eslint-plugin": "^7.0.1", + "axe-playwright": "^2.0.1", "cspell": "^8.3.2", "cspell-dict-lorem-ipsum": "^1.1.2", "eslint": "^8.4.1", diff --git a/src/components/Pega_Extensions_Calendar/index.tsx b/src/components/Pega_Extensions_Calendar/index.tsx index 8e577a8..9fea8e2 100644 --- a/src/components/Pega_Extensions_Calendar/index.tsx +++ b/src/components/Pega_Extensions_Calendar/index.tsx @@ -267,8 +267,30 @@ export default function PegaExtensionsCalendar(props: CalendarProps) { { + if (calendarRef) { + const cal: any = calendarRef.current; + const calendarAPI = cal.getApi(); + calendarAPI?.prev(); + } + } + }, + nextButton: { + text: 'Next', + click: () => { + if (calendarRef) { + const cal: any = calendarRef.current; + const calendarAPI = cal.getApi(); + calendarAPI?.next(); + } + } + } + }} headerToolbar={{ - left: 'prev,next', + left: 'prevButton,nextButton', center: 'title', right: `${VIEW_TYPE.MONTH},${VIEW_TYPE.WEEK},${VIEW_TYPE.DAY}` }} diff --git a/src/components/Pega_Extensions_DisplayAttachments/demo.stories.tsx b/src/components/Pega_Extensions_DisplayAttachments/demo.stories.tsx index abd02eb..bed7a0e 100644 --- a/src/components/Pega_Extensions_DisplayAttachments/demo.stories.tsx +++ b/src/components/Pega_Extensions_DisplayAttachments/demo.stories.tsx @@ -15,6 +15,23 @@ export default { } } }, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'list', + enabled: false + }, + { + id: 'nested-interactive', + enabled: false + } + ] + } + } + }, component: PegaExtensionsDisplayAttachments }; diff --git a/src/components/Pega_Extensions_KanbanBoard/demo.stories.tsx b/src/components/Pega_Extensions_KanbanBoard/demo.stories.tsx index 626ccff..91a17ec 100644 --- a/src/components/Pega_Extensions_KanbanBoard/demo.stories.tsx +++ b/src/components/Pega_Extensions_KanbanBoard/demo.stories.tsx @@ -27,6 +27,23 @@ export default { } } }, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'aria-allowed-role', + enabled: false + }, + { + id: 'nested-interactive', + enabled: false + } + ] + } + } + }, component: PegaExtensionsKanbanBoard }; diff --git a/src/components/Pega_Extensions_NetworkDiagram/demo.stories.tsx b/src/components/Pega_Extensions_NetworkDiagram/demo.stories.tsx index 3ae2040..10c4aac 100644 --- a/src/components/Pega_Extensions_NetworkDiagram/demo.stories.tsx +++ b/src/components/Pega_Extensions_NetworkDiagram/demo.stories.tsx @@ -15,6 +15,19 @@ export default { } } }, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'nested-interactive', + enabled: false + } + ] + } + } + }, component: PegaExtensionsNetworkDiagram }; diff --git a/src/components/Pega_Extensions_RatingLayout/demo.stories.tsx b/src/components/Pega_Extensions_RatingLayout/demo.stories.tsx index 557ca05..6ab8391 100644 --- a/src/components/Pega_Extensions_RatingLayout/demo.stories.tsx +++ b/src/components/Pega_Extensions_RatingLayout/demo.stories.tsx @@ -24,6 +24,19 @@ export default { } } }, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'aria-valid-attr-value', + enabled: false + } + ] + } + } + }, component: PegaExtensionsRatingLayout }; diff --git a/src/components/Pega_Extensions_Scheduler/index.tsx b/src/components/Pega_Extensions_Scheduler/index.tsx index 6ff013d..0a0e24e 100644 --- a/src/components/Pega_Extensions_Scheduler/index.tsx +++ b/src/components/Pega_Extensions_Scheduler/index.tsx @@ -80,7 +80,8 @@ const PegaExtensionsScheduler = (props: PegaExtensionsSchedulerProps) => { aria-label={description} style={{ wordBreak: 'break-all', - color: '#FFFFFF' + color: '#FFFFFF', + fontSize: '1rem' }} onPreview={() => { getPConnect().getActionsApi().showCasePreview(encodeURI(obj.InsKey), { diff --git a/src/components/Pega_Extensions_Scheduler/styles.ts b/src/components/Pega_Extensions_Scheduler/styles.ts index d027eeb..1b0188a 100644 --- a/src/components/Pega_Extensions_Scheduler/styles.ts +++ b/src/components/Pega_Extensions_Scheduler/styles.ts @@ -3,8 +3,9 @@ import styled, { css, createGlobalStyle } from 'styled-components'; export const StyledCardContent = styled.div(() => { return css` - background: red; + background: #cc0000; height: 100%; + font-size: 1rem; `; }); @@ -12,6 +13,7 @@ export const GlobalStyle = createGlobalStyle` :root { --fc-today-bg-color: none !important; --fc-event-border-color: none !important; + --fc-event-bg-color: #2778C8 !important; } `; diff --git a/src/components/Pega_Extensions_UtilityList/demo.stories.tsx b/src/components/Pega_Extensions_UtilityList/demo.stories.tsx index 6781ca0..0d4e51b 100644 --- a/src/components/Pega_Extensions_UtilityList/demo.stories.tsx +++ b/src/components/Pega_Extensions_UtilityList/demo.stories.tsx @@ -20,6 +20,19 @@ export default { } } }, + parameters: { + a11y: { + element: '#storybook-root', + config: { + rules: [ + { + id: 'list', + enabled: false + } + ] + } + } + }, component: PegaExtensionsUtilityList };