Capybara - how to see if a dropdown element is selected? - selenium

My HTML is
<select id="auto_policy_autos_attributes_0_ownership" name="auto_policy[autos_attributes][0][ownership]">
<option value="Owned">Owned</option>
<option value="Financed">Financed</option>
<option value="Leased" selected="selected">Leased</option></select>
and I can select up to
find('select#auto_policy_autos_attributes_0_ownership option[value="Leased"]')
correctly, but how do I see if it has been checked?
I tried
find('select#auto_policy_autos_attributes_0_ownership option[value="Leased" selected="selected"]')
but I get
Selenium::WebDriver::Error::InvalidSelectorError: invalid selector:
An invalid or illegal selector was specified
I had hopes for
'select#auto_policy_autos_attributes_0_ownership option[value="Leased"], selected')).to be
but I get a false positive as
'select#auto_policy_autos_attributes_0_ownership option[value="Owned"], selected')).to be
returns true, even though I have selected Leased with
select 'Leased', from: 'auto_policy_autos_attributes_0_ownership'
which I can see working in the browser.

You can use the be_selected matcher:
expect(#session.find('select#auto_policy_autos_attributes_0_ownership option[value="Leased"]')).to be_selected

One option was
expect(has_select?('auto_policy_autos_attributes_0_ownership', selected: 'Leased')).to be true

This is exactly what the capybara have_select matcher is designed for
expect(page).to have_select('auto_policy_autos_attributes_0_ownership', selected: 'Leased')
which describes what you're checking for -- a specific select element with a specifically selected option, and provides for a nice error message when failure happens.
If you really want to stick with the predicate matcher you could also do
expect(find(:option, 'Leased')).to be_selected
although that option could be in any select on the page unless you used a within block or scoped the find to a specific select.

Related

Why are my Vue/Nuxt Select field states valid by default?

I have a variety of HTML select elements inside of Nuxt.js. I'm also using Vuelidate for validation and this is working as expected. This is a typical select box in my form:
<select
id="location"
name="location"
v-model="form.location"
#blur="$v.form.location.$touch()"
:class="{error: appendErrorClass($v.form.location)}"
>
<option :value="null" hidden>Choose...</option>
<option
v-for="(item, index) in $store.state.quotes.data.practiceStates"
:key="index"
:value="item.data">
{{item.display}}
</option>
</select>
Before selecting any of the options, I'm noticing the following on all select fields.
I've tried removing any Vue magic on a test select field to see if the same results happen.
<select id="location1" name="location1">
<option value="" hidden>Choose...</option>
<option value="one">one</option>
<option value="two">two</option>
<option value="three">three</option>
</select>
Still seeing valid: true. Is there anything I'm overlooking that would cause the validity to default to true? Thanks in advance for any help or guidance on this issue.
UPDATE For Clarification:
Vuelidate validation works just fine. The issue I'm dealing with is the select field property Validity.validate. I only mention Vuelidate to give full context.
HTML Select is a sort of "strange" form element in that validity is typically checking to see if there's a readable value. Since a select always has something picked, it validates...
This is different from say a telephone input that has a specific pattern required to be valid.
I haven't used Vuelidate specifically, but I read the docs as saying, if you left the v-model="form.location" there's a good chance it's simply validating that a value exists so Any selcted item would qualify.
In my original post, I referenced the dynamic style based on the vuelidate library: :class="{error: appendErrorClass($v.form.location)}"
#PierreSaid responded to this post and later deleted his/her reply. Turns out, his response was helpful in pointing me to some Vuelidate attributes that were able to assist in a workaround for my issue. Thank you, PierreSaid.
I have since updated that dynamic class to be a mixin that looks like this:
export default {
methods: {
appendErrorAndValidityClass(field) {
return {
error: field.$error,
invalid: field.$invalid,
};
}
}
};
After importing the mixin into the Vue partial, my select box looks like this:
<select
id="location"
name="location"
v-model="form.location"
#blur="$v.form.location.$touch()"
:class="appendErrorAndValidityClass($v.form.location)"
>
This appends a class of invalid when the select field has not been updated. It also updates the error style accordingly. Now, I can assign styles for when the select field has an invalid class. This solves the overall issue for me. Thanks for your help PierreSaid and Bryce.

Robot Framework: passing argument to a keyword that returns an XPath

In my RF-Selenium project I have a language selection with a couple different options to choose from, which I locate through xpath. I usually separate my high-level keywords, locators/global variables and tests in 3 different files, so I need to get the xpath in one file and keywords in other.
The xpath that I tested and works when hardcoded looks like this: //select[#id="language"]/option[#value="?hl=es"] (and then change the 'es' to any other language identifier to locate other options). So, following the suggestions here I built a "GET LOCATOR" keyword to take a language identifier as a parameter and return the correct xpath:
GET LOCATOR
[Arguments] ${language}
${option locator} Replace String ${LANG} placeholder ${language}
[Return] ${option locator}
I have two different keywords that would use the return value from the GET LOCATOR keyword: in one of them I verify the currently selected language is disabled in the selection list:
${current} Get Element Attribute html#lang
Element Should Be Disabled GET LOCATOR ${current}
and then I actually select a different language and check the page has switched to it:
Select From List By Value ${LANGUAGE SWITCH} es
Wait Until Page Contains Element GET LOCATOR 'es'
All of these is in the Resources file, while the ${LANGUAGE SWITCH} and ${LANG} variables are in a different file (and the Replace String keyword is in the String RF standard library).
The ${LANGUAGE SWITCH} variable holds a css selector that successfully locates the language dropdown. And I already did some tests without the GET LOCATOR keyword and they passed, like:
${current} Get Element Attribute html#lang
Element Should Be Selected xpath=//select[#id="language"]/option[#value="?hl=${current}"]
So I suspect there's a problem with my placeholder xpath, stored in the ${LANG} variable: xpath = //select[#id="language-switch"]/option[#value="?hl=placeholder"]
And this is the DOM part with the language selection dropdown:
<select id="language">
<option value="?hl=ar">Arabic</option>
<option value="?hl=zh-TW">Chinese (Traditional)</option>
<option value="?hl=nl">Dutch - Nederlands‎</option>
<option value="?hl=en" selected="" disabled="">English</option>
<option value="?hl=el">Greek</option>
<option value="?hl=es">Spanish‎</option>
</select>
To make things worse, the test using this keyword fails with no error message, as I only get:
| FAIL |
en
So... what am I doing wrong here?
You cannot call a second keyword from Element should be disabled and Wait Until Page Contains Element. What is happening is that Element should be disabled thinks the locator is the string GET LOCATOR (which obviously doesn't exist), and the custom error message is es.
You will need to break that down into two steps:
${locator}= GET LOCATOR ${current}
Element should be disabled ${locator}

How to get value of checkbox in capybara?

i have code html like this
<input type="checkbox" class="class-of-checkbox" value="facebook">
how to get the value (facebook) ?
You first need to uniquely find the element and then call value on it. How you find the element uniquely can be highly dependent on the structure of the rest of the page, but based on just the single element HTML you've provided (and you not actually knowing what the value already is) either of the following could be a starting place
find('.class-of-checkbox').value
find_field(type: 'checkbox', class: 'class-of-checkbox').value
If you just want to verify the value of an element with an expectation then you could do (assuming RSpec with cucumber)
expect(page).to have_field(type: 'checkbox', with: 'facebook', class: 'class-of-checkbox') # you can also pass :checked option if you want to verify it is checked - or use have_checked_field/have_unchecked_field

Select option robotframework

Really quick (but complicated?) question.
I have this:
<select multiple="multiple" id="id_products" class="selectmultiple" name="products">
<option value="3243">testproductP (3243)</option>
<option value="3244">testproductQ (3244)</option>
</select>
I need to robotframework with selenium to replicate that I select an option. However I can not find a keyword like "Select Option". So I tried using "Click Element" with an xpath pointing to the option.
Click Element xpath=//select[#name="products"]/option[#value=3244]
However this fails the test with the error: "timeout: timed out"
The xpath returns the correct element, but somehow it times out. Maybe Click Element is not supposed to be used like this, but I can't find a better keyword.
Any idea what's going on?
Click Element waits for a page load event unless you give it an additional parameter telling it not to wait. However, you should also be able to use the "Select From List" keyword.
Have fun!
You can use
Select From List ${XPATH} Value
Use " select element by value " keyword and specify the Xpath of the list dropdown and value of component which you want to select from list.
Select From List By Value Xpath=""/ID=""/Name="" Value
Try to select the element using Javascript. Example:
Execute Javascript document.querySelector("your css").click()

Filtering Select - How to add a blank option '-' that allows submission in Dojo

Been trying to fix this for a while now. I have loads of Dojo Filtering Select elements in my form. I need them to have a blank option which should be selected by default. Here is an example (of a normal <select> structure) that I want to emulate:
<select>
<option value="">-</option>
<option value="foo">Bar</option>
</select>
At present when I load up my filtering selects that have the options set as above, there is no element selected. This in turn disables form submission. This is totally unusable for my end users as they would have no idea why the form is not working. The selects are not even required fields.
The problem lies in the way the FilteringSelect stores it's data. It keeps them in a data store that requires an identifier and a label. You can't quite emulate the functionality of a plain select because of this.
You can 'get around' this by putting a fake item in your options with a value of 'XXXX' (or another fake value).
<select>
<option value="XXXX">-</option>
<option value="foo">Bar</option>
</select>
One downside of this kludge is that you need to change your validation functions to look for this fake value (instead of an empty value).
I set up a test on jsbin.com where you can see it in action.