How do I use Capybara to check that a select box has certain values listed as options?
It has to be compatible with Selenium...
This is the HTML that I have:
<select id="cars">
<option></option>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="mercedes">Mercedes</option>
<option value="audi">Audi</option>
</select>
This is what I want to do:
Then the "cars" field should contain the option "audi"
Try using the capybara rspec matcher have_select(locator, options = {}) instead:
#Find a select box by (label) name or id and assert the given text is selected
Then /^"([^"]*)" should be selected for "([^"]*)"$/ do |selected_text, dropdown|
expect(page).to have_select(dropdown, :selected => selected_text)
end
#Find a select box by (label) name or id and assert the expected option is present
Then /^"([^"]*)" should contain "([^"]*)"$/ do |dropdown, text|
expect(page).to have_select(dropdown, :options => [text])
end
For what it's worth, I'd call it a drop-down menu, not a field, so I'd write:
Then the "cars" drop-down should contain the option "audi"
To answer your question, here's the RSpec code to implement this (untested):
Then /^the "([^"]*)" drop-down should contain the option "([^"]*)"$/ do |id, value|
page.should have_xpath "//select[#id = '#{id}']/option[#value = '#{value}']"
end
If you want to test for the option text instead of the value attribute (which might make for more readable scenarios), you could write:
page.should have_xpath "//select[#id = '#{id}']/option[text() = '#{value}']"
As an alternative solution, and as I'm not familiar with xpaths, I did this to solve a similar problem:
page.all('select#cars option').map(&:value).should == %w(volvo saab mercedes audi)
Its quite simple, but took me some time to figure out.
Well, since i was around and saw the question (and been testing today) decided to post my way:
within("select#cars") do
%w(volvo saab mercedes audi).each do |option|
expect(find("option[value=#{option}]").text).to eq(option.capitalize)
end
end
Then I should see "audi" within "#cars"
should do the trick
Related
I'm spec-ing my form that will have some date pickers.
expect(page).to have_select('Start date') and expect(page).to have_select('deal[start_date]') both return no matches. The latter makes sense given that the html for date pickers is a little funky (name="deal[start_date(2i)])
expect(page).to have_date_select('deal[start_date]') says that Capybara doesn't recognize has_date_select.
Is there a way to do this?
Capybaras has_select? predicate and have_select matcher look for HTML <select> elements. Depending on what you mean by a date picker you'll have to use a matcher that would match the correct type of element, or have_selector if there isn't a specific matcher. If what you are actually checking for is an <input type="date"> element with an associated label containing the text 'Start date' then you can use the have_field matcher:
expect(page).to have_field 'Start date', type: 'date'
If you're using the Rails date_select view helper it produces HTML like
<div class="field">
<label for="post_start_date">Start date</label>
<select id="post_start_date_1i" name="post[start_date(1i)]">
<option value="2014">2014</option>
<option value="2015">2015</option>
...
</select>
<select id="post_start_date_2i" name="post[start_date(2i)]">
<option value="1" selected="selected">January</option>
<option value="2">February</option>
...
</select>
<select id="post_start_date_3i" name="post[start_date(3i)]">
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
...
</select>
</div>
You can see from looking at that HTML that the <label> element isn't actually associated with any of the form fields (the for attribute doesn't match an id) which means you won't be able to match the <select> elements using the label text. Instead you'd need to use either the id or name and match them individually
expect(page).to have_select('post_start_date_1i')
expect(page).to have_select('post[start_date(2i)]')
...
or you could use the id filter with a regex and a count to check that there are 3 elements matching like
expect(page).to have_select(id: /^post_start_date_[123]i$/, count: 3)
Note, that's not technically as 'correct' as doing them individually since you could actually have 3 elements with id of post_start_date_1i and it would still pass, but in that case your HTML would also be invalid.
If that's not the type of HTML element you're checking for then you'll need to provide the HTML to get an exact answer.
I have a dropdown list that has a list of locations.
When someone views the page, I want to test to to see if the default selected value is "anywhere"
RSpec.describe AccountController, type: :controller do
context "with render_views" do
render_views
describe "GET new" end
it "defaults to anywhere in location drop down list" do
get :new
expect(....) ???
end
end
end
end
How can I do this?
You can test in the HTML if the <option> with the expected value has the attribute selected.
As shown in this example, here's how a selected option looks like:
<select>
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="vw">VW</option>
<option value="audi" selected>Audi</option>
</select>
You can use assert_select (even if you use RSpec) to test the expected HTML tag.
I'm trying to troubleshoot a feature spec I'm writing to learn Rails & testing. It's an edit_spec for a Rails 4 app. I'm using RSpec and Capybara.
The Problem:
Capybara can not find elements from two drop down lists on a form. Here's the relevant parts of my form's source code:
<div class="field">
<label for="appointment_member_id">Member</label><br>
<select id="appointment_member_id" name="appointment[member_id]">
<option value="1">Callis Callis</option>
<option value="2">Rachale Rachale</option>
<option value="3">Hal Hal</option>
<option value="4">Kallis Kallis</option>
<option value="5">Earle Earle</option>
<option value="6">Rudy Rudy</option></select>
</div>
<div class="field">
<label for="appointment_trainer_id">Trainer</label><br>
<select id="appointment_trainer_id"
name="appointment[trainer_id]"> <option value="1">Jacob Jacob</option>
<option value="2">Michele Michele</option>
<option value="3">Alex Alex</option>
<option value="4">Yanni Yanni</option>
<option value="5">Upton Upton</option>
<option value="6">Willham Willham</option></select>
</div>
In my edit_spec, I tried using "option value" and "select id" to get Capybara to select names from the drop-down lists:
select('4', :from => 'appointment_member_id')
select('2', :from => 'appointment_trainer_id')
The result is a Capybara::ElementNotFound error. Here's the full text of the error message:
updates an appointment successfully with corrected information (FAILED - 1)
Failures:
1) Editing appointments updates an appointment successfully with corrected information
Failure/Error: select('4', :from => 'appointment_member_id')
Capybara::ElementNotFound:
Unable to find option "4"
I researched the issue and documentation for Capybara, and also a Stackoverflow post with similar problem. The poster solved the issue, but couldn't recall how he did it. I'm baffled as to why Capybara can't find the member and trainer from the drop down list? The option values and names appear to be visible on the form. What am I missing? I appreciate any help!
Capybara simulates user behaviour. So instead of ids and values try to use what the user see:
select 'Kallis Kallis', from: 'Member'
select 'Michele Michele', from: 'Trainer'
You could try the code below, or possibly assign the div and id and replace "div.field" with whatever id you choose
within "div.field" do
find("option[value='4']", text: 'Yanni Yanni').select_option
click_button 'your_submit_button'
end
I have a select2 dropdown in my rails code that I am trying to set and assert via capybara.
<select class="select optional select2-offscreen" id="bar_effort" name="bar[effort]" tabindex="-1"><option value=""></option>
<option value="0">Small</option>
<option value="1">Medium</option>
<option value="2">Large</option>
<option value="3">Extra Large</option>
</select>
To set the value I have the following (which works fine):
def effort=(effort)
#page.select(effort, :from => 'bar_effort')
end
Once the value has been set, I close the form and when I return back to the form, I want to assert the value I set is still selected. To do this I attempted the following:
def effort
#page.find(:css, '#bar_effort').value #version 1
end
def effort
#page.find(:css, '#bar_effort').text #version 2
end
Version 1 gave me "0" when I was expecting "Small"
Version 2 gave me "Small Medium Large Extra Large" when I was expecting "Small"
For a select list, the value method will return the selected option's text only if it does not have a value attribute.
To get the selected option's text, you will need to manually locate the option and get its text:
#page.find('#bar_effort').all('option').find(&:selected?).text
#=> "Small"
I'm super new to programming and am stuck... again,
I'm using rails 3 and currently have a venue model where each venue belongs to an area and a type (which are each thier own models) all of the venues in the database are displayed at the index page in partitions displaying the venue name, and its area and type.
How can I go about having a form with 2 dropdowns (areas and types) on the index page which filter the venue records shown depending on what is selected in the dropdowns. e.g. select pubs as type and Manchester as area and only the pubs in Manchester are shown or select pubs as type and all as area and all the pubs from all areas are shown.
I have tried installing sphinx and thinking_sphinx but can't seem to get them working on my windows 7. I got as far as a 1067 error on service startup and a "Failed to start searchd daemon." from thinking_sphinx on rake ts:start, which im presuming is from the sevice not running, so I'm hoping the answer to this won't involve sphinx.
I've had a look at scopes and am thinking this could possibly be the way to go? Although I haven't got the first idea as to how to include a dropdown to select the scope needed or indeed how to write a scope which will satisfy the kind of filter I want.
Thanks very much for any help, its much appreciated!
In your controller you should be able to do something as simple as:
#filtered_venues = Venue.where(:area => params[:venue][:area], :type => params[:venue][:type]).all
That should give you the filtered results that you want.
And then in your view you should be able to use form helpers to create the select elements:
select("venue", "area", ['New York', 'London', 'Amsterdam'], {}, { :prompt => 'Select Area' })
select("venue", "type", ['Pub', 'Outdoor', 'Hall'], {}, { :prompt => 'Select Type' })
Should output something like:
<select name="venue[area]">
<option value="">Select Area</option>
<option value="New York">New York</option>
<option value="London">London</option>
<option value="Amsterdam">Amsterdam</option>
</select>
<select name="venue[:type]">
<option value="">Select Type</option>
<option value="Pub">Pub</option>
<option value="Outdoor">Outdoor</option>
<option value="Hall">Hall</option>
</select>
There are a lot of other ways to get the options in there dynamically if you have collections ready for area or type. Check out the following for more information: http://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html
You can do this in several ways, depending on how exactly you want to filter. The best is to build the filter into a .find(:conditions => ...) call and let the database do the hard work. If you don't know beforehand on what parameters you are going to filter, it's easier but less efficient to do it in code. Assuming you have search parameters venue_area and venue_type, you could do something like this in the controller:
def index
#venues = Venue.all # Or whatever criteria you might have here
#venues = #venues.select { |v| v.area_id == params[:venue_area] } if !params[:venue_area].blank?
#venues = #venues.select { |v| v.type_id == params[:venue_type] } if !params[:venue_type].blank?
...
end
You then create dropdowns containing all type and area ID:s in your search form. There are several helpers you can use for this, such as select_tag. The #options would be better populated in the controller, of course, but this shows the relationship clearer:
<form method="get">
<% #options = Area.all.map { |a| [ a.name, a.id ] } %>
<%= select_tag("venue_area", options_for_select(#options)) %>
<input type="submit" value="Filter" />
</form>
This type of filtering could be done in either JavaScript, Ruby, or both.
If the HTML itself contains all the metadata you need to determine which items match which filters, then it could be done entirely in JavaScript by hiding and showing elements in response to a change in the form.
If the user is required to click a submit button for their chosen filters to take effect, then the form could simply submit and you could repopulate the form on the back end with Rails.
If the HTML doesn't have all the metadata and you don't want them to have to submit a form, you can use AJAX to send the chosen filters to the back end, have Rails construct the new form and send it back to the client, and then use JavaScript to update the front end.
You may get a few ideas from the Railscasts episode Search, Sort, Paginate with AJAX. It's not exactly your situation, but it might point you in the right direction for how these types of operations work in general.