<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mark Noonan</title>
    <description>The latest articles on DEV Community by Mark Noonan (@marktnoonan).</description>
    <link>https://dev.to/marktnoonan</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F113592%2F9e2c0347-20a8-406e-a7f4-031d4ce6e98d.jpeg</url>
      <title>DEV Community: Mark Noonan</title>
      <link>https://dev.to/marktnoonan</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marktnoonan"/>
    <language>en</language>
    <item>
      <title>Skip tests that pass on the current build: Re-run optimization in Cypress Cloud</title>
      <dc:creator>Mark Noonan</dc:creator>
      <pubDate>Thu, 01 Oct 2026 16:35:34 +0000</pubDate>
      <link>https://dev.to/cypress/skip-tests-that-pass-on-the-current-build-re-run-optimization-in-cypress-cloud-4ef2</link>
      <guid>https://dev.to/cypress/skip-tests-that-pass-on-the-current-build-re-run-optimization-in-cypress-cloud-4ef2</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flhq8o8mz99p2c3d15ojn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Flhq8o8mz99p2c3d15ojn.png" alt=" " width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When Cypress detects a CI rerun, it can now skip the work that already passed and run only what failed, so you get to green faster, burn fewer CI minutes, and record fewer billable test results. Re-runs with few failures can &lt;strong&gt;skip 99% or more&lt;/strong&gt; of the tests that would have re-executed. It works out-of-the-box with common CI providers, and ships with overrides to customize the re-run behavior to your specific needs.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://on.cypress.io/rerun-optimization?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=rerun-optimization" rel="noopener noreferrer"&gt;&lt;u&gt;Re-run Optimization&lt;/u&gt;&lt;/a&gt; is available for all Business plans and higher, and in &lt;a href="https://on.cypress.io/free-trial?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=free%20trials" rel="noopener noreferrer"&gt;&lt;u&gt;free trials&lt;/u&gt;&lt;/a&gt;, as a part of Smart Orchestration. &lt;/p&gt;

&lt;p&gt;This post will walk through  the highlights for saving time and getting a green build faster.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Why do teams re-execute failed Cypress runs?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;We interviewed current Cypress Cloud customers to get this feature right. Most told us they already use tools like &lt;strong&gt;flake detection&lt;/strong&gt; to stay on top of things they can control from the testing side. Generally their &lt;strong&gt;test design&lt;/strong&gt; is not causing flakiness, and in-run, often flake represents real race-condition bugs in the application logic.&lt;/p&gt;

&lt;p&gt;Re-runs address instability that’s &lt;strong&gt;not&lt;/strong&gt; at the application layer or the test design layer. A re-run &lt;strong&gt;adds information&lt;/strong&gt; to help you understand the full end-to-end picture, especially if your testing environment itself is not fully stable, which means a single failure could have multiple causes. The re-run helps rule some of those causes out cheaply, before you or your AI systems work on debugging.&lt;/p&gt;

&lt;p&gt;For busy teams with large test suites on complicated applications, keeping the test environment stable isn’t always practical, or even necessarily desired. When systems integrate with live devices or depend on third parties, stability itself is part of what a full end-to-end test run is measuring. &lt;/p&gt;

&lt;p&gt;Whatever the underlying reason for a failure, if something is blocking a release or an important merge, your priority in that moment is to understand the issue and get unblocked as fast as possible. At those times, re-run optimization makes your re-executions cheaper, faster, and less painful. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;How much time is saved with Re-run optimization in Cypress Cloud?&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;The most time savings come from test-level re-runs, which allows Cypress to cherry-pick individual tests that need to re-run. Based on real production runs from customers who have adopted this technique, the median re-run skips &lt;strong&gt;92%&lt;/strong&gt; of the original run’s tests, and finishes &lt;strong&gt;9.3 minutes faster&lt;/strong&gt; than the original run. &lt;/p&gt;

&lt;p&gt;The maximum savings we have seen on re-runs are when there are large test suites with small numbers of failures, where &lt;strong&gt;99.8% of the tests that would have re-executed were skipped&lt;/strong&gt; , and &lt;strong&gt;36 minutes were saved&lt;/strong&gt; for the test run. This is the pattern you may see if you run long nightly test suites or pre-release tests of live environments that might have deployments or other disruptions during the test execution.&lt;/p&gt;

&lt;p&gt;Re-run optimization makes it much faster and more practical to get that extra confidence and confirmation of what’s going on when a build has failed, and avoids the risk of instability leading to the original failures passing on the new run, only for something else to start failing.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Choose spec-level or test-level reruns in Cypress Cloud&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;You set the granularity once in the Smart Orchestration section of your organization or project settings, and projects can inherit the org default or override it.&lt;/p&gt;

&lt;p&gt;When set to run only failed &lt;strong&gt;specs&lt;/strong&gt; , Cypress re-runs every spec that contained a failure on the last run, including the tests in that spec that passed, which is the safer choice if your tests share state inside a spec.&lt;/p&gt;

&lt;p&gt;When set to run only failed &lt;strong&gt;tests&lt;/strong&gt; , Cypress re-runs only the tests that didn't pass, plus any that are new or changed since the last run. It requires Cypress 15.21.0 or later (older versions fall back to failed specs). If a test would pass on its own with .only, it will work in a re-run. If not, prefer spec-based retries for your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Controlling the re-run behavior in Cypress Cloud&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;If you re-run before Cloud marks the previous run complete, Cypress plays it safe and runs everything. Keeping your &lt;a href="https://on.cypress.io/parallelization?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=run-completion-delay" rel="noopener noreferrer"&gt;run completion delay&lt;/a&gt; short can reduce the window where your CI is ready to rerun a job but Cypress Cloud is still open. But in many cases, you may want to manage the previous run’s status explicitly. Our recently released &lt;a href="https://docs.cypress.io/cloud/features/smart-orchestration/run-cancellation-api?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=run-cancellation-api" rel="noopener noreferrer"&gt;&lt;u&gt;Run Cancellation API&lt;/u&gt;&lt;/a&gt;, and &lt;a href="https://on.cypress.io/parallelization?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=run-completion-api" rel="noopener noreferrer"&gt;&lt;u&gt;Run Completion API&lt;/u&gt;&lt;/a&gt; give you programmatic control over the run state. Combined with Spec Prioritization and &lt;a href="https://on.cypress.io/run-cancellation?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=rerun-optimization" rel="noopener noreferrer"&gt;&lt;u&gt;Auto Cancellation&lt;/u&gt;&lt;/a&gt;. &lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;strong&gt;Turn it on&lt;/strong&gt;
&lt;/h2&gt;

