I have the following form
<%= form_for(#route, :html => {:class => "form-horizontal", :role => 'form'}) do |f| %>
<%= render 'shared/error_messages', object: f.object %>
<div class="form-group">
<input type="text" name="route_origin_input" id="route_origin_input" placeholder="From" onFocus="geolocate(); autocompleteLocation(this,route_origin)" class="form-control" />
<%= f.hidden_field :origin, class: "form-control" %>
</div>
<div class="form-group">
<input type="text" name="route_destination_input" id="route_destination_input" placeholder="Destination" onFocus="geolocate(); autocompleteLocation(this,route_destination)" class="form-control" />
<%= f.hidden_field :destination, class: "form-control" %>
</div>
<div class="form-group">
<% options = options_from_collection_for_select(#vehicleList, 'vehicle', 'vehicle') %>
<%= f.select :vehicle, options, class: "form-control" %>
</div>
<div class="form-group">
<%= f.date_field :departure_date, class: "form-control" %>
</div>
<%= f.submit "Post", class: "btn btn-large btn-primary", id: "route_post" %>
<% end %>
and the following test
require 'spec_helper'
describe "Route pages" do
subject { page }
let(:user) { FactoryGirl.create(:user) }
before { sign_in user }
describe "route creation" do
before {
visit terminal_path
}
describe "with invalid information" do
it "should not create a route" do
expect { click_button "route_post" }.not_to change(Route, :count)
end
describe "error messages" do
before { click_button "route_post" }
it { should have_danger_message('Not Submitted') }
end
end
describe "with valid information", :js => true do
before do
fill_in 'route_origin_input', with: "Kimmage, Dublin, Ireland"
fill_in 'route_destination_input', with: "Kimmage, Dublin, Ireland"
fill_in 'route_departure_date', with: Time.now
select 'Car', :from => "route_vehicle"
end
it "should create a route" do
expect { click_button "route_post" }.to change(Route, :count).by(1)
end
end
end
end
For some reason the two text fields that I have added with html cannot be found by capybara
The error I receive is
Failure/Error: fill_in 'route_origin_input', with: "Kimmage, Dublin,
Ireland"
Capybara::ElementNotFound:
Unable to find field "route_origin_input"
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/node/finders.rb:41:in
block in find'
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/node/base.rb:84:in
synchronize'
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/node/finders.rb:30:in
find'
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/node/actions.rb:56:in
fill_in'
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/session.rb:676:in
block (2 levels) in <class:Session>'
# /Users/jeff/.rvm/gems/ruby-2.0.0-p594/gems/capybara-2.4.4/lib/capybara/dsl.rb:51:in
block (2 levels) in '
# ./spec/requests/route_pages_spec.rb:30:in `block (4 levels) in '
I've used fill_in in other tests and the only difference I can see is that I have used standard html code in the form. These fields are used to process the info the user enters and then add the result to a hidden field that is part of my model, basically getting the result from Google maps api.
EDIT:
Here is the HTML
<div class="form-group">
<input type="text" name="route_origin_input" id="route_origin_input" placeholder="From" onFocus="geolocate(); autocompleteLocation(this,route_origin)" class="form-control" />
<input class="form-control" id="route_origin" name="route[origin]" type="hidden" />
</div>
The HTML and spec look OK. Here's some things I would try:
Are you sure it is failing on route_origin_input and not another field?
What if you run it without :js => true? Perhaps there is some Javascript that is preventing the form from rendering or redirecting.
Use save_and_open_page and/or get a screenshot to see what is going on.
Which driver are you using? Different drivers behave differently. Try a different driver.
Try selenium-webdriver. It runs a browser and you can see what is going on. Use sleep 10 before the fill_in. The spec will pause and you can inspect the form or manually fill it in.
Usually I use within '.form' do. That may make a difference. See Capybara docs for how to use within.
Related
Having this form:
<h3 class="contact-header"><span>Ready to try it</span> GET IN TOUCH</h3>
<%= form_for #contact, url: pages_path, remote: true do |f| %>
<div class= "flex-row">
<div class="form-input-spacing">
<%= f.label :name %>
<%= f.text_field :name, required: true, class: "contact-form-text-area" %>
</div>
<div class="form-input-spacing">
<%= f.label :email %>
<%= f.text_field :email, required: true, class: "contact-form-text-area" %>
</div>
</div>
<div class="area-input">
<%= f.label :message %>
<%= f.text_area :message, rows: 8, cols: 59, required: true, class: "contact-form-text-area",
placeholder: "Send us a message"%>
</div>
<div class="submit-form">
<%= f.submit 'Send Message', class: 'btn btn-primary' %>
</div>
<% end %>
I am trying to test how it would be filled and then sent with Capybara:
scenario "visitor/user sends incomplete contact form" do
visit root_path #form is in root
within(".new_contact") do
# fill_in "#contact_name", with: "Test User"
# fill_in "contact_name", with: "Test User"
find("#contact_name").set("Test User")
end
save_and_open_page
end
I have tried js: true in the scenario, and both fill_in and find but when I do save_and_open_page nothing is filled.
The reason why I used .new_contact is because in the Inspector, thats the class that the form takes, the #contact_nameis the id that the input takes andcontact_nameis the labelfor`.
If I use click_button "Send Message" the button is clicked and a message appears so why is it getting the button but not the input? Thanks!
save_and_open_page saves the HTML with the element attributes, not the element's properties. It is really only useful for when you want to see modified page structure (the HTML structure has been changed). When you change the content of a field it changes the value property of that element but doesn't actually update the page HTML (value attribute), so when you save the HTML it won't have the value set. If you want to see the page as it was use save_and_open_screenshot, or just pause your test and look at the browser.
Also fill_in takes a locator, not CSS, so it would be
fill_in "contact_name", with: "Test User"
from https://rubydoc.info/gems/capybara/Capybara/Node/Actions#fill_in-instance_method - The field can be found via its name, id, test_id attribute, placeholder, or label text. - not CSS
The following Capybara/RSpec test is failing on my Rails app and I can't figure out why. I'm using the simple_form_for Gem to create the form and submit button. The update method seems to be working properly, as when I change
expect(#coin.currency_name).to eq('Updated Name')
to
expect(page).to have_text('Updated Name')
the test passes and the updated name is shown on the new page. However #coin.currency_name doesn't seem to be updated when I use the previously described expect method. When I manually update the Coin model (on the page, not using RSpec) it works fine and the currency_name is updated.
What am I doing wrong on this test?
spec/features/coins/coin_spec
require 'rails_helper'
RSpec.feature 'Coins' do
before(:each) do
#user = FactoryBot.create(:user)
end
context 'update coin' do
scenario 'should succesfully edit name if user=admin' do
#user.update(admin: true)
login_as(#user, :scope => :user)
#coin = Coin.create!(currency_name: "TestName", user_id: #user.id)
visit edit_coin_path(#coin)
fill_in 'Currency Name', with: 'Updated Name'
click_button 'Submit'
expect(#coin.currency_name).to eq('Updated Name')
end
end
end
app/views/coins/edit.html.erb
<div class='form-container'>
<%= simple_form_for #coin, url: coin_path do |f| %>
<h2>Edit Coin</h2>
<div class="form-container__section">
<%= f.input :currency_name, label: "Currency Name", class: 'form-control' %>
<%= f.input :link_name, placeholder: "Link Name", label: false, class: 'form-control' %>
...
<%= f.button :submit, value: "Submit", class: "btn primary-small", style: "margin-top: 20px;" %>
<% end %>
</div>
and the HTML
<div class="form-container">
...
<h2>Edit Coin</h2>
<div class="form-container__section">
<div class="form-group string required coin_currency_name"><label class="control-label string required" for="coin_currency_name"><abbr title="required">*</abbr> Currency Name</label><input class="form-control string required" type="text" value="OldName" name="coin[currency_name]" id="coin_currency_name"></div>
...
<input type="submit" name="commit" value="Submit" class="btn btn-default primary-small" style="margin-top: 20px;" data-disable-with="Update Coin">
</form>
After change of model, use reload method:
click_button 'Submit'
#coin.reload
expect(#coin.currency_name).to eq('Updated Name')
I am learning to write feature specs using rspec and capybara. I am trying to write spec for an application, which handles transactions. My transaction controller is as follows:
def new
#transaction = Transaction.new
end
def create
transaction = Transaction.new(transaction_params)
transaction.account = current_account
if transaction.save && transaction.account.save
flash[:success] = 'Transaction successfull'
else
flash[:danger] = 'Insufficient balance'
end
redirect_to root_path
end
It's view is as follows transactions/new:
<div class = 'row'>
<div class = 'col-xs-12'>
<%= form_for(#transaction, id: 'transaction_form', :html => {class: 'form-horizontal', role: 'form'}) do |t| %>
<div class = 'form-group'>
<div class = 'control-label col-sm-2'>
<%= t.label :amount %>
</div>
<div class = 'col-sm-8'>
<%= t.text_field :amount, class: 'form-control', placeholder: 'Enter amount', autofocus: true %>
</div>
</div>
<div class = 'form-group'>
<div class = 'control-label col-sm-2'>
<%= t.label :transaction_type %>
</div>
<div class = 'col-sm-8'>
<%= t.select :transaction_type, Transaction.transaction_types.keys %>
</div>
</div>
<div class = 'form-group'>
<div class = 'col-sm-offset-2 col-sm-10'>
<%= t.submit 'Submit', class: 'btn btn-primary btn' %>
</div>
</div>
<% end %>
I added id: transaction_form to form to avoid ambiguous error.
The spec code is as follows:
RSpec.feature 'Transactions', type: :feature do
context 'create new transaction' do
scenario 'should be successfull' do
visit new_transaction_path
within('#transaction_form') do
fill_in 'Amount', with: '60'
end
click_button 'Submit'
expect(page).to have_content('Transaction successfull')
end
end
end
On running this spec, however,I get error as:
1) Transactions create new transaction should be successfull
Failure/Error:
within('#transaction_form') do
fill_in 'Amount', with: '60'
end
Capybara::ElementNotFound:
Unable to find css "#transaction_form"
What is it I am missing? If I use form directly, it is throwing the ambiguous error as it is getting the same element from different file. What is wrong with this code?
Also, the /transactions/new page will be displayed only if the user is logged in. So will this also affect the transaction spec? If yes, then what should be done?
Please help. Thanks in advance.
If the page you want to interact with is only visible when the user is logged in, then you need to log the user in. That also means you will need to create the user you're going to log in before the test starts. Usually that would be done using either Rails fixtures, or a factory (like the factory_bot gem). Once you have create the user then you'll need to log them in, which can be as simple as visiting the login page and entering the users username and password. If you're using a gem for authentication it may provide a test mode which allows for bypassing actually visiting the login page in order to speed up tests (ie. devise provides this - https://github.com/plataformatec/devise/wiki/How-To:-Test-with-Capybara)
I tried setting the id in various parts of the form, as well as wrapping the form in a div with id set to search. The result is always the same.
spec/features/02_post_spec.rb
scenario 'search for post title' do
fill_post_form(post3)
fill_in "search", with: post3.title
click_button("Search")
expect(page).to_not have_content(post1.title)
expect(page).to_not have_content(post2.title)
expect(page).to have_content(post3.title)
end
spec/spec_helper.rb
def fill_post_form(post)
visit new_post_path
fill_in 'Title', with: post.title
fill_in 'Body', with: post.body
click_button 'Create Post'
end
This will redirect_to post_path(post)
views/posts/index.html.erb
<%= form_tag(posts_path, method: :get, class: "block") do %>
<div class="form-group">
<div class="input-group">
<%= text_field_tag :search, params[:search], class: "form-control", id: "search" %>
<span class="input-group-btn">
<%= submit_tag "Search", name: nil, class: "btn btn-default" %>
</span>
</div>
</div>
<% end %>
Capybara output
Failure/Error: fill_in "search", with: post3.title
Capybara::ElementNotFound:
Unable to find field "search"
The command fill_in "search", with: post3.title you're using should work, assuming you are on the page rendering the shown partial, and the output of that partial is actually visible on the page (not hidden via CSS). Your scenario doesn't show visiting an actual page, and you don't show what fill_post_form is doing so it's tough to know exactly what is going wrong. First step would be to do something like
fill_post_form(post3) # already in your tests
sleep 2 # wait a few seconds to make sure above method has completed whatever actions it does
puts page.html # output the current page and take a look to see if your 'search' element is actually on the page
Trying to test some functionality in a simple page and I am getting this error when using page.check:
Failures:
1) searching for stores serving a taco and a sauce: Adobada tacos with Chile de Arbol sauce
Failure/Error: page.check 'Adobada'
Capybara::ElementNotFound:
Unable to find checkbox "Adobada"
# ./spec/views/store_search_spec.rb:8:in `block (2 levels) in <top (required)>'
Here is my HTML:
<%= simple_form_for :stores, url: stores_path, method: :get do |f| %>
<%= f.label :tacos, 'Select Tacos to Find: ', class: 'label' %>
<div class='taco-select checkboxes'>
<%= f.collection_check_boxes :tacos, Taco.order(:name), :id, :name,
:include_hidden => false, :item_wrapper_class => 'checkbox_container' %>
</div>
<%= f.label :salsa, 'Select Sauces to Find: ', class: 'label' %>
<div class='salsa-select checkboxes'>
<%= f.collection_check_boxes :salsas, Salsa.order(:name), :id, :name,
:include_hidden => false, :item_wrapper_class => 'checkbox_container' %>
</div>
<%= f.submit 'Search!' %>
<% end %>
And this is my test:
require 'rails_helper'
feature 'searching for stores', %(serving a taco and a sauce:) do
scenario 'Adobada tacos with Chile de Arbol sauce' do
visit root_path
page.check 'Adobada'
page.check 'Chile de Arbol'
click_button 'Search!'
expect(page).to have_content "Store"
expect(page).to have_content 'City'
end
end
I would like to test that when some checkboxes are set to true a certain content is rendered in the page.
Don't know how to fix this.
Try with these, they should work for you:
find(:css, "#YOUR_CHECKBOX_ID").set(true)
or
page.check('YOUR_CHECKBOX_ID')
or simply
find('THE CSS SELECTOR OF YOUR CHECKBOX').click
find(:xpath, 'THE XPATH OF YOUR CHECKBOX').click
You don't have to use an ID to check a checkbox. You can just use the label on the checkbox. Say you have a checkbox like this
<label for="...">
<input type="checkbox" name="...">Something</label>
You 'check' it in capybara like so
it "" do
page.check 'Something'
end
Official docs on this can be found here