How to Use Testing Library with Cypress
Add Testing Library’s accessible DOM queries to Cypress, configure the support file, and use retryable queries in end-to-end and component tests.
Install @testing-library/cypress, import its command setup from your Cypress support file, then use cy.findBy… and cy.findAllBy… to locate elements by the way people identify them. These queries work with Cypress’s retry behavior, so Cypress can wait for matching content to appear.
npm install --save-dev cypress @testing-library/cypress
If Cypress is already installed, add only @testing-library/cypress. The current Cypress requirements and installation steps depend on the release and environment; consult the official Cypress installation guide.
1. Register the Testing Library commands
In a JavaScript project, import the package’s command registration in the support file Cypress loads for the tests. The common end-to-end support path is cypress/support/commands.js; ensure your Cypress support entry point imports that file if your project separates command definitions from support setup.
// cypress/support/commands.js
import '@testing-library/cypress/add-commands';
If the project uses CommonJS, the equivalent is:
// cypress/support/commands.js
require('@testing-library/cypress/add-commands');
Make sure the file is part of the support-file path configured for the test type you run. End-to-end and component tests can have separate support files, so register the commands in each support entry point where you need them.
2. Query controls the way a user would
Use a role and accessible name when those describe how someone interacts with the control. Cypress Testing Library adds findBy and findAllBy commands to cy:
cy.findByRole('button', { name: /save/i }).click();
cy.findByRole('dialog').within(() => {
cy.findByRole('button', { name: /confirm/i }).should('exist');
});
Here is a complete example for a page where saving displays a confirmation message:
describe('profile settings', () => {
it('saves the profile and shows confirmation', () => {
cy.visit('/settings/profile');
cy.findByRole('textbox', { name: /display name/i })
.clear()
.type('Ada Lovelace');
cy.findByRole('button', { name: /save/i }).click();
cy.findByRole('status').should('contain.text', 'Changes saved');
});
});
The example assumes the page exposes a textbox with an accessible name, a button named Save, and a status message. Adapt the query and expected message to the application’s actual accessible interface.
For asynchronously rendered content, findBy is useful because the query can retry while Cypress waits for a match. For example:
cy.findByRole('heading', { name: /results/i }).should('be.visible');
cy.findAllByRole('listitem').should('have.length', 3);
Use findAllBy… when the expected result is a collection. Add an assertion for the number or content of matches if that is part of the behavior you intend to verify.
3. Scope queries to a form or container
When a page has repeated labels or buttons, narrow the search to the relevant region. Cypress Testing Library supports scoped usage with Cypress and jQuery elements as well as DOM nodes:
cy.get('form').findByRole('button', { name: /submit/i }).click();
cy.findByRole('region', { name: /billing address/i }).within(() => {
cy.findByLabelText(/postal code/i).type('10001');
});
Prefer a meaningful accessible container when one exists. A CSS container such as form is also reasonable when it clearly identifies the intended scope.
4. Choose a query that matches the test’s intent
Semantic queries can show that a test interacts with the same role, label, or text a person would use. They are not automatically the right selector for every test. Follow the application’s conventions and choose a locator that expresses the behavior under test.
| What identifies the element | Testing Library query | Use when |
|---|---|---|
| Role and accessible name | findByRole |
The user-facing role and name are the behavior you want to exercise, such as a named button. |
| Form label | findByLabelText |
The field is identified by its label. |
| Visible text | findByText |
The text itself is the relevant content or interaction target. |
| Placeholder | findByPlaceholderText |
The placeholder is the locator your application intentionally exposes for this test. |
| Test attribute | findByTestId |
Your project uses a stable test attribute, such as data-testid or data-cy. |
Cypress’s migration guidance documents these semantic locator mappings and data attributes as an alternative. A test attribute can be useful when user-facing content is variable or when a component has no suitable accessible name. Semantic queries can make a user interaction explicit. Consider whether the locator tolerates expected copy or markup changes, whether the needed attribute already exists, and whether changing the application is warranted.
5. TypeScript setup
For TypeScript, the Cypress Testing Library guide recommends listing both Cypress and the integration in the compiler’s types option so the additional command types are available. Merge these entries with any types your project already uses:
{
"compilerOptions": {
"types": ["cypress", "@testing-library/cypress"]
}
}
Keep the runtime import in the support file as well; the TypeScript setting supplies type information and does not register commands at runtime.
6. Configure the integration when needed
Most projects can start with the default registration. If you need to adjust Cypress Testing Library behavior, call cy.configureCypressTestingLibrary(config) from the support setup after registering the commands. Check the configuration keys supported by your installed release in the official repository; do not copy configuration for a different version without checking it.
import '@testing-library/cypress/add-commands';
// Add only configuration supported by the installed package version.
cy.configureCypressTestingLibrary({
// configuration options
});
Configuration belongs in a place that runs as Cypress initializes the relevant tests. The example intentionally leaves the options object empty because the supported settings can vary by release.
7. Understand query behavior and version differences
The Cypress integration’s documented commands are findBy and findAllBy; its guide says get* queries are not supported. Its guide also says the query* commands are no longer needed since version 5 and are slated for removal in version 6. This is version-sensitive: inspect the installed package version and current guide before relying on that note.
More broadly, Testing Library query families differ in how they behave when there are no matches or multiple matches. The query guide explains the distinctions. In Cypress tests, use the integration’s supported retryable commands and assert the result you expect. Avoid replacing them with a query family that the Cypress integration does not expose.
8. Troubleshoot common setup and query problems
| Symptom | Likely cause | Fix |
|---|---|---|
findByRole is not a function or the command is unknown |
The add-commands import did not run for this test type, or the dependency is missing. | Install @testing-library/cypress, add the import to the support entry point used by this test, and confirm that Cypress loads that support file. |
TypeScript reports that findByRole does not exist on cy |
The package types are not included in the TypeScript configuration, or the installed versions/types are mismatched. | Add cypress and @testing-library/cypress to compilerOptions.types, check the installed versions, and restart the editor’s TypeScript service if it has cached old types. |
| A role query finds no element | The rendered element may not have the expected semantic role or accessible name, may not have appeared, or the test may be querying the wrong region. | Inspect the rendered page and accessibility semantics; use the correct role and accessible name, scope the query where needed, and confirm the element is rendered in this state. |
| A text or label query matches more than one element | The same text or label appears in multiple regions. | Scope the query with within or a container query, or use a locator that distinguishes the intended element. |
An example using getBy… fails in Cypress |
The Cypress integration’s guide documents findBy and findAllBy, not getBy. |
Use the supported Cypress command, such as cy.findByRole(…), and check the guide for the installed package version. |
| The Cypress binary fails to install or launch | The environment or platform may not meet the current Cypress release requirements, or installation may be incomplete. | Follow the current Cypress installation guide for your operating system, Node.js version, browser, and package manager. |
9. Keep the test suite reliable and efficient
- Test observable behavior. Query the control or content relevant to the user action, and assert the resulting state.
- Use retryable queries for changing pages. A
findByquery can wait for matching content to appear. Avoid adding arbitrary waits when a query and assertion can express the expected state. - Scope repeated content. A narrower query can avoid ambiguity and make failures point to the relevant part of the page.
- Use a deliberate selector policy. Apply semantic queries where they express the interaction; use stable test attributes where the project needs a locator independent of user-facing copy.
- Check setup once per test type. End-to-end and component suites may have different support files, so a working import in one does not prove it is loaded in the other.
- Keep versions aligned with current docs. Cypress environment requirements and integration behavior can change between releases.
Testing Library queries do not replace Cypress’s own test runner, browser setup, or test design. The performance and stability of a suite still depend on the application, the browser environment, and what each test does.
Or skip the browser setup
If you need a screenshot of a page while building or debugging the test, ScreenshotNeo provides a website screenshot API and MCP server. Its API accepts a URL in one GET request and returns an image or PDF. This does not install Testing Library or run Cypress; it can provide a page capture without setting up a browser automation script. See the ScreenshotNeo documentation.
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
ScreenshotNeo removes cookie banners, newsletter popups, and chat widgets before the shot. Bot checks, blank pages, and failed loads are never billed. Its MCP server lets AI agents use screenshot tools. The free plan includes 1,000 screenshots a month with no card; paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, no card required.
FAQ
Does this work for Cypress component tests as well as end-to-end tests?
The commands are registered through a Cypress support file. Add the import to the support setup used by the test type where you want to call them.
Should I use role queries for every element?
No. Use a role or label when it represents the intended user interaction. A stable test attribute can be appropriate when the application’s testing conventions call for one or semantic information is not a useful locator.
Can I use the usual Testing Library getBy queries in Cypress?
The Cypress integration guide documents findBy and findAllBy commands and says get* queries are unsupported. Follow the guide for the version installed in your project.
Where can I check the current setup details?
Use the Cypress Testing Library guide for integration setup and the Cypress installation guide for current environment requirements.