&lt;p&gt;Re-run optimization is part of Smart Orchestration on Business and Enterprise plans, and it's available during a free trial. Owners and Admins can enable it in organization or project settings. The &lt;a href="https://on.cypress.io/rerun-optimization?utm_source=devto&amp;amp;utm_medium=syndication&amp;amp;utm_campaign=rerun-optimization&amp;amp;utm_content=rerun-optimization-docs" rel="noopener noreferrer"&gt;Re-run optimization docs&lt;/a&gt; cover setup for each CI provider.&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>testing</category>
      <category>ci</category>
      <category>rerun</category>
    </item>
    <item>
      <title>Build custom workflows with Cypress Cloud Webhooks</title>
      <dc:creator>Mark Noonan</dc:creator>
      <pubDate>Tue, 08 Sep 2026 17:17:31 +0000</pubDate>
      <link>https://dev.to/cypress/build-custom-workflows-with-cypress-cloud-webhooks-4p6i</link>
      <guid>https://dev.to/cypress/build-custom-workflows-with-cypress-cloud-webhooks-4p6i</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb504ghmymlrvastsr6gp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fb504ghmymlrvastsr6gp.png" alt="Push Results with Webhooks" width="800" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://on.cypress.io/webhooks?utm_source=devto" rel="noopener noreferrer"&gt;Webhooks&lt;/a&gt; are a new addition to Cypress Cloud, supporting more flexible automation workflows beyond what is built into the platform itself.&lt;/p&gt;

&lt;p&gt;Learn why we've added them and how to get started using them in your project.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integration support in Cypress Cloud
&lt;/h2&gt;

&lt;p&gt;Cypress Cloud supports a wide range of integrations out of the box. If you need a &lt;a href="https://on.cypress.io/github?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks#Status-checks" rel="noopener noreferrer"&gt;GitHub status check&lt;/a&gt; for every group of tests in your test run, we've got you covered. &lt;a href="https://docs.cypress.io/cloud/integrations/slack?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Slack&lt;/a&gt; and &lt;a href="https://on.cypress.io/microsoft-teams?utm_source=devto&amp;amp;utm_medium=cypress.io&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Teams&lt;/a&gt; messages when a run fails? That's there, along with &lt;a href="https://on.cypress.io/recorded-runs?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks#Notifications" rel="noopener noreferrer"&gt;desktop notifications&lt;/a&gt;, &lt;a href="https://on.cypress.io/jira?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Jira ticket creation&lt;/a&gt;, &lt;a href="https://on.cypress.io/enterprise-reporting?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;high-level trend reporting APIs&lt;/a&gt;, and more.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why webhooks?
&lt;/h2&gt;

&lt;p&gt;Using webhooks is a great solution for &lt;strong&gt;custom integrations&lt;/strong&gt; where you want Cypress Cloud to &lt;strong&gt;push&lt;/strong&gt; run results and other data into another system.&lt;/p&gt;

&lt;p&gt;A webhook can be the starting point to kick off workflows based on inspecting the outcome of a run, or a way to customize the details you will include in a Slack or Teams message, or send messages to destinations Cypress doesn't support, such as Google Chat.&lt;/p&gt;

&lt;p&gt;Webhooks also help you leverage our other recently-released Cypress App and Cypress Cloud updates in ways that work for you. Rather than invoke the Cypress &lt;a href="https://on.cypress.io/cloud-cli?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Cloud CLI&lt;/a&gt; or &lt;a href="https://on.cypress.io/cloud-mcp?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;MCP&lt;/a&gt; at the end of every run, you can set up a URL for Cypress to deliver run results, along with the tags, branch, and commit info that helps you decided if further action is needed.&lt;/p&gt;

&lt;p&gt;This lets you be more efficient with AI token usage and reduce rate-limited request you make for routine run analysis. Filter to just the runs you are most interested in based on the webhook payload, then you can dive deeper with scripts using the Cloud AI tools to get Test Replay snapshot data and command logs, or hand off to your LLM using the live Cypress App running locally with &lt;a href="https://on.cypress.io/cypress-tap?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;&lt;code&gt;cypress tap&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  When to use a webhook
&lt;/h2&gt;

&lt;p&gt;In some cases, existing APIs may fully meet your needs, particularly if your runs are small and the existing integrations are well-suited to the content you already want in your messaging platforms.&lt;/p&gt;

&lt;p&gt;In other cases, webhooks remove multiple layers of handoffs from your CI environment to other services, removing glue code or even opening up new possibilities, like optionally triggering re-runs of your failed tests in CI based on the tags or commit message you send to Cypress Cloud.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;Available on all paid Cypress Cloud plans, today webhooks can be attached to a &lt;code&gt;run.completed&lt;/code&gt; event, which fires when a run has resolved to a finalized state after all results have been recorded.&lt;/p&gt;

&lt;p&gt;Admins and owners can add webhooks in your project settings page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyvglgxe25qczotxevke6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyvglgxe25qczotxevke6.png" alt="webhook creation area of the settings page" width="800" height="107"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; the recently-released &lt;a href="https://on.cypress.io/parallelization?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks#Run-Completion-API" rel="noopener noreferrer"&gt;Run Completion API&lt;/a&gt; may be useful if you have parallel or grouped runs, and you want your webhooks to fire as soon as all expected groups have finished recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  What's next
&lt;/h2&gt;

&lt;p&gt;We'd love to know how you are using this and what types of events or payloads would be useful for your specific goals. We will continue developing and expanding in this area based on your feedback.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://on.cypress.iowebhooks?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Read the webhooks docs&lt;/a&gt; to get your first webhook configured. Don't have a Cypress Cloud account yet? &lt;a href="https://cloud.cypress.io/signup?utm_source=devto&amp;amp;utm_medium=cypress-org&amp;amp;utm_content=cypress-cloud-webhooks" rel="noopener noreferrer"&gt;Start your free trial&lt;/a&gt; and try it on your own project.&lt;/p&gt;

</description>
      <category>cypress</category>
      <category>webhooks</category>
      <category>slack</category>
      <category>jira</category>
    </item>
    <item>
      <title>Open Source Accessibility Plugins in Cypress</title>
      <dc:creator>Mark Noonan</dc:creator>
      <pubDate>Wed, 19 Feb 2025 16:02:45 +0000</pubDate>
      <link>https://dev.to/cypress/open-source-accessibility-plugins-in-cypress-23da</link>
      <guid>https://dev.to/cypress/open-source-accessibility-plugins-in-cypress-23da</guid>
      <description>&lt;p&gt;Last year saw the GA launch of Cypress's commercial &lt;a href="https://on.cypress.io/accessibility-trial?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=accessibility-testing-solution" rel="noopener noreferrer"&gt;accessibility testing solution&lt;/a&gt; built into Cypress Cloud. We're delighted to see this helping teams speed up and scale their accessibility efforts.&lt;/p&gt;

