Selected value
Option's value
<select>
<option value="456">apples</option>
<option value="457">oranges</option>
<option value="458">bananas</option>
</select>
Let's select the option "oranges" and see what value it has. We can use cy.select It yields the jQuery for the original <select>
element.
cy.get('select')
.select('oranges')
.should(($el) => {
expect(Cypress.dom.isElement($el), 'yields DOM element').to
.be.true
expect(Cypress.dom.isJquery($el), 'wrapped in jQuery').to.be
.true
// note: the yielded element is the <select>
expect($el.prop('nodeName'), 'element type').to.equal(
'SELECT',
)
expect($el.val(), 'option value').to.equal('457')
})
// shorter assertion using chaining
cy.get('select')
.select('oranges')
.invoke('val')
.should('equal', '457')
// you can yield the value without retrying
cy.get('select')
.select('oranges')
.invoke('val')
.then((value) => {
expect(value).to.equal('457')
})
You can select multiple options, yielding list of elements
<select multiple>
<option value="456">apples</option>
<option value="457">oranges</option>
<option value="458">bananas</option>
</select>
cy.get('select')
.select(['apples', 'bananas']) // yields <select> element
.invoke('val') // calls $(<select>).val() which returns list of selected values
.should('deep.equal', ['456', '458'])
Selecting option by index
Imagine we have a <select>
element and want to select an option by index. Let's say we want to select the option at index 1 and confirm it has text "oranges" and value "457".
<select>
<option value="456">apples</option>
<option value="457">oranges</option>
<option value="458">bananas</option>
</select>
// every child of <select> is an <option> element
cy.get('select')
.children()
.eq(1)
.then(($option) => {
expect(
$option.prop('label'),
'cannot compare 🍎 to 🍊',
).to.equal('oranges')
const value = $option.attr('value')
expect(value).to.equal('457')
// if we want to select the oranges,
// let's use the value we got
cy.get('select').select(value)
})
// let's confirm the selected option
cy.get('select').invoke('val').should('equal', '457')
Selecting the random option
Imagine we have a <select>
element and want to select one of its options randomly.
<select>
<option value="456">apples</option>
<option value="457">oranges</option>
<option value="458">bananas</option>
</select>
// get the number of options available
cy.get('select option')
.its('length')
// pick a random number between 0 and n-1
// using the Lodash _.random function
.then((n) => Cypress._.random(0, n - 1))
// print the picked random number
.should('be.a', 'number')
// and then use the cy.select command
// to select it from the element
.then((index) => {
cy.get('select').select(index)
})
// confirm the selected value
cy.get('select')
.invoke('val')
.should('be.oneOf', ['456', '457', '458'])
Select the last option
Similarly, we can select the last option in two steps: first, find the value of the last <option>
element, then select it in the <select>
element.
<select>
<option value="apl">apples</option>
<option value="ora">oranges</option>
<option value="ban">bananas</option>
</select>
cy.get('select option')
.last()
.invoke('val')
.then((value) => {
cy.get('select').select(value)
})
// verify the last option was selected
cy.get('select').should('have.value', 'ban')
Verify options text
Let's say we want to verify all available options and confirm their text. The options below should include only "BMW", "Mercedes", and "Audi".
<select id="cars_list">
<option value="-1">--Select Car--</option>
<option value="B">BMW</option>
<option value="M">Mercedes</option>
<option value="A">Audi</option>
</select>
The test is verbose on purpose, converting and confirming everything step by step.
cy.get('#cars_list option')
.then(($options) => {
// get the text of each option
return Cypress._.map(
$options,
($option) => $option.innerText,
)
})
.should('deep.equal', [
'--Select Car--',
'BMW',
'Mercedes',
'Audi',
])
// let's skip the "--Select Car--" default option
.then((list) =>
Cypress._.filter(list, (s) => s !== '--Select Car--'),
)
// and check now
.should('deep.equal', ['BMW', 'Mercedes', 'Audi'])
// TIP: sort the array for consistency
.invoke('sort')
.should('deep.equal', ['Audi', 'BMW', 'Mercedes'])
Get selected option
You can get the currently selected option using the jQuery's :selected selector.
<select id="name">
<option>Joe</option>
<option>Mary</option>
<option selected="selected">Peter</option>
</select>
cy.get('select#name option:selected').should(
'have.text',
'Peter',
)
Escape value to select
Imagine that the option values come from an external source we cannot control. The values might have characters like double quotes "
that will make selecting the value difficult. In the example below, the value we want is present"
. Can we select it?
📺 Watch this example explained in the video Select An Option Manually By Setting An Attribute.
<select class="select" name="my-data" id="my-data">
<option value=""></option>
<option value="empty">empty</option>
<option value='present"'>First column</option>
<option value="main_column">main_column</option>
<option value="mesto">mesto</option>
<option value="akce">akce</option>
</select>
Initially the first option is selected
cy.get('#my-data option:selected').should('have.value', '')
Let's select the option with the value that has "
character. We cannot use the standard cy.select
command since it does not escape the value / text:
// 🚨 DOES NOT WORK
// Syntax error, unrecognized expression: option[value="present""]
cy.get('#my-data').select('present"')
Notice how the attribute value is quoted by Cypress, yet the value inside has a quote, breaking the string. We need to form the selector ourselves and select the option. We can escape all invalid characters in the text using the Cypress.$.escapeSelector
function. Then we can mark the option as selected by setting the attribute selected
.
// select the option ourselves by setting its attribute
const escaped = Cypress.$.escapeSelector('present"')
cy.get(`#my-data option[value="${escaped}"]`).invoke(
'attr',
'selected',
'selected',
)
// check the selected value
cy.get('#my-data option:selected').should(
'have.text',
'First column',
)
cy.get('#my-data').should('have.value', 'present"')
Select when the element becomes actionable
<select class="select" name="my-data" id="my-data" disabled>
<option value=""></option>
<option value="empty">empty</option>
<option value='present"' disabled>First column</option>
<option value="main_column">main_column</option>
<option value="mesto">mesto</option>
<option value="akce">akce</option>
</select>
<script>
setTimeout(() => {
document
.getElementById('my-data')
.removeAttribute('disabled')
}, 1000)
setTimeout(() => {
document
.querySelector('#my-data option[value=present\\"]')
.removeAttribute('disabled')
}, 2000)
</script>
We need to ensure both the <select>
element and the <option>
we want to pick are enabled. If we don't then our test does not do what the human user can do. We can attach assertion to the queries.
// select the option ourselves by setting its attribute
const escaped = Cypress.$.escapeSelector('present"')
// wait until the select element becomes actionable
cy.get('#my-data')
.should('be.visible')
.and('be.enabled')
.find(`option[value="${escaped}"]`)
.should('be.enabled')
.invoke('attr', 'selected', 'selected')
// check the selected value
cy.get('#my-data option:selected').should(
'have.text',
'First column',
)
cy.get('#my-data').should('have.value', 'present"')