
Dropdowns are common in forms, filters, and configuration screens, but they can break tests when option values change, when the DOM re-renders, or when the UI uses custom components instead of native <select> elements. A reliable test must target the correct element, select the intended option, and verify that the underlying value and visible state both update as expected.
The select() command in Cypress interacts directly with native dropdown elements by setting the value and triggering the appropriate change events. Its behavior differs when the application uses custom or autocomplete dropdowns, where options are rendered dynamically and require a different selection strategy.
This guide explains how to use the Cypress select command across these scenarios with practical, test-focused examples.
The select() command in Cypress is used to choose one or more options from a native HTML <select> element. It programmatically sets the selected value and triggers the associated change event so that the application reacts the same way it would during a real user interaction.
Unlike a simple click action, select() works specifically with <select> tags and their <option> children. It allows selection by visible text, value attribute, or index, and it automatically handles matching the correct option inside the dropdown. For multi-select dropdowns, it can accept an array of values to select multiple options in a single command.
Because it operates at the DOM level, select() is reliable for standard dropdowns. However, it does not work for custom UI dropdowns built with divs or JavaScript frameworks, where options are not real <option> elements. Those cases require a different interaction approach using commands such as click() and assertions on rendered lists.
Writing stable dropdown tests requires two things: targeting the correct <select> element and verifying that the intended option is actually selected at the DOM level.
In Cypress, the select() command works only with native <select> tags, so the first step is always to confirm whether the dropdown is native or custom. Once confirmed, the selection strategy depends on how options are identified in the markup.
Below are the most common and practical patterns used in real test suites.
Selecting by index targets the option based on its position in the list. Indexing starts from zero.
cy.get('#country')
.select(2)
This selects the third option in the dropdown.
This method is simple, but it is tightly coupled to UI order. If the application reorders options, inserts a new entry, or applies sorting logic, the test may start selecting the wrong value without failing immediately. For that reason, index-based selection is best suited for controlled datasets or temporary test environments.
Selecting by value matches the value attribute of the <option> element.
Example HTML:
<select id="country">
<option value="IN">India</option>
<option value="US">United States</option>
</select>
Test:
cy.get('#country')
.select('IN')
This method is typically more stable because backend systems often rely on the value attribute rather than the visible label. If the displayed text changes from “United States” to “USA,” the test still passes as long as the value remains constant.
Selecting by visible text matches what the user sees in the UI.
cy.get('#country')
.select('India')
This approach improves readability because the test clearly reflects user intent. However, it becomes fragile if product teams frequently modify UI labels, apply localization, or add extra whitespace.
When using text-based selection, ensure the text matches exactly, including case and spacing.
For dropdowns with the multiple attribute, Cypress allows selecting more than one option by passing an array.
Example HTML:
<select id="skills" multiple>
<option value="js">JavaScript</option>
<option value="py">Python</option>
<option value="java">Java</option>
</select>
Test:
cy.get('#skills')
.select(['js', 'py'])
Cypress sets both values and triggers the appropriate change events. After selection, it is good practice to assert the selected values to prevent false positives.
Selecting an option is incomplete without verification. Assertions confirm that the correct value is applied at the DOM level.
For single select:
cy.get('#country')
.select('IN')
.should('have.value', 'IN')
For multi-select:
cy.get('#skills')
.invoke('val')
.should('deep.equal', ['js', 'py'])
The have.value assertion checks the underlying selected value, not just the visual state. This prevents tests from passing when the UI changes but the form state does not.
Autocomplete dropdowns are not native <select> elements. They are usually built with divs, list items, and dynamic rendering. The select() command does not work in these cases.
Instead, the interaction pattern involves typing into an input field and clicking the rendered suggestion.
cy.get('#search-country')
.type('Ind')
cy.contains('.dropdown-item', 'India')
.click()
cy.get('#search-country')
.should('have.value', 'India')
Because options are generated dynamically, synchronization becomes important. Cypress automatically retries commands until elements appear, which helps handle delayed rendering. However, selectors must target stable attributes such as data-test IDs rather than styling classes to reduce flakiness.
Autocomplete components require DOM-based interaction logic rather than value-based selection, which makes them structurally different from native dropdown testing.
Resetting a dropdown is relevant in form validation, negative test cases, and state-reset scenarios. A dropdown can be reset either by selecting its default option explicitly or by triggering a form reset action.
If the default option has a known value such as an empty string, it can be selected directly:
cy.get('#country')
.select('')
.should('have.value', '')
If the application includes a reset button that restores form state, the test should validate the dropdown after the reset action:
cy.get('#country')
.select('IN')
cy.get('#reset-btn')
.click()
cy.get('#country')
.should('have.value', '')
In both cases, the assertion verifies that the DOM value reflects the default state. Relying only on visual confirmation is insufficient because UI updates can differ from the underlying form value.
Dropdown behavior is not identical across all environments. Native <select> elements are rendered differently by browser engines, and mobile devices often replace them with system-level pickers.
Event timing, focus handling, scrolling behavior, and viewport constraints can vary between desktop Chrome, Safari, Firefox, and mobile browsers. A dropdown test that passes locally may fail in production because of rendering differences or device-specific interaction patterns.
Testing on real devices helps validate that the selected value updates correctly, that change events fire as expected, and that the dropdown remains usable across different screen sizes and operating systems. This is especially important for forms, checkout flows, and filtering components where incorrect selection handling directly affects user experience and business logic.
Running Cypress tests on a real device cloud such as BrowserStack enables validation across real browsers and physical mobile devices without maintaining in-house infrastructure. It allows teams to execute the same dropdown tests on multiple OS and browser combinations so issues related to rendering, interaction, or device behavior can be detected before release.
Dropdown testing in Cypress requires more than selecting an option and moving on. Stable tests depend on choosing the right selection method, targeting reliable attributes, and validating the underlying value at the DOM level. Native selects, multi-select fields, and autocomplete components each demand a slightly different interaction pattern, and ignoring those differences often leads to flaky or misleading results.
To ensure dropdown behavior remains consistent across browsers and devices, execution on real environments becomes critical. Platforms such as BrowserStack allow Cypress tests to run on real browser and device combinations, helping teams catch rendering issues, event inconsistencies, and mobile-specific behavior before production release.
Get visual proof, steps to reproduce and technical logs with one click
Try Bird on your next bug - you’ll love it
“Game changer”
Julie, Head of QA
Try Bird later, from your desktop