&lt;p&gt;But accessibility testing itself is &lt;strong&gt;nothing new&lt;/strong&gt; in Cypress, and there are many different ways to account for accessibility in test automation which all complement each other. We’ve blogged in the past about considering &lt;a href="https://www.cypress.io/blog/maintaining-accessibility-through-user-focused-testing?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=accessibility-in-component-tests" rel="noopener noreferrer"&gt;accessibility in component tests&lt;/a&gt;, and recently added an &lt;a href="https://docs.cypress.io/app/guides/accessibility-testing?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=accessibility-testing-guide" rel="noopener noreferrer"&gt;accessibility testing guide&lt;/a&gt; to the open-source Cypress App docs.&lt;/p&gt;

&lt;p&gt;When drafting that guide I found I wanted to go a bit deeper into the community plugin side of accessibility and Cypress, as I realized that in 2024 alone, there were multiple accessibility related plugins released, some directly related to testing, and others more geared towards customization of Cypress itself.&lt;/p&gt;

&lt;p&gt;In this post we’ll take a look at three recently-released accessibility-related Cypress Plugins: Wick A11y, Cypress Runner Themes, and Cypress Voice Plugin, and hear from their creators.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cypress Voice Plugin
&lt;/h2&gt;

&lt;p&gt;This plugin was created by&amp;nbsp;&lt;a href="https://www.linkedin.com/in/dennis-bergevin/" rel="noopener noreferrer"&gt;Dennis Bergiven&lt;/a&gt;, who told me "The voice plugin was inspired by your chat with Filip Hric, where you chatted over various ideas and topics using Cypress". This was a really fun live stream&amp;nbsp;&lt;a href="https://www.linkedin.com/in/filip-hric/" rel="noopener noreferrer"&gt;Filip&lt;/a&gt;&amp;nbsp;and I did back in 2023, and here's the relevant clip called&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=-SS4G8qd4EM" rel="noopener noreferrer"&gt;"How to make Cypress talk"&lt;/a&gt;. In it, I show how to use&amp;nbsp;&lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis" rel="noopener noreferrer"&gt;built-in browser Speech Synthesis&lt;/a&gt;&amp;nbsp;to have Cypress verbally announce something at the end of a spec's execution, especially where the spec might contain many tests or do something that takes some time and you have already moved your screen back to the next code change. (In addition to being a great testing educator, Filip is also the developer of the popular&amp;nbsp;&lt;a href="https://www.npmjs.com/package/cypress-plugin-api" rel="noopener noreferrer"&gt;Cypress API testing plugin&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;This was just a proof of concept, as we discussed various ways to hack different functionality into Cypress to customize it for specific testing needs. Dennis described later seeing a practical problem at work that this could help with, saying "The idea came back when some colleagues at work expressed they wanted a faster way to detect a test result when running in the UI."&lt;/p&gt;

&lt;p&gt;The end result is a highly configurable voice announcer:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xgayfauful3ixx9z4gq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3xgayfauful3ixx9z4gq.png" alt="A zoomed-in view of the Cypress App showing three sliders to control voice rate, voice pitch, and voice volume for the Cypress Voice Plugin" width="800" height="539"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Dennis added that "using native web speech API within the plugin fits right into the Cypress framework as it lives in the browser as well", which made the implementation possible.&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://medium.com/@drbergevin/cypress-voice-plugin-an-auditory-tool-for-the-cypress-test-runner-ui-1726040b693e?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Medium post about Cypress Voice Plugin&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.npmjs.com/package/cypress-voice-plugin?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Cypress Voice Plugin's npm package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Cypress Runner Themes
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://www.linkedin.com/in/dingraham01/?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;David Ingraham&lt;/a&gt;&amp;nbsp;recognized two needs in the community and created a plugin to solve both. First he created a more color-blind friendly theme for the Cypress command in the Cypress App, to avoid using red and green to hint at the passing/failing status of tests. Then he rolled this up into a general Cypress theming package to combine and update some existing theming solutions like&amp;nbsp;&lt;a href="https://www.npmjs.com/package/cypress-light-theme?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;cypress-light-theme&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a href="https://www.npmjs.com/package/cypress-dark?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;cypress-dark&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;David said, "I created &lt;code&gt;cypress-runner-themes&lt;/code&gt; after a user on the discord mentioned they were having trouble reading Cypress results due to being colorblind and I noticed there wasn't any existing plugins out there. In combination with the old plugin &lt;code&gt;cypress-dark&lt;/code&gt; being unsupported, I thought it would be a good idea to provide a newer theme plugin with accessibility support."&lt;/p&gt;

&lt;p&gt;Cypress does not have built-in theme support, but David has been able to leverage the fact that Cypress executes plugin code in the browser, and runs in the same environment, to make modifications to the Cypress interface. Plugins are a common way that the community can get out ahead and iterate on behavior that might be desirable in the Cypress App, without waiting for it to be implemented into the core Cypress library. Here's an example of one of the themes:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv4ld58h9yg2kjvphmci.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkv4ld58h9yg2kjvphmci.png" alt="The Cypress App open with a custom yellow color replacing the standard green color for a passing test." width="800" height="438"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;"It was my first community plugin so I also wanted to learn something new while making a real impact on the community," David told us. We look forward to seeing more in the future!&lt;/p&gt;

&lt;h3&gt;
  
  
  Links
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://medium.com/@dingraham01/cypress-runner-themes-alternative-styles-for-the-cypress-test-runner-9505881002a0?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Cypress Runner Themes medium post&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.npmjs.com/package/cypress-runner-themes?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Cypress Runner Themes npm package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Wick-A11y
&lt;/h2&gt;

&lt;p&gt;Created by&amp;nbsp;&lt;a href="https://www.linkedin.com/in/sebastianclavijosuero/?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Sebastian Clavijo Suero&lt;/a&gt;, and named for its John Wick-style ability to identify and remove accessibility issues with extreme prejudice, this summer blockbuster adds some visual, reporting, and voice-announcing dimensions to the&amp;nbsp;&lt;a href="https://github.com/component-driven/cypress-axe?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;cypress-axe plugin&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;

&lt;p&gt;Before we hear from Sebastian, it's worth backing up for a second to explain the connection between all these tools.&lt;/p&gt;

&lt;p&gt;At the root is the open source&amp;nbsp;&lt;a href="https://github.com/dequelabs/axe-core?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Axe Core library&lt;/a&gt;&amp;nbsp;by Deque Systems, which was released in 2015. Axe Core has over 1 billion downloads and is used in many accessibility testing systems such as Google's Lighthouse, as well as in&amp;nbsp;&lt;a href="https://on.cypress.io/accessibility-trial?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=cypress-accessibility" rel="noopener noreferrer"&gt;Cypress Accessibility&lt;/a&gt;. (Side note: we were delighted to welcome Dylan Barrell, the creator of Axe Core, to Cypress Conf 2023, where he shared his presentation about&amp;nbsp;&lt;a href="https://www.youtube.com/watch?v=MM8u1dbniwQ&amp;amp;ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Agile Accessible Software Development&lt;/a&gt;.)&lt;/p&gt;

&lt;p&gt;The cypress-axe plugin by Andy Van Slaars was first published in 2018, providing an easy integration in Cypress allowing testers to add Axe Core checks where they chose at different steps of the user journey in their tests. In our docs, we discuss more about these kinds of&amp;nbsp;&lt;a href="https://docs.cypress.io/app/guides/accessibility-testing?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=in-test-accessibility-scans" rel="noopener noreferrer"&gt;in-test accessibility scans&lt;/a&gt;&amp;nbsp;work, so I won't repeat that here.&lt;/p&gt;

&lt;p&gt;While there are other accessibility checkers that also have Cypress integrations, cypress-axe has been the go-to for most Cypress users.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;OK, now we're up to date!&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Much like the other plugin authors, Sebastian saw an opportunity for extending beyond the current behavior to solve a problem, and shared that solution with others. I send him over a few questions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What inspired you to create wick-a11y?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I created Wick-a11y to significantly simplify accessibility testing, which is often neglected despite its crucial role in developing inclusive web applications. Although tools like cypress-axe are easy to set up, they provide raw data that requires additional processing for clear interpretation of the results. Wick-a11y seamlessly integrates with Cypress, delivering an easy-to-use solution to assess accessibility, interact with results directly in the Cypress runner, and effortlessly produce detailed HTML reports with screenshots.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;What made Cypress a good platform for this?&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Cypress is an excellent platform for wick-a11y due to its seamless integration capabilities with tools like axe-core for comprehensive accessibility testing. Cypress's interactive test runner and user-friendly interface allow for real-time interaction with accessibility results directly on the web page, enhancing the identification and resolution of issues. Additionally, Cypress supports detailed logging, providing testers with an efficient way to document and share accessibility findings.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Tell us about your recent addition of voice feedback&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I added the voice feedback feature to wick-a11y, acknowledging that many individuals testing website accessibility are affected by disabilities themselves. By providing auditory cues alongside accessibility violations, this feature enhances the testing experience, empowering those committed to inclusivity to engage without barriers and continue championing a more accessible web for everyone.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's an example of a test open in the Cypress App, showing some accessibility issues detected with cypress-axe and highlighted by wick-a11y&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7294kcp7kef1shsvaty.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu7294kcp7kef1shsvaty.png" alt="The wick a11y plugin running, which adds highlights to elements with failing accessibility checks and lists elements in the command log of the Cypress App" width="800" height="373"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is much more to see, so check out the links below to learn more about adding these kinds of accessibility assertions to your Cypress tests.&lt;/p&gt;

&lt;p&gt;Links&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;  &lt;a href="https://dev.to/sebastianclavijo/wick-a11y-cypress-plugin-your-unstoppable-ally-for-smashing-accessibility-barriers-cool-as-john-wick-280a?ref=cypress-io.ghost.io"&gt;Article for original Wick-A11y release&lt;/a&gt;&amp;nbsp; &amp;nbsp;&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://dev.to/sebastianclavijo/wick-a11y-v121-voice-the-accessibility-cypress-plugin-that-talks-more-than-john-wick-in-his-movies-8c8?ref=cypress-io.ghost.io"&gt;Article for voice feature release&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;  &lt;a href="https://www.npmjs.com/package/wick-a11y?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Wick-A11y npm package&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  What comes next
&lt;/h2&gt;

&lt;p&gt;The Cypress community has created a useful array of plugins to support accessibility testing and other customized extensions to the app. This is only a recent subset of plugins related to accessibility in Cypress - there are plugins for other accessibility testing packages beyond Axe Core, as well as accessibility-minded test locators from&amp;nbsp;&lt;a href="https://testing-library.com/docs/cypress-testing-library/intro/?ref=cypress-io.ghost.io" rel="noopener noreferrer"&gt;Cypress Testing Library&lt;/a&gt;, and more.&lt;/p&gt;

&lt;p&gt;What I like about these three recently released plugins is that they represent extensions and iterations upon existing ideas to solve new needs. They leverage the hackability that's inherent to the browser-based nature of Cypress to great effect, and they set the baseline for future iterations to continue building.&lt;/p&gt;

&lt;p&gt;Do you have a plugin for Cypress? You can&amp;nbsp;&lt;a href="https://github.com/cypress-io/cypress-documentation/blob/main/CONTRIBUTING.md?ref=cypress-io.ghost.io#adding-plugins" rel="noopener noreferrer"&gt;submit it&lt;/a&gt;&amp;nbsp;to our documentation's&amp;nbsp;&lt;a href="https://docs.cypress.io/app/plugins/plugins-list?utm_medium=intro&amp;amp;utm_source=dev-to&amp;amp;utm_campaign=dev-to-syndication&amp;amp;utm_term=&amp;amp;utm_content=accessibility-testing-guide" rel="noopener noreferrer"&gt;plugins list&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>cypress</category>
      <category>a11y</category>
      <category>testing</category>
    </item>
    <item>
      <title>Why I rarely use `getByRole`: Testing Library and the first rule of ARIA</title>
      <dc:creator>Mark Noonan</dc:creator>
      <pubDate>Sat, 04 May 2024 00:16:34 +0000</pubDate>
      <link>https://dev.to/marktnoonan/why-i-rarely-use-getbyrole-testing-library-and-the-first-rule-of-aria-4581</link>
      <guid>https://dev.to/marktnoonan/why-i-rarely-use-getbyrole-testing-library-and-the-first-rule-of-aria-4581</guid>
      <description>&lt;p&gt;&lt;em&gt;Note: I've gotten some &lt;a href="https://x.com/matanbobi/status/1787033641177993545"&gt;feedback&lt;/a&gt; from a Testing Library maintainer, Matan Borenkraout, about these ideas. I haven't gotten around to incorporating that feedback yet. He had some good examples where &lt;code&gt;ByText&lt;/code&gt; or even &lt;code&gt;ByLabelText&lt;/code&gt; might not be able to find some elements due to how the label is created or how the implicit role is determined, so what I'm describing here might not handle all cases nicely. I don't think this blows up the premise I'm describing, but I'll be thinking that feedback over and expect I'll be updating the content below in the future.&lt;/em&gt; &lt;/p&gt;

&lt;p&gt;**&lt;/p&gt;

&lt;h2&gt;
  
  
  Intro
&lt;/h2&gt;

&lt;p&gt;To explain the reasons that I mostly stopped using &lt;code&gt;ByRole&lt;/code&gt; locators and started specifying elements, I want to zoom way out and talk about the various pieces of the puzzle. Here's a rough table of contents.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Background&lt;/li&gt;
&lt;li&gt;What problems Testing Library is intended to solve&lt;/li&gt;
&lt;li&gt;Why &lt;code&gt;ByRole&lt;/code&gt; is too vague&lt;/li&gt;
&lt;li&gt;What makes something accessible&lt;/li&gt;
&lt;li&gt;What roles even are&lt;/li&gt;
&lt;li&gt;The first rule of ARIA (Accessible Rich Internet Applications)&lt;/li&gt;
&lt;li&gt;Semantic HTML, TypeScript, and using the platform&lt;/li&gt;
&lt;li&gt;What we expect developers and testers to know when writing and testing their code&lt;/li&gt;
&lt;li&gt;Situations where I still use &lt;code&gt;ByRole&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Why I love &lt;code&gt;ByLabelText&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;The use of Test IDs&lt;/li&gt;
&lt;li&gt;Overall conclusions&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since this argument is all in the details, this is a relatively long post, so I'm skipping some background on the underlying ideas of front-end testing and locating elements. If you're new to these topics, I have a 2022 post on CSS-Tricks called &lt;a href="https://css-tricks.com/front-end-test-element-locators/"&gt;Writing Strong Front-end Test Element Locators&lt;/a&gt; that starts more from the ground up. But for now, I'm going to assume you have some familiarity with how front-end testing works and are interested in best practices for locating elements.&lt;/p&gt;

&lt;p&gt;And of course, feel free to skip ahead to the conclusions if this is all familiar stuff.&lt;/p&gt;

&lt;h2&gt;
  
  
  Background
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://testing-library.com/"&gt;Testing Library&lt;/a&gt; provides a great set of accessibility-focused tools to locating elements when writing tests. It was created by Kent C Dodds, one of my longtime favorite educators on front-end and testing topics.  Since the initial release in 2018 as "React Testing Library", it's grown in popularity beyond its React component testing roots. It now has plugins for all major test runners and JavaScript frameworks, and in 2022 some of its patterns were adopted in Playwright's test runner as the recommended way to locate elements.&lt;/p&gt;

&lt;p&gt;I do almost all of my testing in Cypress (and for clarity: I work there). I've added &lt;a href="https://testing-library.com/docs/cypress-testing-library/intro"&gt;Cypress Testing Library&lt;/a&gt; to multiple projects over the years, and it's my go-to for a lot of testing tasks, especially when testing forms, using the &lt;code&gt;ByLabelText&lt;/code&gt; locator.&lt;/p&gt;

&lt;p&gt;One thing I've noticed over time is that I've mostly stopped using the main workhorse of Testing Library, the &lt;code&gt;ByRole&lt;/code&gt; locator. When I wrote some guidance for my team a few years ago, I recommended not using it in most cases. I also mention this as a quick caveat when I teach testing or accessibility topics (for example, it comes up in passing in a &lt;a href="https://www.cypress.io/blog/2023/06/13/maintaining-accessibility-through-user-focused-testing#locating-a-link-using-name-and-expected-location-in-the-accessibility-tree"&gt;blog post about user-focused locators&lt;/a&gt; that I wrote last year). &lt;/p&gt;

&lt;p&gt;I haven't given it much thought over the years, it's just one tool in the Testing Library toolbox and it has its place. My recommendation was driven by what I expect &lt;code&gt;ByRole&lt;/code&gt; to accomplish. But recently I've noticed many strong recommendations to use &lt;code&gt;ByRole&lt;/code&gt; as the &lt;em&gt;best&lt;/em&gt; way to find an element in a test, citing the reason that this helps ensure the underlying application being tested is accessible.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short version
&lt;/h2&gt;

&lt;p&gt;My argument in this post will be that &lt;code&gt;getByRole&lt;/code&gt; is not strict enough to ensure that a given accessible role is correctly implemented. Locating elements this way can create misleading scenarios where your tests imply that an element is accessible, even if it's not. We'll get into more detail on that below, but first I want to give you the TLDR on what I do instead.&lt;/p&gt;

&lt;p&gt;The recommended Testing Library approach to find and test a button is this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/submit/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;What I prefer to do is locate an element by a combination of two things that, if they are changed, should fail a test: &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The element's specific tag name - &lt;code&gt;button&lt;/code&gt; or &lt;code&gt;a&lt;/code&gt;, for example&lt;/li&gt;
&lt;li&gt;The element's accessible name - "Save" or "Home", for example&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In order to do this in Testing Library, for buttons and links, I would use the &lt;code&gt;ByText&lt;/code&gt; locator, like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// get a "Submit" button&lt;/span&gt;
&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="c1"&gt;// get a "Home" link in the navigation element&lt;/span&gt;
&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nav a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;I do something similar using the following format of the &lt;code&gt;contains&lt;/code&gt; command in Cypress. I tend to only look for another locator when this isn't going to get me the element I need:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// get a "Submit" button&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Submit&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// get a "Home" link in the navigation element&lt;/span&gt;
&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;nav a&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;h2&gt;
  
  
  The long version
&lt;/h2&gt;

&lt;p&gt;The rest of this post is really just me trying to push at this from a few different angles and think everything through. I often find I have some opinion that I think is right, and then when I try to write about it, I realize I don't know the exact source of why I think something, or what things might just be assumptions. So it helps to document all the pieces, and it lets somebody else cross-check the ideas.&lt;/p&gt;
&lt;h3&gt;
  
  
  What is Testing Library for?
&lt;/h3&gt;

&lt;p&gt;The basic premise of Testing Library is summed up by this quote from the home page:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The more your tests resemble the way your software is used,&lt;br&gt;
the more confidence they can give you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The problems Testing Library solves are described in two ways. The first is about avoiding testing implementation details to have better confidence that test failures matter:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You want tests for your UI that avoid including implementation details and rather focus on making your tests give you the confidence for which they are intended.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The second is about how not testing implementation details makes refactoring less painful:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You want your tests to be maintainable so refactors (&lt;em&gt;changes to implementation but not functionality&lt;/em&gt;) don't break your tests and slow you and your team down.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The issue of test stability over time, and avoiding testing "implementation details", had previously often been addressed with a Test ID based approach, which maximizes the stability of tests. Testing Library's authors make the argument that using &lt;code&gt;[data-testid="login"]&lt;/code&gt; style locators ignores important user-facing aspects of the elements being tested. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;This is true.&lt;/strong&gt; Test IDs intentionally and explicitly ignore the nature of the elements being used. We'll talk more about them at the end -- there's no disagreement there. &lt;/p&gt;

&lt;p&gt;My issue with &lt;code&gt;ByRole&lt;/code&gt; locators is the same as the problem with Test IDs, just in a narrower area. If either of these are your &lt;strong&gt;only&lt;/strong&gt; locators and no test ever specifies the specific elements you expect, developers have too much wiggle room to break accessibility while keeping tests green. &lt;/p&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;ByRole&lt;/code&gt; locators are too forgiving for safe refactoring
&lt;/h3&gt;

&lt;p&gt;The Testing Library query documentation says this about the &lt;code&gt;ByRole&lt;/code&gt; locator:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This should be your top preference for just about everything. There's not much you can't get with this (if you can't, it's possible your UI is inaccessible).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The Playwright documentation puts it in similar terms:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We recommend prioritizing role locators to locate elements, as it is the closest way to how users and assistive technology perceive the page.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Both give examples of doing something like this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/submit/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;The underlying idea I take from this that if an element passes the "role check", it's likely to be accessible: locating an element by its role is intended to achieve the goal of safe refactoring - where "changes to implementation but not functionality" do not break your tests.&lt;/p&gt;

&lt;p&gt;However, even though a &lt;code&gt;role&lt;/code&gt; is part of an element's "identity" in an accessibility sense, it's not enough. We could refactor an accessible component in a way that fully breaks all accessibility, but still have a green test that uses &lt;code&gt;getByRole&lt;/code&gt;. Many implementation changes that leave &lt;code&gt;role&lt;/code&gt; intact are actually critical changes in functionality.&lt;/p&gt;

&lt;p&gt;Here's an example of this kind of refactoring:&lt;/p&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/cf363569974643fa8278eaf2d68549ff"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;



&lt;h3&gt;
  
  
  What makes a button accessible?
&lt;/h3&gt;

&lt;p&gt;HTML elements all have implicit roles that describe the nature of the element to people with disabilities, accessing the page using assistive technology. Buttons have the &lt;code&gt;button&lt;/code&gt; role, anchor tags with &lt;code&gt;href&lt;/code&gt; attributes have the &lt;code&gt;link&lt;/code&gt; role, &lt;code&gt;input&lt;/code&gt; elements with type &lt;code&gt;text&lt;/code&gt; have a &lt;code&gt;textbox&lt;/code&gt; role and so on.&lt;/p&gt;

&lt;p&gt;When it comes to interactive elements, these roles are not usually useful by themselves. What is useful about them is that they represent an overall contract that element will fulfill. To use the &lt;code&gt;button&lt;/code&gt; element as an example, here is at least a partial list of the accessibility "contract" that browser vendors fulfill for a &lt;code&gt;button&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;It has the implicit role of &lt;code&gt;button&lt;/code&gt; so that users know what it is - a screen reader, for example, would announce it as a button&lt;/li&gt;
&lt;li&gt;It has a default browser button style to visually distinguish it from surrounding content&lt;/li&gt;
&lt;li&gt;It is placed in the tab order of the document and can be focused with the keyboard&lt;/li&gt;
&lt;li&gt;When focused it receives a focus outline&lt;/li&gt;
&lt;li&gt;It can be activated with a mouse click, or the enter key, or the space bar&lt;/li&gt;
&lt;li&gt;If placed inside a form element, activating the button by any of these methods will submit the form (because its default &lt;code&gt;type&lt;/code&gt; is &lt;code&gt;submit&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;It will receive specific styling, customizable by the user, in Windows High Contrast Mode (used by people with certain visual disabilities)&lt;/li&gt;
&lt;li&gt;It has default browser styles for hover and "pressed" states&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That's a lot of behavior that the browser implements for a humble button. The browser also manages this button's presence in the &lt;a href="https://developer.mozilla.org/en-US/docs/Glossary/Accessibility_tree"&gt;Accessibility Tree&lt;/a&gt;, which is how assistive technology like a screen reader can announce the button's existence, what it does, and how the user understands what actions are possible.&lt;/p&gt;

&lt;p&gt;And here's what may be surprising: the browser only does this stuff for real &lt;code&gt;button&lt;/code&gt; elements. Adding &lt;code&gt;role="button"&lt;/code&gt; to a &lt;code&gt;div&lt;/code&gt; or a &lt;code&gt;span&lt;/code&gt; does not trigger any of this in the browser. If &lt;code&gt;role="button"&lt;/code&gt; is used on say, a &lt;code&gt;div&lt;/code&gt; with an &lt;code&gt;onClick&lt;/code&gt; handler, the &lt;strong&gt;entire contract of a button must be implemented by the developer&lt;/strong&gt;, using extra HTML attributes, CSS rules, and JavaScript listeners. And even then, there will still be gaps - especially in &lt;a href="https://www.smashingmagazine.com/2022/06/guide-windows-high-contrast-mode/#use-semantic-html"&gt;Windows High Contrast Mode, which ignores &lt;code&gt;role="button"&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the main reason I avoid &lt;code&gt;ByRole&lt;/code&gt; locators most of the time. Let's look at this locator again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;screen&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/submit/i&lt;/span&gt; &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This will absolutely find a true &lt;code&gt;button&lt;/code&gt; element, because of its implicit role, but it will also have no problem finding a &lt;code&gt;div&lt;/code&gt; with &lt;code&gt;role="button"&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Since these two elements can be &lt;em&gt;very&lt;/em&gt; different from an accessibility point of view, it does not seem at all safe to depend on &lt;code&gt;ByRole&lt;/code&gt; locators during a UI refactor. Accessibility can change radically depending on the underlying HTML, CSS, and JavaScript, even when roles are preserved during what is intended to be passive refactoring.&lt;/p&gt;

&lt;p&gt;So, in the cases where there is a semantic HTML element available, I prefer to just specify &lt;em&gt;that element&lt;/em&gt;, and that way the tests will fail if somebody refactors to a pattern that uses non-semantic elements to recreate existing HTML functionality.&lt;/p&gt;

&lt;p&gt;This element-level approach also nudges developers towards  accessibility success, by forcing them to either follow the first rule of ARIA in their refactoring, or modify the test code if they change the implementation. That means that in a pull request, for example, a reviewer would see unexpected test changes resulting from a refactor (where tests shouldn't change) and hopefully ask why semantic HTML was no longer being used. There's at least an extra layer of protection there.&lt;/p&gt;

&lt;h3&gt;
  
  
  The first rule of ARIA
&lt;/h3&gt;

&lt;p&gt;ARIA stands for &lt;a href="https://www.w3.org/TR/using-aria/#rule1"&gt;Accessible Rich Internet Applications&lt;/a&gt; and it's a specification that teaches us how to create online experiences that are likely to be functional for people with disabilities.&lt;/p&gt;

&lt;p&gt;The first rule of ARIA is:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you can use a native HTML element &lt;a href="https://www.w3.org/TR/using-aria/#bib-html51"&gt;HTML51&lt;/a&gt; or attribute with the semantics and behavior you require &lt;strong&gt;already built&lt;/strong&gt; in, instead of re-purposing an element and adding an ARIA role, state or property to make it accessible, &lt;strong&gt;then do so&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The reason for this is to take advantage of what the browser provides, which is highly likely to work correctly with assistive technology, instead of doing a custom implementation of the same functionality.&lt;/p&gt;

&lt;p&gt;One way to think about this is: the &lt;em&gt;absolute best&lt;/em&gt; you can do for users when implementing a custom button, is to faithfully recreate everything the browser already does in the "button" contract, except your version won't support High Contrast Mode. &lt;/p&gt;

&lt;p&gt;There is no value to writing and owning code that reimplements browser functionality - your company doesn't need it, you don't need it, and your users definitely don't need it. &lt;/p&gt;

&lt;h3&gt;
  
  
  Related practices
&lt;/h3&gt;

&lt;p&gt;A lot of Testing Library advocates are also fans of other good practices, like using explicit types with TypeScript. &lt;/p&gt;

&lt;p&gt;A &lt;code&gt;ByRole&lt;/code&gt; locator essentially says that there is only one required property of an element, and everything else about its accessibility contract is optional - the test will accept whatever has that one single property. Specifying the correct semantic element, on the other hand, is a way to force the test to only except something where the browser is implementing the full contract. Following the first rule of ARIA in our tests, as well as our code, gives us the most "type safety" in this sense. &lt;/p&gt;

&lt;p&gt;The alternative solution is to assert all of the expected accessibility behaviors in your tests, in addition to locating the element by its role, which is absolutely the way to go if &lt;strong&gt;you&lt;/strong&gt; own the code that implements that functionality.&lt;/p&gt;

&lt;p&gt;Another good practice is in web development is "using the platform", not fighting it. The first rule of ARIA perfectly aligns with this: using correct semantic elements allows browsers and operating systems to meet the needs of disabled users, and provides the best compatibility with assistive technology. When people say the web is "accessible by default", semantic HTML is at the heart of this statement.&lt;/p&gt;

&lt;p&gt;Developers can still override things and break semantic elements of course, but semantic HTML is still a better foundation and more likely to be accessible. So having our tests depend on this aspect of code seems worth it.&lt;/p&gt;

&lt;h3&gt;
  
  
  What we expect developers to know
&lt;/h3&gt;

&lt;p&gt;Because of the first rule of ARIA, I don't see any valid use case for &lt;code&gt;role="button"&lt;/code&gt; in code. We should only see the &lt;code&gt;role&lt;/code&gt; attribute being used for custom widgets that &lt;strong&gt;do not have&lt;/strong&gt; native HTML equivalents. &lt;/p&gt;

&lt;p&gt;The Testing Library docs point out something similar to the first rule of ARIA, but don't quite make the same conclusion:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note that setting a role and/or aria-* attribute that matches the implicit ARIA semantics is unnecessary and is not recommended as these properties are already set by the browser&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This recommendation makes clear that it is expected and desired that developers know they should prefer maintaining the native semantics of HTML. Since they need this knowledge to choose the correct accessible implementation of a given &lt;code&gt;role&lt;/code&gt;, we should take the mystery out of it and just specify the element that should be there in our tests. Then there is no need to hope that future developers know all the same nuances about accessibility. They can learn them when their non-semantic HTML causes a test failure.&lt;/p&gt;

&lt;h3&gt;
  
  
  When I still use &lt;code&gt;ByRole&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;I'll take a &lt;code&gt;ByRole&lt;/code&gt; selector any time for roles like &lt;code&gt;menu&lt;/code&gt;, &lt;code&gt;menuitem&lt;/code&gt;, &lt;code&gt;tabpanel&lt;/code&gt;, &lt;code&gt;treegrid&lt;/code&gt;... there are lots of useful accessible roles that are not yet implemented in standard HTML. Selecting them by role is a great idea, especially as it allow you to refactor &lt;em&gt;into semantic HTML&lt;/em&gt; without breaking a test, when elements with those roles do make their way into browsers.&lt;/p&gt;

&lt;p&gt;There are also some rare cases where ARIA roles are needed, even when there is overlap with semantic HTML elements. This might happen when working around some specific browser bug with the native element, for example, where owning the implementation of the accessibility contract is worth it because it lets you do something you can't do otherwise.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why I love &lt;code&gt;ByLabelText&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;OK, enough about why &lt;code&gt;ByRole&lt;/code&gt; is not my thing. Let's talk about some good stuff. Here's my favorite way to locate a form field in Cypress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myusername&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is not built in to Cypress -- I use the Testing Library plugin. It's elegant, readable, concise, and requires form fields to have a specific programmatically associated label present, which is also needed for assistive technology.&lt;/p&gt;

&lt;p&gt;If I wasn't using Testing Library, I might define a custom command that knows how to find labels in my application, executing something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;next&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;my-username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;But this depends on knowing the exact DOM structure, and here we don't care about that. There are a lot of correct ways to label a form input, it doesn't matter too much which way is used. One good thing is that here we are specifying a real input element, but Testing Library can do that too if we want to, using the &lt;code&gt;selector&lt;/code&gt; option:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;cy&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;findByLabelText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Username&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;input&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
  &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;type&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;myusername&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This option is explained in the docs:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If it is important that you query a specific element (e.g. an ) you can provide a selector in the options. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is also presumably why &lt;code&gt;ByText&lt;/code&gt; also takes a &lt;code&gt;selector&lt;/code&gt; option. Even though we want to avoid testing implementation details when they don't matter, Testing Library has built-in options so that you can still specify them when they do matter.&lt;/p&gt;

&lt;p&gt;In general the risk of developers creating custom inputs built out of divs and spans is pretty low, so I don't do that very often in practice. But it might be useful to use this pattern at the component test level, to give the developers instant feedback if they decide to get creative and reimplement an &lt;code&gt;input&lt;/code&gt; out of a custom &lt;code&gt;div&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;So why don't we pass this &lt;code&gt;selector&lt;/code&gt; option to our &lt;code&gt;ByRole&lt;/code&gt; locators, where the risks of using non-semantic elements are higher? Primarily because &lt;code&gt;ByRole&lt;/code&gt; doesn't support a selector option. That's for a pretty good reason as far as I can tell, since &lt;code&gt;ByRole&lt;/code&gt; is specifically intended to &lt;strong&gt;avoid&lt;/strong&gt; specifying the implementation. &lt;/p&gt;

&lt;p&gt;It would be pretty pointless and circular to write code that looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nf"&gt;getByRole&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sr"&gt;/submit/i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;selector&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;button&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="c1"&gt;// ⚠️ not possible, just an example&lt;/span&gt;
&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nf"&gt;click&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the above format, the &lt;code&gt;selector&lt;/code&gt; property would just override the role. On the other hand, in the &lt;code&gt;ByLabelText&lt;/code&gt; scenario, since many elements can have similar labels, passing a &lt;code&gt;selector&lt;/code&gt; option to further narrow what is acceptable makes more sense. You could have a Shipping and a Billing form on the same page with the same labels. You could have a &lt;code&gt;select&lt;/code&gt; and an &lt;code&gt;input&lt;/code&gt; with the same label text. &lt;/p&gt;

&lt;p&gt;Or you might want to pass something like a &lt;code&gt;[data-testid="header"] input&lt;/code&gt; selector if there are two instances of similar forms on the same page. &lt;/p&gt;

&lt;h3&gt;
  
  
  Oh yeah, what &lt;strong&gt;about&lt;/strong&gt; &lt;code&gt;data-testid&lt;/code&gt;?
&lt;/h3&gt;

&lt;p&gt;As a big believer in accessibility, and a longtime user of Testing Library, I want to take a second to stick up for the good old Test ID pattern, which still has its place and can be used in conjunction with specifying the element, or the role, or anything else.&lt;/p&gt;

&lt;p&gt;I strongly believe you need to cover the accessibility of your app with automated tests, and that means specifying the parts of the DOM that matter. The HTML we ship to users is &lt;em&gt;our product&lt;/em&gt; and we should all pay attention to the actual code we ship. There is an enormous, expensive, complicated system of servers, databases, and various tubes often involved in sending it from us to our users. We might as well send the right HTML.&lt;/p&gt;

&lt;p&gt;How I feel about Test IDs is this: if you've already specified the correct HTML output in one place, for example in component tests, then it's fine to use Test IDs elsewhere if you want.&lt;/p&gt;

&lt;p&gt;Especially if you have a separate QA team, not as familiar with what the "right" HTML and roles are, we don't need to block them from workflows using generic helper locators, as long as there are tests owned and run by the developers writing code that will fail if HTML accessibility is broken. You must make sure your something in your system will fail if accessibility regressions happen. &lt;/p&gt;

&lt;p&gt;On a personal level I'd be happy if everything went red when accessibility broke, because it's a critical thing for me. But as long as accessibility is specified, tested, and owned, then testing some workflows using Test IDs might actually have some upsides for certain teams.&lt;/p&gt;

&lt;p&gt;It's also the case that many applications are not built in an accessible way where roles, or even elements themselves, are appropriate for their functionality. Those apps still need to be tested, and if it's not easy or possible to remediate things on the fly, a generic Test ID is a better choice than something that, say, specifies the current &lt;em&gt;wrong&lt;/em&gt; role that something happens to have, and then causes confusion. &lt;/p&gt;

&lt;p&gt;Test IDs also come in handy when disambiguating different instances of similar elements, and in a few other situations. It's just important to know what they do and do not cover.&lt;/p&gt;

&lt;p&gt;I'm hoping to make a PR to the Cypress Best Practices documentation, which already endorses both Test IDs &lt;strong&gt;and&lt;/strong&gt; Testing Library, to get into some of this kind of detail about how to choose the approach. But as you can see, what I've got here currently long and unwieldy. I'm hoping writing this post will help me form a much shorter proposed update to the docs.&lt;/p&gt;

&lt;p&gt;If you've ready this far: thanks! And please let me know if you have thoughts or feedback. Am I missing something? Is the &lt;code&gt;ByRole&lt;/code&gt; locator awesome in a way I'm not accounting for?&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Here's the understanding I'm working with at the moment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Semantic HTML, when available, is always preferred over custom &lt;code&gt;role&lt;/code&gt; attributes for accessibility. This is the first rule of ARIA.&lt;/li&gt;
&lt;li&gt;While users do perceive the &lt;code&gt;role&lt;/code&gt; of an element, what they they &lt;em&gt;depend&lt;/em&gt; on is its entire contract, so a ensuring a role exists is not enough to guarantee behavior doesn't change in refactors.&lt;/li&gt;
&lt;li&gt;This means we should &lt;em&gt;not&lt;/em&gt; use a &lt;code&gt;ByRole&lt;/code&gt; locator if the role we are selecting on can be fulfilled by a native HTML element.&lt;/li&gt;
&lt;li&gt;Instead we should specify the HTML element itself in our tests. It will help developers do the right thing, and provide better feedback when refactoring, giving you one extra layer of resistance to accessibility bugs.&lt;/li&gt;
&lt;li&gt;We can do this in Testing Library by passing a &lt;code&gt;selector&lt;/code&gt; option to our &lt;code&gt;ByText&lt;/code&gt; and &lt;code&gt;ByLabelText&lt;/code&gt; locators. And we can likely do something like it in our framework of choice even if Testing Library is not available, such as with &lt;code&gt;cy.contains('selector', 'text')&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Writing tests this way aligns your tests and your development practices with the first rule of ARIA, which will give you a great foundation for building accessible apps and avoid some common accessibility pitfalls that trap even the most well-intentioned of us.&lt;/p&gt;

&lt;p&gt;Last note: Testing Library is still great and I'll still add it to every project to augment whatever I'm doing.&lt;/p&gt;

</description>
      <category>frontend</category>
      <category>cypress</category>
      <category>testing</category>
      <category>react</category>
    </item>
  </channel>
</rss>
