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
Related
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
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'm having a set of problems that are doing my head in! Kind of a Rails newb so I'm having trouble figuring this out.
I've got a field for my 'Question' model that's called 'Answers_expected', which I want to have two options for, 'One' or 'Multiple', rather than just a normal text input.
My Questions_controller.rb (relevant lines):
before_action :set_answers_expected
private
# Use callbacks to share common setup or constraints between actions.
def set_question
#question = Question.find(params[:id])
end
# Never trust parameters from the scary internet, only allow the white list through.
def question_params
params.require(:question).permit(:title, :brief, :idea_id, :user_id, :answers_expected)
end
def set_answers_expected
#answers_expected = [
"One",
"Multiple"
]
end
Questions.rb (relevant line):
validates :answers_expected, presence: true
_form.html.erb:
<%= form_for(#question) do |f| %>
<% if #question.errors.any? %>
<div id="error_explanation">
<h2><%= pluralize(#question.errors.count, "error") %> prohibited this question from being saved:</h2>
<ul>
<% #question.errors.full_messages.each do |msg| %>
<li><%= msg %></li>
<% end %>
</ul>
</div>
<% end %>
<div class="field form-group">
<%= f.label :title, "Question" %><br>
<%= f.text_area :title, class:"form-control" %>
</div>
<div class="field form-group">
<%= f.label :brief, "Description" %><br>
<%= f.text_area :brief, class:"form-control" %>
</div>
<div class="field form-group">
<%= f.label :answers_expected %><br>
<% #answers_expected.each do |a| %>
<%= f.label :a, class: 'checkbox' do %>
<%= f.check_box :answers_expected, "a" %>
<%= a %>
<% end %>
<% end %>
</div>
My Questions show.html.erb:
div class="question">
<p>
<strong>Question:</strong>
<%= #question.title %>
</p>
<p>
<strong>Brief:</strong>
<%= #question.brief %>
</p>
<p>
<strong>Answers expected:</strong>
<%= #question.answers_expected %>
</p>
For some reason on my server, I get an error undefined methodmerge' for "a":Stringpointing to line<%= f.check_box :answers_expected, "a" %>in _form.html.erb, but it works when I changef.check_boxtof.radio_button`; why?
Even with radio_button, however, the Answers Expected display on the server continuously shows zero, despite what I click, which I also don't understand.
Also wrote specs hoping to point me in the right direction here:
question_spec.rb:
scenario 'with valid params' do
click_link 'Create a question'
fill_in 'Question', with: 'Valid question'
fill_in 'Description', with: 'This is valid description for the question.'
check 'One'
click_button 'Create Question'
page.should have_content 'One'
expect(page).to have_content('Question was successfully created.')
end
With my session_helper.rb having:
def submit_question(title = 'valid title', brief = 'valid brief')
click_link 'Create a question'
fill_in 'Question', with: title
fill_in 'Description', with: brief
check 'One'
click_button 'Create Question'
end
And my failed spec:
1) Visitor submits a question with valid params
Failure/Error: page.should have_content 'One'
expected to find text "One" in "Toggle navigation Labthi.ng Home Explore Recent Activity Example User Sign out × Question was successfully created. 0 Title: Valid Title Phase: 1 Brief: Valid brief for an idea Image: Active: true Components: App Categories: Other User: Example User Direct Define Reputation Activity Question was successfully created. Question: Valid question Brief: This is valid description for the question. Answers expected: 0 Idea: Valid brief for an idea User: Example User No comments. Add comment No answers yet. Why don't you add one ? Add answer Edit | Back"
# ./spec/features/question_spec.rb:16:in `block (2 levels) in <top (required)>'
Very confused! This is messing with my understanding of Rails a bit.
Thanks.
Edit:
Changed the syntax to <%= f.check_box :answers_expected, value: "a" %> , but the answers expected on the show page is still displaying as zero?
The correct way to set a value with the the check_box form helper is:
<%= f.check_box :answers, {}, "a" %>
:answers is the field name
{} is where you would put html attributes like class or id
"a" will be the value :)
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'
I currently am using Rails' "Devise" plugin to handle login/authentication. I am using a very basic form_for tag to handle the log-in form. Here is the code:
<div class="well-outer splash-signin-block">
<div class="well-inner">
<h2>Sign in</h2>
<div>
<%= form_for(resource, as: resource_name, url: user_session_path, html: {
class: "form-inline"
}) do |f| %>
<p><%= f.text_field :email, placeholder: "Email", autofocus: true %></p>
<p><%= f.password_field :password, placeholder: "Password" %></p>
<p>
<%= f.submit 'Sign in', class:"btn btn-primary btn-large" %>
<%= f.check_box :remember_me, class: "checkbox" %>
<%= f.label :remember_me %>
</p>
<% end %>
</div>
</div>
</div>
However, I would like to change that "Remember me" checkbox in to a button. The user experience would be that they could either click "Sign in" (the default action) or they could click "Remember me" to sign in persistently.
Behind the scenes, I imagine this would work by using a hidden field that sets the resource[remember_me] property to "1". However as a rails newbie I don't know how to go about coding this. I imagine it will need some javascript and that is fine, but googling has only turned up AJAX-y stuff and I don't think that's necessary. I won't shy away from it if it is necessary, though.
You would create a button with some id, then use javascript to bind to the click event of that button. When the button is clicked, you want to change the value of a hidden field. If you were using jQuery, it would be something like...
$('#id_of_button').click(function() {
$('#id_of_hidden_field').val("true");
});
Then you just check for that value in the controller like you normally would.
If you're not using jQuery it's not much more work, I just don't know it off the top of my head. Btw this code should be located in a .js file in your assets/javascript folder