Focus events in Cypress are important for accessibility and user experience, particularly keyboard navigation.
Overview
What is Cypress.focus()
In Cypress, cypress.focus() is a command that helps trigger the focus on a specific DOM element, such as a button, input field, or similar focusable element. It simulates user interaction by programmatically focusing the element, letting you test behaviors like keyboard navigation, accessibility, and input field interactions.
Why Use Cypress.focus()
- Simulate user interactions
- Helps trigger focus events
- Validates accessibility
Learn what the Cypress focus method is, its use cases, best practices, and how to use it effectively with this comprehensive guide.
What is Cypress Focus?
Cypress.focus() is a command that simulates focusing on an element within a web application during automated testing. It ensures that focus can be programmatically applied to focusable elements, such as input fields, buttons, or links.
The.focus() command is particularly useful in testing scenarios where the focus event is key, such as in keyboard navigation validation or checking that visual cues (such as focus outlines) are rendered correctly.
Using cy.focus() allows testers to interact with elements as they would be used by the user, thereby confirming application behavior under focus. This is often combined with assertions to check the focus state, ensuring focus transitions are correct in scenarios that involve various user behaviors and are accessible.
Read More: How to handle Click Events in Cypress
How to Use cy.focus()
The cy.focus() command is used in Cypress to simulate focusing on a specific element during automated tests. It can be applied to focusable elements like input fields, buttons, and links to verify focus-related behavior.
Syntax:
cy.focus()
To use cy.focus(), simply chain it to a selector targeting a focusable element. This will simulate the focus event on the component.
cy.get('input[name="username"]').focus()
This command will focus on the input field with the name attribute “username”.
The cy.focus() command does not require any arguments. It operates on the element selected via Cypress commands like cy.get(), cy.contains(), or cy.find(). You must locate a focusable element before applying .focus() to it.
Example with an assertion:
cy.get('input[name="username"]').focus().should('have.class', 'focused')
In this example, after focusing on the username input field, the test checks if the element has a focused class applied.
cy.focus() does not trigger events like onFocus or focus natively; it simply moves the focus to the targeted element for testing purposes.
How to Focus an Element in Cypress (with Examples)
In Cypress, you can use the .focus() method to simulate focusing on an element, such as an input field, button, or any other focusable element. This is particularly useful when testing interactions that rely on focus events, such as keyboard navigation, form field validation, or visual focus styles.
1. Focusing on an Input Field
Suppose you want to test if an input field can be focused correctly. You can use .focus() to simulate the focus event on that element.
// Focusing on a text input field cy.get('input[name="username"]').focus()
In this example:
- cy.get(‘input[name=”username”]’) command selects the input field with the name attribute “username”.
- .focus() simulates the action of focusing on that input field.
2. Verifying Focus Style (e.g., CSS Focus Class)
You might want to verify that a CSS class (like focused) is applied when the element is focused. You can use .should() to assert the expected result.
// Focusing on an input field and verifying the focus class cy.get('input[name="username"]') .focus() .should('have.class', 'focused')
Here, after focusing on the input field, Cypress checks if the focused class is applied to the element.
3. Testing Focus on a Button
You can also use .focus() on other focusable elements like buttons. This helps ensure that focus works as expected for elements outside form fields.
// Focusing on a button element cy.get('button#submit').focus() .should('have.css', 'outline', '1px solid rgb(0, 0, 255)') // Assert focus outline
In this example:
- cy.get(‘button#submit’) selects the button with the id “submit“.
- .focus() Simulates focusing on the button.
- .should(‘have.css’, ‘outline’, ‘1px solid rgb(0, 0, 255)’) checks if the button has a visible outline (commonly used as a focus indicator).
4. Testing Keyboard Navigation Focus
If you need to verify the keyboard navigation flow, use .focus() to ensure focus moves correctly when the user navigates between elements.
// Focusing on the first input field and pressing Tab to move focus cy.get('input[name="username"]').focus() cy.get('input[name="password"]').should('not.be.focused') cy.focus().tab() // Simulate pressing the Tab key to move focus to the next field cy.get('input[name="password"]').should('be.focused') // Verify the password input is now focused
Here,
- First, the username input is focused.
- Then, it checks that the password field is not yet focused.
- cy.focus().tab() simulates pressing the Tab key to move focus to the next field (password).
- Finally, it verifies that the password input field is now focused.
In cases where the typing tab doesn’t work, you can use the experimental cypress-plugin-tab.
Real-World Use Cases of Cypress .focus()
The Cypress .focus() method is valuable for testing scenarios requiring focus management and keyboard navigation and ensuring accessibility standards are met.
Below are a few real-world use cases where .focus() can be used in automated testing, along with examples.
1. Validating Focus on Accessibility Elements
Focus management is crucial for users who rely on keyboard navigation or screen readers. When users interact with elements like modals, dropdowns, or interactive lists, it’s essential to ensure that focus is properly set and that elements are accessible.
You can test that the focus is correctly moved to a modal window when it’s opened and that the focus returns to the correct element when the modal is closed.
describe('Modal Focus Management', () => { it('should focus the modal and return focus to the button after closing', () => { // Visit the page with the modal cy.visit('https://example.com') // Click the button to open the modal cy.get('button#openModal').click() // Ensure the modal receives focus cy.get('.modal').should('be.visible').focus() cy.get('.modal').should('be.focused') // Ensure modal is focused // Simulate closing the modal cy.get('.modal-close').click() // Ensure focus returns to the open modal button cy.get('button#openModal').should('be.focused') }) })
After clicking the button to open the modal (cy.get(‘button#openModal’).click()), the test checks that the modal receives focus (cy.get(‘.modal’).should(‘be.focused’)). After closing the modal, the test asserts that the focus returns to the original button that opened the modal.
2. Ensuring Focus on Input Fields after Validation
Sometimes, after a user submits a form, the focus should be returned to an invalid input field for correction. This is especially useful in applications that provide inline validation.
After a form submission with invalid input, you can test that the focus is returned to the first invalid field (for example, an email input with an invalid format).
describe('Form Validation and Focus Return', () => { it('should return focus to the first invalid input after form submission', () => { // Visit the form page cy.visit('https://example.com/signup') // Submit the form with invalid data (e.g., invalid email) cy.get('input[name="email"]').type('invalidemail') cy.get('button[type="submit"]').click() // Ensure the email field is invalid and refocused cy.get('input[name="email"]').should('have.class', 'invalid') cy.get('input[name="email"]').focus().should('be.focused') }) })
The form is submitted with an invalid email (cy.get(‘input[name=”email”]’).type(‘invalidemail’)). After submission, Cypress verifies that the email input has an “invalid” class and that the focus is returned to the invalid email field using .focus().
Read More: How to perform Cypress Email Testing?
3. Testing Focus on a Dropdown Menu
In applications with complex UI components like dropdowns, it is critical for accessibility to ensure that the focus remains on the dropdown after opening and behaves as expected when using the keyboard to navigate options.
Here, you can verify whether the focus moves correctly between dropdown items when the user navigates through the options using the keyboard.
describe('Dropdown Keyboard Navigation', () => { it('should focus the correct dropdown items when using arrow keys', () => { // Visit the page with the dropdown cy.visit('https://example.com') // Open the dropdown cy.get('.dropdown-toggle').click() // Move focus to the first item using the down arrow key cy.focus().type('{downarrow}') cy.get('.dropdown-item').first().should('be.focused') // Move focus to the next item cy.focus().type('{downarrow}') cy.get('.dropdown-item').eq(1).should('be.focused') }) })
The dropdown is opened using .click() on the toggle button. Cypress simulates the down arrow key press using .type(‘{downarrow}’) to navigate the dropdown items. The test asserts that focus moves correctly between the items as the arrow key is pressed.
cy.focus() vs cy.focused()
cy.focus() is used to set the focus, while cy.focused() is used to verify whether a specific element has the focus.
Here are the key differences between cy.focus() and cy.focused():
Feature | cy.focus() | cy.focused() |
---|---|---|
Usage | cy.get(‘selector’).focus() | cy.get(‘selector’).should(‘be.focused’) |
Function | Moves the focus to the selected element. | Checks if the element is currently focused. |
Command Type | Action command (performs a focus action). | Assertion command (verifies the focus state). |
Return Value | No return value (focuses on the element). | Returns an assertion result (true/false). |
Common Use Case | Simulating focus in tests (e.g., form interaction, keyboard navigation). | Verifying if an element focused is typically used in assertions after actions. |
Can be chained? | Yes, with other commands (like .type(), .should()). | Yes, it can be chained with other assertions. |
Element Type | Works on any focusable element. | Asserts focus on an element, typically used for form fields, buttons, etc. |
Challenges of cy.focus() and the Solutions
While cy.focus() is valuable for simulating focus events in Cypress, you may encounter certain challenges during testing. Below are some common challenges and their solutions to ensure effective and reliable use of .focus().
- Focus Not Working on Dynamic or Delayed Elements: In some cases, you may attempt to focus on an element that isn’t immediately available in the DOM (due to animations, lazy loading, or delays in rendering). To solve this, use cy.get() with a .should(‘be.visible’) or .should(‘exist’) assertion to ensure the element is ready for interaction before applying .focus().
- Focus Applied But Not Reflected Visually: In some cases, .focus() may successfully focus an element, but you may not see any visible focus indicator (like a border or outline), especially if CSS styles aren’t correctly applied for focus states. You should always validate the visual focus state of elements to ensure that focus behavior aligns with accessibility and design requirements. Use .should(‘have.css’) to check for a focus style, such as an outline.
Read More: CSS Selectors in Cypress
- Issues with Focus on Non-Focusable Elements: Applying .focus() to non-focusable elements (like divs or spans that don’t have the tabindex attribute) may result in no visible effect or cause errors in your tests. Ensure you only use .focus() on elements that are focusable by default (e.g., inputs, buttons, links). If necessary, apply tabindex=”0″ to custom elements to make them focusable.
- Does not Trigger Focus Events: .focus() in Cypress doesn’t always trigger native focus events like onFocus. This can make it difficult to test event listeners or side effects that depend on focus-related events. To ensure that the focus event is fully triggered, use the .trigger() method to manually fire a focus event after applying .focus().
- Testing Focus with Complex Forms: In forms with multiple focusable elements or complex interactions (e.g., conditional visibility, validation errors), focus may not move as expected or may require additional interactions to trigger focus changes. Simulate user behavior by using .tab() to test the sequential movement of focus between form fields. Combine .focus() with keyboard navigation simulation to ensure focus flows as expected in complex form scenarios.
- Focusing on Modal or Overlay Elements: When testing modals or overlays, focusing on the correct element can be tricky if the modal is not fully visible or hidden behind other DOM elements (like overlays). Ensure that the modal or overlay is visible and not obstructed by other elements before applying .focus(). Use .should(‘be.visible’) or .scrollIntoView() to make sure the modal is in the correct state before focusing.
Why Run Cypress Tests on BrowserStack Automate?
BrowserStack Automate is a leading cross-browser testing platform that allows you to run Cypress tests on real browsers and devices in the cloud.
Here are the key reasons why integrating Cypress with BrowserStack Automate can enhance your testing strategy:
- Access to Real Devices & Browsers: Test across 3500+ real devices, OS and browsers, ensuring accurate results for user interactions and compatibility.
- Parallel Test Execution: Run tests concurrently across multiple environments, reducing execution time and speeding up feedback cycles.
- Seamless CI/CD Integration: Easily integrate with CI/CD tools like Jenkins, GitHub Actions, and Circle CI, automating your tests as part of the development workflow.
- Cross-Browser Testing: Ensure your app works over multiple browsers (like Chrome, Firefox, Safari etc.) and their versions enhancing compatibility and user experience.
- No Infrastructure Maintenance: Avoid managing testing infrastructure; BrowserStack handles everything, letting you focus on writing tests.
- Advanced Debugging Tools: Access screenshots, video recordings, and logs to quickly troubleshoot test failures.
- Scalability: Effortlessly scale your tests, from small projects to large suites, without infrastructure concerns.
- Cypress Dashboard Integration: Track test results in real time with the Cypress Dashboard, enabling better test management and faster issue resolution.
Best Practices for Using Cypress Focus
When using the .focus() method in Cypress, it’s important to follow best practices to ensure reliable and efficient tests, particularly when dealing with user interactions and accessibility features. Below are a few best practices to keep in mind:
Best Practices for using cypress.focus()
- Focus on Focusable Element
- Use Assertions After Focusing
- Avoid Overusing .focus()
- Use .focus() with Delays When Needed
- Focus on Focusable Elements: Always use .focus() on elements that are naturally focusable, such as input fields, buttons, or links. Focusing on non-focusable elements (like divs without tabindex) may lead to unexpected behaviour and unreliable tests.
- Use Assertions After Focusing: After using .focus(), it’s a good practice to immediately verify the element’s state using assertions like .should(‘be.focused’). This ensures that the element has received focus and behaves as expected.
- Avoid Overusing .focus(): While .focus() is a powerful tool for simulating focus, avoid overusing it unless necessary. Only use it when you need to test specific focus-related behaviors, such as ensuring elements receive focus on specific actions (like form submissions or keyboard navigation).
- Use .focus() with Delays When Needed: In some cases, especially with animations or transitions, it may be necessary to wait for an element to become focusable before applying .focus(). Use cy.wait() or cy.get().should() to ensure the element is in the right state before focusing on it.
Conclusion
Cypress .focus() method is vital for testing user interactions and accessibility, ensuring focus management works as expected across forms, buttons, and modals.
Integrating Cypress with BrowserStack Automate enhances testing by providing access to a vast real device cloud, cross-browser compatibility, and parallel test execution. This combination streamlines the testing process, improves test coverage, and helps deliver high-quality applications faster, ensuring seamless user experiences and robust accessibility compliance.
Useful Resources for Cypress
Understanding Cypress
- Cross Browser Testing with Cypress : Tutorial
- Run Cypress tests in parallel without Dashboard: Tutorial
- Handling Test Failures in Cypress A Comprehensive Guide
- Cypress Test Runner: Tutorial
- Handling Touch and Mouse events using Cypress
- Cypress Automation Tutorial
- CSS Selectors in Cypress
- Performance Testing with Cypress: A detailed Guide
- Cypress Best Practices for Test Automation
- Test React Native Apps with Cypress
- Cypress E2E Angular Testing: Advanced Tutorial
- Cypress Locators : How to find HTML elements
- Maximizing Web Security with Cypress: A Step-by-Step Guide
- Conditional Testing in Cypress: Tutorial
- Cypress Web Testing Framework: Getting Started
- Cypress Disable Test: How to use Skip and Only in Cypress
- What’s new in Cypress 10? How it will change your current testing requirements
Use Cases
- How to Record Cypress Tests? (Detailed Guide)
- How to run your first Visual Test with Cypress
- How to Fill and Submit Forms in Cypress
- How to Automate Localization Testing using Cypress
- How to run Cypress Tests in Chrome and Edge
- How to use Cypress App Actions?
- How to Run Cypress Tests for your Create-React-App Application
- How to Run Cypress Tests in Parallel
- How to handle Click Events in Cypress
- How to Test React using Cypress
- How to Perform Visual Testing for Components in Cypress
- How to run UI tests in Cypress
- How to test redirect with Cypress
- How to Perform Screenshot Testing in Cypress
- How to write Test Case in Cypress: (with testing example)
Tool Comparisons