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
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 have multiple email fields in a form. None of them have an id on them intentionally. How can I differentiate each element in the test if they don't have an id? I'll show code for clarity.
TEST
it "sends an invitation to multiple users" do
click_on "Invite"
click_link "Invite Another Team Member"
fill_in "", with: "user#example.com"
fill_in "", with: "user2#example.com"
expect { click_button "Invite" }
.to change(ActionMailer::Base.deliveries, :count).by(1)
.and change(Invitation, :count).by(2)
expect(current_path).to eq(account_users_path)
expect(page).to have_content("user#example.com")
expect(page).to have_content("user2#example.com")
end
This actually creates one object, the bottom field. How can I give the text fields individuality?
FORM
<%= form_tag account_invitations_url do %>
<label class="email-label">
<%= email_field_tag "emails[]", "", placeholder: "Email Address", data: { invitation_modal_email: "" }, id: "" %>
</label>
<%= link_to '✚ Invite Another Team Member', "#email", data: { invitation_modal_add: "" } %>
<div class="form-actions invitation">
<span class="button-text"><%= link_to 'Cancel', account_users_path %></span>
<%= submit_tag "Invite", class: "button button--invitation" %>
</div>
<% end %>
## Browser HTML
I think you can use Capybara's method all for finding all elements with same name:
emails = ["user#example.com", "user2#example.com"]
all('input[name="emails[]"]').each_with_index do |field, i|
field.set(emails[i])
end
Or:
all('input[name="emails[]"]')[0].set("user#example.com")
all('input[name="emails[]"]')[1].set("user2#example.com")
I have a nested form that has 4 checkboxes. Currently, everything is working in browser, but I can't get the capybara tests to uncheck the checkbox and save.
Using Rails 4.2.2 and latest versions of capaybara-webkit and rspec
settings.html.erb
<%= f.fields_for :preferences do |f| %>
<div class="email-notifications-holder">
<div class="email-holder">
<%= f.label :new_match, "Getting a new match each week" %>
<%= f.check_box :new_match, class: "checkbox new_match_email" %>
</div>
<div class="email-holder">
<%= f.label :match_reminder, "New matches Thursday reminder", class: "match_reminder_email" %>
<%= f.check_box :match_reminder, default: true, class: "checkbox" %>
</div>
<div class="email-holder">
<%= f.label :accepted_match, "A Glassbreakers accepted a match", class: "accepted_match_email" %>
<%= f.check_box :accepted_match, default: true, class: "checkbox" %>
</div>
<div class="email-holder">
<%= f.label :new_message, "Received a new message", class: "new_message_email" %>
<%= f.check_box :new_message, default: true, class: "checkbox" %>
</div>
</div>
<% end %>
edit_account_spec.rb
it "allows the user to opt out of new match email", :js do
user = create(:user)
preferences = create(:preference, user: user)
sign_in(user)
visit edit_user_path(user)
click_tab(t("edit_user.tabs.settings"))
find(:css, "#user_preferences_attributes_0_new_match").set(false)
within "#button-container" do
page.find('.save.main-save-button-edit').trigger('click')
end
visit edit_user_path(user)
click_tab(t("edit_user.tabs.settings"))
user.preferences.reload
new_match_email_checkbox = find(".new_match_email")
expect(new_match_email_checkbox.checked?).to be_falsey
end
I've tried clicking it, unchecking it, checking it, trigger clicking it, wrapping it around a within block, reloading the db, etc.
new_match_email_checkbox = find(".new_match_email")
within(".email-notifications-holder") do
page.uncheck('Getting a new match each week')
end
new_match_email_checkbox.set(false)
Right now when you save a user's profile, you must have onboard skills saved or else it will throw an error message when you're trying to click the save button.
part of the user controller
def update
if update_current_user?(user_params)
redirect_to user_path(current_user)
else
flash["notice"] =
"Please choose 3 industries, fields and years of experience."
redirect_to edit_user_path(current_user)
end
end
private
def update_current_user?(update_params)
skills_chosen?(update_params[:user_onboard_skills_attributes]) &&
current_user.update(update_params)
end
Using save_and_open_page, the error alert wasn't appearing so it was unclear what was happening. I was able to debug this by trailing the logs while running the tests using:
tail -f log/test.log
Just using this will uncheck the checkbox
within(".email-notifications-holder") do
page.uncheck('Getting a new match each week')
end
But you then have to grab the element to test it.
new_match_email_checkbox = find(".new_match_email")
expect(new_match_email_checkbox.checked?).to be_falsey
Note:
One thing I am unclear about. Are you trying to make this line work?:
find(:css, "#user_preferences_attributes_0_new_match").set(false)
or are you trying to uncheck the checkbox after you call user.preferences.reload ?
I have a text field like this :
<%= form_for(ownership, remote: true) do |f| %>
<div>
<%= f.text_field :confirm, value: nil, title: t('label.transaction.confirmation.code') %>
<%= f.hidden_field :start_date, value: Time.now %>
</div>
<%= f.submit t('button.ownership.take.confirmation'), class: "btn btn-small"%>
<% end %>
And I want to fill in the text field with rspec :
fill_in t('label.transaction.confirmation.code'), with: "something"
But it doesn't work because the rspec don't recognize the title tag in order to fill in the text field :
Failure/Error: fill_in t('label.transaction.confirmation.code'), with: confirmation_code
Capybara::ElementNotFound:
Unable to find field "Code de confirmation"
Do you know a way to fill in the text field with rspec without adding a label ?
the fill_in method's first argument must be a css selection. for example: #id, li, .class.
So you can change t('label.transaction.confirmation.code')
to the text field id or [title='#{t('label.transaction.confirmation.code')}']
e.g.
<input id="conf_code">
fill_in 'conf_code', with: 'something'