'select react-select dropdown list option using cypress
Does anyone know how to select an option from a react-select dropdown list in a cypress test?
I have tried lots of stuff but to no avail.
Seems that react-select uses a hidden input. That cypress can not write into. And divs that cypress can also not write into either.
It also does not help that I do not know how to inspect the actual dropdown list in dev tools because it does not stay open.
I am using:
- react-select v2.4.1
- cypress v3.1.5
Edit 1:
@bkucera's answer works. The working Code I ended up was:
it('updates Person', () => {
cy.get('[data-id=bearbeiter]')
.find('.css-10nd86i')
.click()
.find('input')
.eq(1)
.focus()
cy.contains('Test Tester').click({ force: true })
})
I had to add an .eq(1)
after find
because there seem to be two inputs.
Edit 2:
Above solution ended up clicking on elements in the nav tree on my site that happened to contain the same text. So no cigar :-(
Edit 3:
I have also tried this solution:
Cypress.Commands.add('setSelectOption', ({ selector, option, value }) => {
cy.get(selector)
.find('.css-10nd86i input')
.eq(1)
.focus()
.type(value, { force: true })
})
...but even though force: true
is used I get this error:
The element typed into was:
> <input name="aeId" type="hidden" value="862333db-31cf-444c-b8ea-021c640c7a44">
Cypress considers the 'body', 'textarea', any 'element' with a 'tabindex' or 'contenteditable' attribute, or any 'input' with a 'type' attribute of 'text', 'password', 'email', 'number', 'date', 'week', 'month', 'time', 'datetime', 'datetime-local', 'search', 'url', or 'tel' to be valid typeable elements.
Edit 4:
So far this has worked best:
Cypress.Commands.add('setSelectOption', ({ selector, option, value }) => {
cy.get(selector)
.find('.css-10nd86i input:text')
.focus()
.type(option, { force: true, delay: 600, timeout: 330000 })
.type('{enter}', { force: true })
cy.get(selector)
.find('.css-10nd86i')
.find('input')
.eq(1)
.should('have.value', value)
})
At least it works for short lists. Text is entered slowly. For our species list (7000 long) I added those delay
and timeout
options. Delay seems to help but I have not been able to understand exactly how these options influence behaviour. And sometimes cypress times out :-(
Edit 5:
Meanwhile (react-select v3.0.4, cypress v3.3.2) all tests fail because:
Expected to find element '.css-10nd86i' but never found it
I guess the class has changed. Not surprising with such a brittle solution :-(
Solution 1:[1]
On Cypress 4.2.0 and react-select 3.0.8 pressing enter twice is working for me:
cy.get('#react-select-component-id').type('Something{enter}{enter}');
Solution 2:[2]
Unfortunately, you are running into two Cypress bugs, which are fixed in pending releases
1) an input that already has focus is being validated before
.type
, which is wrong2) when the browser is out of focus chrome does not fire blur/focus events, which react-select relies on. Due to this bug, you won't see the dropdown appear when the chrome window is not focused.
The next version of Cypress will polyfill these events, fixing this problem.workarounds:
for 1) you'll have to use
{force:true}
during the.type
(see below)for 2) you can either make sure to have the window focused when running the test, or see the workaround in the code below
it('react-select', () => {
cy.visit('https://react-select.com/creatable')
cy.get('.css-10nd86i input').eq(1) // get the first react-select input
.focus() // workaround for bug #2
.type('Ocean', {force:true}) // workaround for bug #1
})
another example:
it('react-select', () => {
cy.visit('https://react-select.com/creatable')
cy.get('.css-10nd86i').eq(1)
.click() // click on the react-select div
.find('input').focus() // workaround for bug #2
cy.contains('Ocean').click({force:true}) // workaround for bug #1
// Other actions to take ?
// cy.focused().type('{downarrow}{enter}', {force:true})
// cy.focused().type('{enter}', {force:true})
// cy.focused().type('Ocean', {force:true})
})
Solution 3:[3]
in the latest version of react-select
you can set classNamePrefix
property.
If you provide the classNamePrefix prop to react-select, all inner elements will be given a className based on the one you have provided.
For example, given classNamePrefix="react-select", the DOM would roughly look like this:
<div class="react-select"> <div class="react-select__control"> <div class="react-select__value-container">...</div> <div class="react-select__indicators">...</div> </div> <div class="react-select__menu"> <div class="react-select__menu-list"> <div class="react-select__option">...</div> </div> </div> </div>
Using this trick you can easily find react-select
components in Cypress using class selectors. For example, here is the code snippet to select first option:
cy.get('.react-select__control') // find react-select component
.click() // click to open dropdown
.get('.react-select__menu') // find opened dropdown
.find('.react-select__option') // find all options
.first()
.click() // click on first option
Also you can explore cypress tests in the official github repository of react-select.
Solution 4:[4]
I got this solution here:
"cypress": "^3.4.1"
"react-select": "^2.4.3"
cy
.get('[class*="-control"]')
.click(0, 0, { force: true })
.get('[class*="-menu"]')
.find('[class*="-option"]')
.eq(2)
.click(0, 0, { force: true })
Solution 5:[5]
You have to click first to open the react-select dropdown, and then click on the actual element you want to open. We use this syntax for that:
cy.get('.s3p-react-select__indicator').eq(1)
.click()
cy.get('[id^="react-select-"]').contains('<value_dropdownbox>')
.click()
And in does indeed use hidden input fields. To find the hidden input field open your developertools, choose elements and look for "input[type='hidden']".
At last an answer on your latest question:
It also does not help that I do not know how to inspect the actual dropdown list in dev tools because it does not stay open.
Try downloading the React select developer plugin for Chrome: https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi
If you have that open your Chrome developer tools, hit the React tab. Now click right on your React element and choose inspect element. You see all options you can do for that element. But probably it wont select the correct element at once, so look for the element with checkbox "menuIsOpen", and check it. The dropdown will stay open until something changes on the page
Solution 6:[6]
Pass the ID to react-select, and find it like:
cy.get('#country').within($el => {
cy.wrap($el)
.click()
.find('div[tabindex*="-1"]')
.first()
.click();
});
So, first query within the element, wrap it and fire the click event, then just use one of the data props that every element has, I went with tabindex -1 since every element has it, use eq(x) if you need specific element.
Solution 7:[7]
I found a simple solution to same problem:
-> cy.get('#basic_category').click() //getting id of dropdown by cy.get() and using click()
-> cy.contains('Test Category2').click() //typing name of what you want to pick from dropdown in cy.contains() and using click()
Solution 8:[8]
This worked for my State dropdown that has a data-testid
used for React Testing Library:
cy.get("[data-testid='shippingAddress.state']").type("California{enter}");
Using:
"@testing-library/react": "11.2.7"
"react-select": "3.2.0"
"cypress": "6.9.1"
Solution 9:[9]
In my case this helped:
cy.get("[for=country]")
.click()
.type("Poland{enter}");
But please remember I'm clicking on label, which nicely focus on react-select input.
Solution 10:[10]
I use Cypress 4.2.0, I am able to do the following chain commands:
Cypress.Commands.add('selectDropdownlist', (dropDownSelectionId) => {
cy.get('[data-id=bearbeiter]').click({force: true})
.get(`[id="${dropDownSelectionId}"]`).click() //the id or any selector of the value 'Test Tester'
})
Solution 11:[11]
You can try my code template. In this test I click on input, select option in menu list 3 times. Notice: After each selection of option my menu list closes, so I need to click on input after this.
it('test react-select', () => {
cy.get('#react-select-2-input').click().focus()
cy.get('#react-select-2-option-0').click()
cy.get('#react-select-2-input').click().focus()
cy.get('#react-select-2-option-1').click()
cy.get('#react-select-2-input').click().focus()
cy.get('#react-select-2-option-2').click()
})
Solution 12:[12]
This worked for me:
cy.get('[id="react-select-component"] select > option ').eq(3);
In my case, id is for select component:
<select id="name_select" name="name_select">
<option value="someValue_1"> someOptionText_1 </option>
<option value="someValue_2"> someOptionText_2 </option>
<option value="someValue_3"> someOptionText_3 </option>
</select>
eq(3) => value="someValue_2"; eq(1) header
Solution 13:[13]
There was a custom dropdown in a React-based application I was working on. So, I have written the following function to select a value from the dropdown.
// definition
function selectOptionFromDropDown(elDropdown, stOptionElement, stOptionToSelect){
cy.get(elDropdown).eq(0).click()
.find(stOptionElement).first().focus()
cy.contains(stOptionToSelect).click({force:true})
}
// calling
keywords.selectOptionFromDropDown('[id="dropdown-account-campaigns"]','input', 'Main (GBP)')
Solution 14:[14]
If the object is read-only, all you need is to read the object and then select it.
cy.get('XXXXX').click();
cy.contains(YYYY
).click({ force: true })
Solution 15:[15]
cy.get(' [name=" Optionwithcheck[] "] ').select( ['Option 2','Option 3'] )
Solution 16:[16]
Here is my solution. It is a bit generalized, but seems to be working fine for me. Mine does not rely on classes because as soon as they re-render they will probably be different so they will fail.
My solution just looks for tag types which there should only be one input:text
type anyway and you should be looking for a unique value in the dropdown that wouldn't be in the dropdown regardless.
// command.js
Cypress.Commands.add('setSelectOption', ({ selector, option, value }) => {
cy.get(selector)
.find('input:text')
.focus()
.type(option, { force: true, delay: 600, timeout: 330000 })
.type('{enter}', { force: true })
cy.get(selector)
.contains(value)
})
cy.setSelectOption({
selector: '#funding-opportunity-select',
option: '00',
value: '00 Funding Opportunity Template'
});
cy.setSelectOption({
selector: '#funding-cycle-select',
option: 'Test Funding Cycle',
value: "TPR Test Funding Cycle"
});
Solution 17:[17]
cy.get("[id*='react-select']")
.first()
.focus()
.type('some text in the list{enter}', { force: true });
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow