From a45d9e6600e7a253fdc1ab0fa0b6f14a3e4960ca Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 23 Jun 2025 08:29:56 -0400 Subject: [PATCH 01/27] update supported providers for the Results API --- docs/accessibility/results-api.mdx | 70 +++++++++++++++++++++++++++++- docs/ui-coverage/results-api.mdx | 60 +++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 1 deletion(-) diff --git a/docs/accessibility/results-api.mdx b/docs/accessibility/results-api.mdx index 76da044dd7..baefe6b80c 100644 --- a/docs/accessibility/results-api.mdx +++ b/docs/accessibility/results-api.mdx @@ -34,6 +34,7 @@ Fetching Accessibility results for a run supports fetching results for the follo - [GitLab](/app/continuous-integration/gitlab-ci) - [Jenkins](/app/continuous-integration/overview#Jenkins) - [AWS CodeBuild](/app/continuous-integration/aws-codebuild) +- Drone Please reach out to Cypress Support to request support for a different provider. @@ -59,6 +60,27 @@ If you check this in as a dependency, your installation will fail when we update Write a script using the `getAccessibilityResults` utility to retrieve the results and perform one or more assertions to verify if the changes are acceptable. This script will be executed in CI. +#### Basic example + +This snippet uses the `getAccessibilityResults()` helper to log out the results. It assumes your Project ID and Record Key variable are set. The following should work in any of the supported CI Providers out of the box: + +```javascript title="scripts/verifyAccessibilityResults.js" +// Assuming these environment variables are set: +// CYPRESS_PROJECT_ID=your-id +// CYPRESS_RECORD_KEY=your-record-key + +const { getAccessibilityResults } = require('@cypress/extract-cloud-results') + +getAccessibilityResults().then((results) => { + + // use `console.dir` instead of `console.log` because the data is nested + console.dir(results, { depth: Infinity }); + +}) +``` + +#### How to assert that only known rules are failing in the run + The Cypress App [repository](https://github.com/cypress-io/cypress) uses the Results API to ensure no new violations have been introduced. You can reference [this script](https://github.com/cypress-io/cypress/blob/develop/scripts/verify-accessibility-results.js) as a real example. ```javascript title="scripts/verifyAccessibilityResults.js" @@ -133,7 +155,28 @@ getAccessibilityResults({ }) ``` -#### `getAccessibilityResults` Arguments +#### How to use a previous run as a baseline + + +```javascript title="scripts/verifyAccessibilityResults.js" +// Assuming these environment variables are set: +// CYPRESS_PROJECT_ID=your-id +// CYPRESS_RECORD_KEY=your-record-key + +const { getAccessibilityResults } = require('@cypress/extract-cloud-results') + +getAccessibilityResults().then((results) => { + + // use `console.dir` instead of `console.log` + // to ensure nested data prints out correctly + console.dir(results, { depth: Infinity }); + +}) +``` + + + +### `getAccessibilityResults` Arguments `getAccessibilityResults` uses the following attributes to identify the Cypress run and return the Accessibility results: @@ -444,5 +487,30 @@ phases: + - CYPRESS_INTERNAL_ENV=staging CYPRESS_PROJECT_ID=[slug] CYPRESS_RECORD_KEY=[KEY] node ./scripts/verifyAccessibilityResults.js ``` + + + +```diff title=".drone.yaml" + kind: pipeline + name: default + + environment: + CYPRESS_PROJECT_ID: example_project_slug + CYPRESS_RECORD_KEY: + from_secret: example_record_key_secret + + steps: + - name: test + image: node:latest + commands: + - npm install + - npx cypress run --record + ++ - name: validate ++ image: node:latest ++ commands: ++ - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz ++ - node ./scripts/verifyAccessibilityResults.js +``` diff --git a/docs/ui-coverage/results-api.mdx b/docs/ui-coverage/results-api.mdx index 568a6ad9d6..ae7e839549 100644 --- a/docs/ui-coverage/results-api.mdx +++ b/docs/ui-coverage/results-api.mdx @@ -20,6 +20,8 @@ The utility supports the following CI providers. Refer to the linked guides for - [GitHub Actions](/app/continuous-integration/github-actions) - [GitLab](/app/continuous-integration/gitlab-ci) - [Jenkins](/app/continuous-integration/overview#Jenkins) +- [AWS CodeBuild](/app/continuous-integration/aws-codebuild) +- Drone For other CI providers, contact Cypress Support to request support. @@ -324,5 +326,63 @@ workflows: - run-cypress ``` + + + + +```diff title="buildspec.yaml" +phases: + install: + runtime-versions: + nodejs: latest + commands: + # Set COMMIT_INFO variables to send Git specifics to Cypress Cloud when recording + # https://docs.cypress.io/app/continuous-integration/overview#Git-information + - export COMMIT_INFO_BRANCH="$(git rev-parse HEAD | xargs git name-rev | + cut -d' ' -f2 | sed 's/remotes\/origin\///g')" + - export COMMIT_INFO_MESSAGE="$(git log -1 --pretty=%B)" + - export COMMIT_INFO_EMAIL="$(git log -1 --pretty=%ae)" + - export COMMIT_INFO_AUTHOR="$(git log -1 --pretty=%an)" + - export COMMIT_INFO_SHA="$(git log -1 --pretty=%H)" + - export COMMIT_INFO_REMOTE="$(git config --get remote.origin.url)" + - npm ci + pre_build: + commands: + - npm run cypress:verify + - npm run cypress:info + build: + commands: + - CYPRESS_INTERNAL_ENV=staging CYPRESS_PROJECT_ID=[slug] npx cypress run --record --key [KEY] ++ post_build: ++ commands: ++ - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz ++ - CYPRESS_INTERNAL_ENV=staging CYPRESS_PROJECT_ID=[slug] CYPRESS_RECORD_KEY=[KEY] node ./scripts/verifyUICoverageResults.js +``` + + + + +```diff title=".drone.yaml" + kind: pipeline + name: default + + environment: + CYPRESS_PROJECT_ID: example_project_slug + CYPRESS_RECORD_KEY: + from_secret: example_record_key_secret + + steps: + - name: test + image: node:latest + commands: + - npm install + - npx cypress run --record + ++ - name: validate ++ image: node:latest ++ commands: ++ - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz ++ - node ./scripts/verifyUICoverageResults.js +``` From b48706940fdcaf3d0ff4bec40210b7bc6568f979 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 30 Jun 2025 12:25:32 -0400 Subject: [PATCH 02/27] wip docs for Cypress rules --- .../core-concepts/cypress-rules.mdx | 27 ++++++++++++++++++ .../get-started/introduction.mdx | 1 - docs/ui-coverage/get-started/introduction.mdx | 1 - .../core-concepts/cypress-rule.png | Bin 0 -> 47900 bytes 4 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 docs/accessibility/core-concepts/cypress-rules.mdx create mode 100644 static/img/accessibility/core-concepts/cypress-rule.png diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx new file mode 100644 index 0000000000..2a09b28600 --- /dev/null +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -0,0 +1,27 @@ +--- +title: 'Cypress Rules | Cypress Documentation' +description: 'Review the main areas to pay attention to when first reviewing an accessibility report for a Cypress run.' +sidebar_position: 70 +sidebar_label: Cypress rules +sidebar_custom_props: { 'new_label': true } +--- + + + +# Cypress rules + +In addition to the default ruleset of the Axe-Core® library, we also develop custom rules that take advantage of the addition layer of information available in a test automation context. + +The first custom rule that we have implemented is called "Interactive elements must be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass or return an inconclusive state. + +## Interactive elements must be semantically correct + + + +This custom rule is intended to surface the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, even though users may threat them that way. + +This works based on the interactions that take place during testing. \ No newline at end of file diff --git a/docs/accessibility/get-started/introduction.mdx b/docs/accessibility/get-started/introduction.mdx index a6ae40b5eb..b257ab948a 100644 --- a/docs/accessibility/get-started/introduction.mdx +++ b/docs/accessibility/get-started/introduction.mdx @@ -3,7 +3,6 @@ sidebar_label: Introduction title: 'Accessibility Testing | Cypress Documentation' description: 'Cypress Accessibility provides organized, visual, and actionable accessibility reports, based completely on the tests you record to Cypress Cloud, and powered by Axe Core® by Deque Systems.' sidebar_position: 10 -sidebar_custom_props: { 'new_label': true } --- diff --git a/docs/ui-coverage/get-started/introduction.mdx b/docs/ui-coverage/get-started/introduction.mdx index 241a0c4510..d60786f473 100644 --- a/docs/ui-coverage/get-started/introduction.mdx +++ b/docs/ui-coverage/get-started/introduction.mdx @@ -3,7 +3,6 @@ title: 'Test coverage with UI Coverage | Cypress Documentation' description: 'Increase your test coverage with UI Coverage, a visual test coverage report based on the interactive elements that make up your application.' sidebar_label: Introduction sidebar_position: 10 -sidebar_custom_props: { 'new_label': true } --- diff --git a/static/img/accessibility/core-concepts/cypress-rule.png b/static/img/accessibility/core-concepts/cypress-rule.png new file mode 100644 index 0000000000000000000000000000000000000000..2d64614799aa08b42809f8ea7668791d48d72427 GIT binary patch literal 47900 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 z

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 Date: Mon, 30 Jun 2025 21:39:32 -0400 Subject: [PATCH 03/27] add detail, update changelog --- docs/accessibility/changelog.mdx | 14 +++++ .../core-concepts/cypress-rules.mdx | 60 ++++++++++++++++++- 2 files changed, 71 insertions(+), 3 deletions(-) diff --git a/docs/accessibility/changelog.mdx b/docs/accessibility/changelog.mdx index cf1cf4c14c..7223acd097 100644 --- a/docs/accessibility/changelog.mdx +++ b/docs/accessibility/changelog.mdx @@ -9,6 +9,20 @@ sidebar_position: 200 # Changelog +## Week of 6/2/2025 + +- We now support fetching Accessibility results from Drone CI with the [Results API](/accessibility/results-api). + +## Week of 5/26/2025 + +- A new [element identification](/accessibility/configuration/element-identification) algorithm is now available for Cypress Accessibility. This produces improved element deduplication across different snapshots and runs, and incorporates testing-specific attributes like Test IDs into the element recognition and deduplication process. This replaces the default Axe-Core® element identification behavior. +- Two new configuration options are available in Cypress Accessibility - [`significantAttributes`](/accessibility/configuration/significant-attributes) and [`attributeFilters`](/accessibility/configuration/attribute-filters). These allow you to fine-tune Cypress's element identification behavior to ensure stable and relevant locators are used. +- Branch Review for Cypress Accessibility is now generally available, with an updated interface for displaying new and resolved violations, based on feedback during the Beta period. Thank you all for hitting the feedback button! [Learn more about comparing reports](/accessibility/core-concepts/compare-reports). + +## Week of 5/12/2025 + +- We now support fetching Accessibility results from AWS CodeBuild with the [Results API](/accessibility/results-api). + ## Week of 3/24/2025 - Cypress Accessibility results are now included in the [Data Extract API](/cloud/integrations/data-extract-api) so that you can retrieve data over time. diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 2a09b28600..15a96547f9 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -10,18 +10,72 @@ sidebar_custom_props: { 'new_label': true } # Cypress rules -In addition to the default ruleset of the Axe-Core® library, we also develop custom rules that take advantage of the addition layer of information available in a test automation context. +In addition to running the default ruleset of the Axe-Core® library, we also create custom rules that take advantage of the addition layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. The first custom rule that we have implemented is called "Interactive elements must be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass or return an inconclusive state. ## Interactive elements must be semantically correct +**Rule ID**: `semantic-html-warning` + -This custom rule is intended to surface the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, even though users may threat them that way. +This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements. + +This works based on the interactions that take place during testing. Often an inaccessible custom component will have Cypress tests that perform interactions the way a user does, and that allows us to detect a mismatch between the underlying purpose of the element in code, and the usage of the element in the context of a test. + +### How to pass this rule + +You should look at the purpose and nature of the specific elements flagged by this rule and decide what interactive element is appropriate for the interactions that a user can do and the effects of the interaction. + +For example, if the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be standard html button element. But if the same element was styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct element is a link. + +The goal of this rule is not to propose the correct element for your scenarios, but to surface the elements that need attention so that you can make this decision. After that, with appropriate semantics in place, the elements will then be able to be correctly parsed and analyzed by the standard Axe-Core® checks. + +:::info +**Tip**: We recommend following the [first rule of ARIA use](https://www.w3.org/TR/using-aria/#firstrule) and implementing interactive controls with standard semantic HTML where possible, relying on ARIA `role` attributes only when no suitable HTML element is available. +::: + + +### Why this matters + +In the Web Content Accessibility Guidelines (WCAG), interactive elements are required to met a wide range of Success Criteria (SCs) in order to follow the POUR principles, which stands for Perceivable, Operable, Understandable, and Robust. + +Interactive elements that are not semantically correct often don't appear in automated scans, but do appear in manual testing, because they are usually not operable with a keyboard or correctly understandable when described by a screen reader. + +Custom components implemented this way have a direct impact on the independence of your disabled users. + +### Related WCAG Success Criteria + +An incorrectly implemented interactive element may be failing multiple Success Criteria from WCAG, for example: + +- [SC 1.3.1 Info and Relationships](https://www.w3.org/TR/WCAG21/#info-and-relationships) +- [SC 2.1.1 Keyboard](https://www.w3.org/TR/WCAG21/#keyboard) +- [SC 4.1.2 Name, Role, Value](https://www.w3.org/TR/WCAG21/#name-role-value) + +### Status + +This rule is available in all Cypress Accessibility projects, though it is not turned on by default at launch. Reach out to Cypress if you would like to have this rule activated for you early. + +### Possible outcomes + +For each run, this rule can be in one of four states. Most importantly, it will never fail, which means it will not affect your accessibility score. + + +| Outcome | Description | +|---------|-------------| +| **Pass** | No interactive elements with semantic issues were detected during the test run. | +| **Inconclusive** | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. | +| **Not Applicable** | The test run did not interact with any elements. | +| **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off. | + + +### False positives + +We expect a certain number of false positives to be detected during the initial rollout. If you see these, please use the "Submit Feedback" button in the product to let us know. Our goal is to follow the general Axe-Core® philosophy that minimizes false positives. + -This works based on the interactions that take place during testing. \ No newline at end of file From b46c8fed078da9af5cd5e0e792d5c628be18a292 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 30 Jun 2025 21:48:07 -0400 Subject: [PATCH 04/27] changelog updates --- docs/accessibility/changelog.mdx | 4 ++-- docs/ui-coverage/changelog.mdx | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/docs/accessibility/changelog.mdx b/docs/accessibility/changelog.mdx index 7223acd097..9f245b5ebd 100644 --- a/docs/accessibility/changelog.mdx +++ b/docs/accessibility/changelog.mdx @@ -15,8 +15,8 @@ sidebar_position: 200 ## Week of 5/26/2025 -- A new [element identification](/accessibility/configuration/element-identification) algorithm is now available for Cypress Accessibility. This produces improved element deduplication across different snapshots and runs, and incorporates testing-specific attributes like Test IDs into the element recognition and deduplication process. This replaces the default Axe-Core® element identification behavior. -- Two new configuration options are available in Cypress Accessibility - [`significantAttributes`](/accessibility/configuration/significant-attributes) and [`attributeFilters`](/accessibility/configuration/attribute-filters). These allow you to fine-tune Cypress's element identification behavior to ensure stable and relevant locators are used. +- A new [element identification](/accessibility/core-concepts/element-identification) algorithm is now available for Cypress Accessibility. This produces improved element deduplication across different snapshots and runs, and incorporates testing-specific attributes like Test IDs into the element recognition and deduplication process. This replaces the default Axe-Core® element identification behavior. +- Two new configuration options are available in Cypress Accessibility - [`significantAttributes`](/accessibility/configuration/significantattributes) and [`attributeFilters`](/accessibility/configuration/attributefilters). These allow you to fine-tune Cypress's element identification behavior to ensure stable and relevant locators are used. - Branch Review for Cypress Accessibility is now generally available, with an updated interface for displaying new and resolved violations, based on feedback during the Beta period. Thank you all for hitting the feedback button! [Learn more about comparing reports](/accessibility/core-concepts/compare-reports). ## Week of 5/12/2025 diff --git a/docs/ui-coverage/changelog.mdx b/docs/ui-coverage/changelog.mdx index 2dc779bbd9..6df262263d 100644 --- a/docs/ui-coverage/changelog.mdx +++ b/docs/ui-coverage/changelog.mdx @@ -16,10 +16,18 @@ UI Coverage now supports defining custom commands that will count towards covera - [`additionalInteractionCommands`](/ui-coverage/configuration/additionalinteractioncommands) - [`allowedInteractionCommands`](/ui-coverage/configuration/allowedinteractioncommands) +## Week of 6/2/2025 + +- We now support fetching UI Coverage results from Drone CI with the [Results API](/ui-coverage/results-api). + ## Week of 5/26/2025 - Launched AI-powered Test Generation in Cypress Cloud, to help you quickly add tests for the untested elements detected in UI Coverage reports, in a way that follows your existing practices and conventions. For more details, read [our blog post](https://www.cypress.io/blog/add-your-missing-tests-faster-with-test-generation-in-ui-coverage). +## Week of 5/12/2025 + +- We now support fetching UI Coverage results from AWS CodeBuild with the [Results API](/ui-coverage/results-api). + ## Week of 4/1/2024 - **Shadow DOM and iFrame Support:** UI Coverage now supports Shadow DOM and iFrames for reporting on interactions. Both of these settings are off by default. Please contact your Cypress representative to opt in. From b44267c321ccb16e9ac15d1ca31e8c150335ec96 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 30 Jun 2025 22:51:48 -0400 Subject: [PATCH 05/27] improve alt text --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 15a96547f9..5132041730 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -21,7 +21,7 @@ The first custom rule that we have implemented is called "Interactive elements m This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements. From 95c8f830b944deda0fc5e86c38de479ed52055e1 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 7 Jul 2025 08:17:21 -0400 Subject: [PATCH 06/27] update wording for website crawling --- docs/accessibility/guides/production-monitoring.mdx | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/accessibility/guides/production-monitoring.mdx b/docs/accessibility/guides/production-monitoring.mdx index a8f03ba38d..2f11d4eabb 100644 --- a/docs/accessibility/guides/production-monitoring.mdx +++ b/docs/accessibility/guides/production-monitoring.mdx @@ -1,5 +1,5 @@ --- -sidebar_label: Production monitoring +sidebar_label: Production monitoring and website crawling title: 'Production monitoring | Cypress Accessibility Documentation' description: 'Monitor accessibility issues in production by running scheduled Cypress tests against live environments, capturing dynamic content changes, and generating automated reports for a comprehensive accessibility overview.' sidebar_position: 60 @@ -7,13 +7,13 @@ sidebar_position: 60 -# Production monitoring +# Production monitoring and website crawling -Cypress is commonly used in CI and local development workflows. It can also be leveraged to monitor production or staging environments through scheduled tests. This approach is particularly useful for environments involving dynamic content, such as those managed by Content Management Systems (CMS), where content changes can impact accessibility. +Cypress is commonly used in CI and local development workflows. It can also be used to monitor production or staging environments through scheduled tests. This approach is particularly useful for environments involving dynamic content, such as those managed by Content Management Systems (CMS), where content changes can impact accessibility. Dynamic or externally controlled content, such as A/B tests or user-generated content, often makes it challenging to write explicit assertions. For these cases, production smoke tests can serve as high-level health checks, ensuring the accessibility of dynamic UI variations without requiring full test coverage. -## Using Cypress for Production Monitoring +## Using Cypress for production monitoring Cypress Accessibility enables you to test dynamic content seamlessly. By visiting a production URL within your Cypress tests and performing minimal UI interactions, you can capture the page's accessibility state in reports. This allows teams to detect accessibility issues introduced outside the regular development lifecycle. @@ -34,6 +34,9 @@ describe('Accessibility Scan', () => { Cypress._.each(URLs, (URL) => { cy.visit(URL) cy.contains('').scrollIntoView() + // perform some repeatable actions here that influence accessibility, for example: + // - change from light mode to dark mode + // - modify the viewport size to simulate mobile screens and higher zoom levels }) }) }) From cd3860888dbaced292584c99fc234a64e32350f0 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 7 Jul 2025 08:17:29 -0400 Subject: [PATCH 07/27] tweaks --- .../core-concepts/cypress-rules.mdx | 24 ++++++++++++------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 5132041730..9334b74e8b 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -1,5 +1,5 @@ --- -title: 'Cypress Rules | Cypress Documentation' +title: 'Cypress Rules | Cypress Accessibility Documentation' description: 'Review the main areas to pay attention to when first reviewing an accessibility report for a Cypress run.' sidebar_position: 70 sidebar_label: Cypress rules @@ -12,11 +12,11 @@ sidebar_custom_props: { 'new_label': true } In addition to running the default ruleset of the Axe-Core® library, we also create custom rules that take advantage of the addition layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. -The first custom rule that we have implemented is called "Interactive elements must be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass or return an inconclusive state. +The first custom rule that we have implemented is called "Interactive elements must be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state. ## Interactive elements must be semantically correct -**Rule ID**: `semantic-html-warning` +**Rule ID**: `cd-semantic-html-warning` Date: Mon, 7 Jul 2025 11:38:49 -0400 Subject: [PATCH 08/27] lint fix --- .../core-concepts/cypress-rules.mdx | 23 ++++------ docs/accessibility/results-api.mdx | 46 +++++++++---------- docs/ui-coverage/results-api.mdx | 33 +++++++------ 3 files changed, 48 insertions(+), 54 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 9334b74e8b..d98d352d49 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -24,7 +24,7 @@ The first custom rule that we have implemented is called "Interactive elements m alt="A custom Cypress accessibility rule called 'Interactive elements must be semantically correct' has two failed elements displayed. One element is open and message reads 'This element should use semantic HTML or ARIA to support the interactions that take place during tests. Detected interactions: mousedown, mouseup, click." /> -This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements. +This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements. This works based on the interactions that take place during testing. Often an inaccessible custom component will have Cypress tests that perform interactions the way a user does, and that allows us to detect a mismatch between the underlying purpose of the element in code, and the usage of the element in the context of a test. @@ -34,9 +34,9 @@ You should look at the purpose and nature of the specific elements flagged by th For example: -* If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. +- If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. -* If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution is a link element with a `href` attribute. +- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution is a link element with a `href` attribute. In each case, the solution is to choose the element that provides the best information to the user, so they can independently understand what the action does, and activate it. @@ -70,18 +70,13 @@ This rule is available in all Cypress Accessibility projects, though it is not t For each run, this rule can be in one of four states. Most importantly, it will never fail, which means it will not affect your accessibility score. - -| Outcome | Description | -|---------|-------------| -| **Pass** | No interactive elements with semantic issues were detected during the test run. | -| **Inconclusive** | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. | -| **Not Applicable** | The test run did not interact with any elements. | -| **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off. | - +| Outcome | Description | +| ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | +| **Pass** | No interactive elements with semantic issues were detected during the test run. | +| **Inconclusive** | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. | +| **Not Applicable** | The test run did not interact with any elements. | +| **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off. | ### False positives We expect a certain number of false positives to be detected during the initial rollout. If you see these, please use the "Submit Feedback" button in the product to let us know. Our goal with any new rules is to follow the general Axe-Core® philosophy that minimizes false positives. - - - diff --git a/docs/accessibility/results-api.mdx b/docs/accessibility/results-api.mdx index baefe6b80c..d777a23572 100644 --- a/docs/accessibility/results-api.mdx +++ b/docs/accessibility/results-api.mdx @@ -72,10 +72,8 @@ This snippet uses the `getAccessibilityResults()` helper to log out the results. const { getAccessibilityResults } = require('@cypress/extract-cloud-results') getAccessibilityResults().then((results) => { - // use `console.dir` instead of `console.log` because the data is nested - console.dir(results, { depth: Infinity }); - + console.dir(results, { depth: Infinity }) }) ``` @@ -157,7 +155,6 @@ getAccessibilityResults({ #### How to use a previous run as a baseline - ```javascript title="scripts/verifyAccessibilityResults.js" // Assuming these environment variables are set: // CYPRESS_PROJECT_ID=your-id @@ -166,16 +163,12 @@ getAccessibilityResults({ const { getAccessibilityResults } = require('@cypress/extract-cloud-results') getAccessibilityResults().then((results) => { - - // use `console.dir` instead of `console.log` + // use `console.dir` instead of `console.log` // to ensure nested data prints out correctly - console.dir(results, { depth: Infinity }); - + console.dir(results, { depth: Infinity }) }) ``` - - ### `getAccessibilityResults` Arguments `getAccessibilityResults` uses the following attributes to identify the Cypress run and return the Accessibility results: @@ -494,23 +487,26 @@ phases: kind: pipeline name: default - environment: - CYPRESS_PROJECT_ID: example_project_slug - CYPRESS_RECORD_KEY: - from_secret: example_record_key_secret +environment: +CYPRESS_PROJECT_ID: example_project_slug +CYPRESS_RECORD_KEY: +from_secret: example_record_key_secret - steps: - - name: test - image: node:latest - commands: - - npm install - - npx cypress run --record +steps: + +- name: test + image: node:latest + commands: + - npm install + - npx cypress run --record + +* - name: validate +* image: node:latest +* commands: +* - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz +* - node ./scripts/verifyAccessibilityResults.js -+ - name: validate -+ image: node:latest -+ commands: -+ - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz -+ - node ./scripts/verifyAccessibilityResults.js ``` +``` diff --git a/docs/ui-coverage/results-api.mdx b/docs/ui-coverage/results-api.mdx index ae7e839549..8165212bdf 100644 --- a/docs/ui-coverage/results-api.mdx +++ b/docs/ui-coverage/results-api.mdx @@ -366,23 +366,26 @@ phases: kind: pipeline name: default - environment: - CYPRESS_PROJECT_ID: example_project_slug - CYPRESS_RECORD_KEY: - from_secret: example_record_key_secret +environment: +CYPRESS_PROJECT_ID: example_project_slug +CYPRESS_RECORD_KEY: +from_secret: example_record_key_secret - steps: - - name: test - image: node:latest - commands: - - npm install - - npx cypress run --record +steps: + +- name: test + image: node:latest + commands: + - npm install + - npx cypress run --record + +* - name: validate +* image: node:latest +* commands: +* - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz +* - node ./scripts/verifyUICoverageResults.js -+ - name: validate -+ image: node:latest -+ commands: -+ - npm install --force https://cdn.cypress.io/extract-cloud-results/v1/extract-cloud-results.tgz -+ - node ./scripts/verifyUICoverageResults.js ``` +``` From 72618dcc9c613da2b842c520633816af25772513 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Mon, 7 Jul 2025 17:33:56 -0400 Subject: [PATCH 09/27] fix typo in rule id --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index d98d352d49..dd95eae2cb 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -16,7 +16,7 @@ The first custom rule that we have implemented is called "Interactive elements m ## Interactive elements must be semantically correct -**Rule ID**: `cd-semantic-html-warning` +**Rule ID**: `cy-semantic-html-warning` Date: Mon, 7 Jul 2025 17:45:42 -0400 Subject: [PATCH 10/27] remove temp file --- docs/accessibility/core-concepts/cypress-rules.mdx | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index dd95eae2cb..0d8639ca32 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -59,12 +59,15 @@ Custom components implemented this way have a direct impact on the independence An incorrectly implemented interactive element may be failing multiple Success Criteria from WCAG, for example: - [SC 1.3.1 Info and Relationships](https://www.w3.org/TR/WCAG21/#info-and-relationships) + - Elements may incorrectly appear to be non-interactive generic elements - [SC 2.1.1 Keyboard](https://www.w3.org/TR/WCAG21/#keyboard) + - Non-interactive elements require custom implementations for keyboard accessibility and focus states - [SC 4.1.2 Name, Role, Value](https://www.w3.org/TR/WCAG21/#name-role-value) + - Non-interactive elements require explicit ARIA roles to have their function and name correctly described by assistive technology such as screen readers ### Status -This rule is available in all Cypress Accessibility projects, though it is not turned on by default at launch. Reach out to Cypress if you would like to have this rule activated for you early. +This rule is available in all Cypress Accessibility projects, though it is not turned on by default. Reach out to Cypress if you would like to have this rule activated for you early. ### Possible outcomes From 0d33a0c52ee7a9f36778dbe6aa40f335efe4dd36 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Mon, 7 Jul 2025 17:47:19 -0400 Subject: [PATCH 11/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 0d8639ca32..66bbf00636 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -34,7 +34,7 @@ You should look at the purpose and nature of the specific elements flagged by th For example: -- If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. +- If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be to instead use a standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. - If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution is a link element with a `href` attribute. From adede794d68622a60b6b00ebd959329486abcb88 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Mon, 7 Jul 2025 17:47:30 -0400 Subject: [PATCH 12/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 66bbf00636..d8251755c5 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -36,7 +36,7 @@ For example: - If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be to instead use a standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. -- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution is a link element with a `href` attribute. +- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution would be a link element with a `href` attribute. In each case, the solution is to choose the element that provides the best information to the user, so they can independently understand what the action does, and activate it. From c8d6bd740343cc567482308b55a3459cce0a4135 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Wed, 9 Jul 2025 10:27:06 -0400 Subject: [PATCH 13/27] fix a typo --- docs/cloud/account-management/users.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/cloud/account-management/users.mdx b/docs/cloud/account-management/users.mdx index 2dac3a45cf..3402e511d5 100644 --- a/docs/cloud/account-management/users.mdx +++ b/docs/cloud/account-management/users.mdx @@ -144,7 +144,7 @@ The permissions for each user role for Cypress Cloud: Cypress App users can "request" access to a given organization. If a developer on your team has access to Cypress and your project's source code - they can request -to be given access to your organization from within the Cypres App. This means +to be given access to your organization from within the Cypress App. This means instead of you having to invite team members up front, they can request access and you can choose to accept or deny them access. From 6fd74b7747ccfe8ca84555b9be8098e011a5278d Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Wed, 9 Jul 2025 10:27:14 -0400 Subject: [PATCH 14/27] update rule text --- docs/accessibility/core-concepts/cypress-rules.mdx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index d8251755c5..ee416e8e08 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -10,18 +10,18 @@ sidebar_custom_props: { 'new_label': true } # Cypress rules -In addition to running the default ruleset of the Axe-Core® library, we also create custom rules that take advantage of the addition layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. +In addition to running the default ruleset of the Axe-Core® library, Cypress develops custom rules that take advantage of the addition layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. -The first custom rule that we have implemented is called "Interactive elements must be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state. +The first custom rule that we have implemented is called "Interactive elements should be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state. -## Interactive elements must be semantically correct +## Interactive elements should be semantically correct **Rule ID**: `cy-semantic-html-warning` This custom rule is intended to surface potential usability problems with the kinds of elements that Axe-Core® traditionally does not evaluate as interactive, such as div, span, SVG, and image elements. From ae485fc82ece9a569e36ba6c5d5f86649b89ef41 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Wed, 9 Jul 2025 17:11:24 -0400 Subject: [PATCH 15/27] add more detail --- docs/accessibility/core-concepts/cypress-rules.mdx | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index ee416e8e08..a2c64ea263 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -17,6 +17,12 @@ The first custom rule that we have implemented is called "Interactive elements s ## Interactive elements should be semantically correct **Rule ID**: `cy-semantic-html-warning` +**Rule Tag**: `cypress-rule` +**Severity**: `serious` + +:::caution +This rule requires that runs be recorded using Cypress version 13.14.0 or above. +::: Date: Thu, 10 Jul 2025 13:34:32 -0400 Subject: [PATCH 16/27] add more detail --- docs/accessibility/core-concepts/cypress-rules.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index a2c64ea263..58ff13feb6 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -83,11 +83,11 @@ For each run, this rule can be in one of four states. Most importantly, it will | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | **Pass** | No interactive elements with semantic issues were detected during the test run. | | **Inconclusive** | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. | -| **Not Applicable** | The test run did not interact with any elements. | +| **Not Applicable** | The test run did not interact with any elements, or the version of Cypress was below 13.14.0, so interaction data was not gathered. | | **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off. | ### False positives -We expect a certain number of false positives to be detected during the initial rollout. If you see these, please use the "Submit Feedback" button in the product to let us know. Our goal with any new rules is to follow the general Axe-Core® philosophy that minimizes false positives. +Please use the "Submit Feedback" button in the product to let us know if you see something that you think is a false positive. Our goal with any new rules is to follow the general Axe-Core® philosophy that minimizes false positives, so we will make adjustments for specific situations that are not already known as we learn about them. + -There is also a possibility that your tests are interacting with non-interactive elements intentionally, for example to test some side effect on focus. From 05e7cbc90cd60f0126bfcb56365680fb1548d563 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Thu, 10 Jul 2025 14:15:31 -0400 Subject: [PATCH 17/27] lint fix --- docs/accessibility/core-concepts/cypress-rules.mdx | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 58ff13feb6..aab7ef4013 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -83,11 +83,9 @@ For each run, this rule can be in one of four states. Most importantly, it will | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- | | **Pass** | No interactive elements with semantic issues were detected during the test run. | | **Inconclusive** | Interactive elements with potential semantic issues were detected. You should review each element and determine the correct solution. | -| **Not Applicable** | The test run did not interact with any elements, or the version of Cypress was below 13.14.0, so interaction data was not gathered. | +| **Not Applicable** | The test run did not interact with any elements, or the version of Cypress was below 13.14.0, so interaction data was not gathered. | | **Ignored by configuration** | The rule was not executed during this test run because it was intentionally turned off. | ### False positives Please use the "Submit Feedback" button in the product to let us know if you see something that you think is a false positive. Our goal with any new rules is to follow the general Axe-Core® philosophy that minimizes false positives, so we will make adjustments for specific situations that are not already known as we learn about them. - - From 2fe30130ad3ddc4c7a5cd9165ec9ee1c628a6de6 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Thu, 10 Jul 2025 14:32:15 -0400 Subject: [PATCH 18/27] add more detail --- docs/accessibility/core-concepts/cypress-rules.mdx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index aab7ef4013..3e8c182256 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -16,9 +16,9 @@ The first custom rule that we have implemented is called "Interactive elements s ## Interactive elements should be semantically correct -**Rule ID**: `cy-semantic-html-warning` -**Rule Tag**: `cypress-rule` -**Severity**: `serious` +- **ID**: `cy-semantic-html-warning` +- **Tag**: `cypress-rule` +- **Severity**: `serious` :::caution This rule requires that runs be recorded using Cypress version 13.14.0 or above. From 993b19e343f7008dc41edec42a8cd51cdba16dbf Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 16:36:30 -0400 Subject: [PATCH 19/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 3e8c182256..4fa48eca0e 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -10,7 +10,7 @@ sidebar_custom_props: { 'new_label': true } # Cypress rules -In addition to running the default ruleset of the Axe-Core® library, Cypress develops custom rules that take advantage of the addition layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. +In addition to running the default ruleset of the Axe-Core® library, Cypress develops custom rules that take advantage of the additional layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. The first custom rule that we have implemented is called "Interactive elements should be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state. From 3b0dba28d33ff2259f1ffeb86bd8d96b4e6227a0 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 16:39:37 -0400 Subject: [PATCH 20/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 4fa48eca0e..299bc86d4b 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -42,7 +42,7 @@ For example: - If the element that gets flagged is a span that has been styled to look like a button and submits a form, the correct solution would be to instead use a standard HTML button element. This communicates the expected action and is activated with the space bar or enter key. -- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution would be a link element with a `href` attribute. +- If the same element is styled with underlined text, and when clicked it resets the URL to navigate to a new page, the correct solution would be to instead use a link element with a `href` attribute. In each case, the solution is to choose the element that provides the best information to the user, so they can independently understand what the action does, and activate it. From c0cf9bb6c1b55566d62a9b1576c90ae437f3f67f Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Thu, 10 Jul 2025 16:40:00 -0400 Subject: [PATCH 21/27] remove unfinished example --- docs/accessibility/results-api.mdx | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/docs/accessibility/results-api.mdx b/docs/accessibility/results-api.mdx index d777a23572..a55f6ffac5 100644 --- a/docs/accessibility/results-api.mdx +++ b/docs/accessibility/results-api.mdx @@ -153,22 +153,6 @@ getAccessibilityResults({ }) ``` -#### How to use a previous run as a baseline - -```javascript title="scripts/verifyAccessibilityResults.js" -// Assuming these environment variables are set: -// CYPRESS_PROJECT_ID=your-id -// CYPRESS_RECORD_KEY=your-record-key - -const { getAccessibilityResults } = require('@cypress/extract-cloud-results') - -getAccessibilityResults().then((results) => { - // use `console.dir` instead of `console.log` - // to ensure nested data prints out correctly - console.dir(results, { depth: Infinity }) -}) -``` - ### `getAccessibilityResults` Arguments `getAccessibilityResults` uses the following attributes to identify the Cypress run and return the Accessibility results: From 087bc82902673df28d834379259e9b2c3e9e6341 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Thu, 10 Jul 2025 16:51:40 -0400 Subject: [PATCH 22/27] changelog --- docs/accessibility/changelog.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/accessibility/changelog.mdx b/docs/accessibility/changelog.mdx index 9f245b5ebd..cb88a85e4e 100644 --- a/docs/accessibility/changelog.mdx +++ b/docs/accessibility/changelog.mdx @@ -9,6 +9,10 @@ sidebar_position: 200 # Changelog +## Week of 7/7/2025 + +- A new custom accessibility rule, ["Interactive elements should be semantically correct"](/accessibility/core-concepts/cypress-rules#Interactive-elements-should-be-semantically-correct), is now available. This rule is based on the interactions that take place during your test execution, and helps detect accessibility issues that are not a part of typical DOM-based accessibility scans. + ## Week of 6/2/2025 - We now support fetching Accessibility results from Drone CI with the [Results API](/accessibility/results-api). From e47a6e7bcca74c4b3f25a8ba291b0352f1792e51 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 16:52:05 -0400 Subject: [PATCH 23/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Jennifer Shehane --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 299bc86d4b..076b47afa4 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -54,7 +54,7 @@ After you have updated to a suitable HTML solution, elements will then be able t ### Why this matters -In the Web Content Accessibility Guidelines (WCAG), interactive elements are required to met a wide range of Success Criteria (SCs) in order to follow the POUR principles, which stands for Perceivable, Operable, Understandable, and Robust. +In the Web Content Accessibility Guidelines (WCAG), interactive elements are required to meet a wide range of Success Criteria (SCs) in order to follow the POUR principles, which stands for Perceivable, Operable, Understandable, and Robust. Interactive elements that are not semantically correct often don't appear in automated scans, but do appear in manual testing, because they are usually not operable with a keyboard or correctly understandable when described by a screen reader. From a5000aeb75b320bfca17588954168ea696d0c9a8 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 16:52:19 -0400 Subject: [PATCH 24/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 076b47afa4..023b67b064 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -73,7 +73,7 @@ An incorrectly implemented interactive element may be failing multiple Success C ### Status -This rule is available in all Cypress Accessibility projects, though it is not turned on by default. Reach out to Cypress if you would like to have this rule activated for you early. +This rule is available in all Cypress Accessibility projects, though it is not enabled by default. Reach out to Cypress if you would like to have this rule enabled for you. ### Possible outcomes From a09a9c3fcd4c4c21a5c795ab344e4302ba4211a6 Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 16:53:33 -0400 Subject: [PATCH 25/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Jennifer Shehane --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 023b67b064..83086e2d83 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -58,7 +58,7 @@ In the Web Content Accessibility Guidelines (WCAG), interactive elements are req Interactive elements that are not semantically correct often don't appear in automated scans, but do appear in manual testing, because they are usually not operable with a keyboard or correctly understandable when described by a screen reader. -Custom components implemented this way have a direct impact on the independence of your disabled users. +Custom components implemented this way have a direct impact on the independence of disabled users. ### Related WCAG Success Criteria From 3378f2bfaa3e42a9c22ce4ab00c20b4ff1f77c59 Mon Sep 17 00:00:00 2001 From: marktnoonan Date: Thu, 10 Jul 2025 17:23:12 -0400 Subject: [PATCH 26/27] add overall explainer at the top --- docs/accessibility/core-concepts/cypress-rules.mdx | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index 299bc86d4b..d0a9310408 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -10,10 +10,22 @@ sidebar_custom_props: { 'new_label': true } # Cypress rules +## What are Cypress rules? + In addition to running the default ruleset of the Axe-Core® library, Cypress develops custom rules that take advantage of the additional layer of information available in a test automation context. These rules are identified by a "Cypress Rule" badge, to distinguish them from the main Axe-Core® rule set. The first custom rule that we have implemented is called "Interactive elements should be semantically correct." At launch, it is a non-blocking **manual-review** rule that will either pass if no issues are found, or return an inconclusive state. +## Why do we need custom accessibility rules? + +Conventional accessibility checks work by scanning the DOM of a web page to discover errors and inconsistencies that would affect the accessibility of the content. These checks use signals based on the nature of the content itself to determine what the correct accessible experience should be. Buttons, links, and form fields without labels can all be detected this way - if they are written correctly. + +This form of "passive" accessibility scan is limited to what can be learned from the page itself, because there is no other source of input about the purpose of the elements on the screen. The tools used are typically general-purpose scanners that can be called in many different contexts, not always in a test automation pipeline. + +In Cypress Accessibility, we can build rules that move beyond a passive scan and offer more insights about the accessibility of what you are testing, based on your existing test activities, which already describe how a user is supposed to move through the application, and what elements they use. + +This helps provide early detection of issues that might later appear in manual testing or in bug reports from users, increasing the total range of issues detectable in an automated scan without custom assertions or setup. + ## Interactive elements should be semantically correct - **ID**: `cy-semantic-html-warning` From d6c96d0960c0d18cd2a87040dd793fff8debaced Mon Sep 17 00:00:00 2001 From: Mark Noonan Date: Thu, 10 Jul 2025 17:49:30 -0400 Subject: [PATCH 27/27] Update docs/accessibility/core-concepts/cypress-rules.mdx Co-authored-by: Tyler Biethman --- docs/accessibility/core-concepts/cypress-rules.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/accessibility/core-concepts/cypress-rules.mdx b/docs/accessibility/core-concepts/cypress-rules.mdx index da083ea365..4072ecb551 100644 --- a/docs/accessibility/core-concepts/cypress-rules.mdx +++ b/docs/accessibility/core-concepts/cypress-rules.mdx @@ -22,7 +22,7 @@ Conventional accessibility checks work by scanning the DOM of a web page to disc This form of "passive" accessibility scan is limited to what can be learned from the page itself, because there is no other source of input about the purpose of the elements on the screen. The tools used are typically general-purpose scanners that can be called in many different contexts, not always in a test automation pipeline. -In Cypress Accessibility, we can build rules that move beyond a passive scan and offer more insights about the accessibility of what you are testing, based on your existing test activities, which already describe how a user is supposed to move through the application, and what elements they use. +In Cypress Accessibility, we can build rules that move beyond a passive scan and offer more insights about the accessibility of what you are testing based on your existing test activities, which already describe how a user is supposed to move through the application and what elements they use. This helps provide early detection of issues that might later appear in manual testing or in bug reports from users, increasing the total range of issues detectable in an automated scan without custom assertions or setup.