Uncheck check_box only not working with rspec / capybara tests - ruby-on-rails

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 ?

Related

Form is not being filled - Capybara

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

How to pass parameters from html.erb to a different html.erb

I'm playing with the messenger gem in rails 4.
I have a graph of nodes and I want to be able to bring up a message box (initially in a different page but will make it a partial later) when a node is pressed so that the current user can message that node.
The id for the clicked node is kept in a div called NameID
At the moment all I've got working is a button that opens the new message page and then you can choose a user from a drop down list. I guess I want that drop down list- the recipient- to be prepopulated from the currently clicked node on the index page.
Here is what I have so far:
index.html.erb
<p><a class="btn btn-lg btn-primary" id="BtnMessageNode" href="/messages/new">Start conversation</a></p>
<div id=NameID><<THIS IS POPULATED BY JAVASCRIPT>></div>
messages_controller.rb
class MessagesController < ApplicationController
before_action :authenticate_user!
def new
#chosen_recipient = User.find_by(id: params[:to].to_i) if params[:to]
end
def create
recipients = User.where(id: params['recipients'])
conversation = current_user.send_message(recipients, params[:message][:body], params[:message][:subject]).conversation
flash[:success] = "Message has been sent!"
redirect_to conversation_path(conversation)
end
end
helpers/messages_helper.rb
module MessagesHelper
def recipients_options(chosen_recipient = nil)
s = ''
User.all.each do |user|
s << "<option value='#{user.id}' data-img-src='#{gravatar_image_url(user.email, size: 50)}' #{'selected' if user == chosen_recipient}>#{user.name}</option>"
end
s.html_safe
end
end
messages/new.html.erb
<% page_header "Start Conversation" %>
<%= form_tag messages_path, method: :post do %>
<div class="form-group">
<%= label_tag 'message[subject]', 'Subject' %>
<%= text_field_tag 'message[subject]', nil, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'message[body]', 'Message' %>
<%= text_area_tag 'message[body]', nil, cols: 3, class: 'form-control', required: true %>
</div>
<div class="form-group">
<%= label_tag 'recipients', 'Choose recipients' %>
<%= select_tag 'recipients', recipients_options(#chosen_recipient), multiple: true, class: 'form-control chosen-it' %>
</div>
<%= submit_tag 'Send', class: 'btn btn-primary' %>
<% end %>
There are basically two ways to pass parameters to GET routes:
A. Named segments
/users/:user_id/message/new
This nested route would be great if you are sending a message to a single user.
B. Query parameters
Rails supports query parameters as well:
/message/new?to=2
Rails automatically adds query parameters to the params hash. So in this case you would do params[:to].
You can use the Rails route helpers so that you don't have to deal with encoding urls yourself:
new_message_path(to: #user.id)
Use query params for optional parameters like filters and sorting or in this case a preset. Don't use them like users?id=5.

Checkboxes in Rails - Value chosen not displaying in 'Show', undefined method `merge' for "a":String

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 :)

Why is Rails resetting user selected times when there are unrelated validation errors?

I have this code that allows user to click Add Date to show another line to specify a date time. Screenshot shows user entered two dates:
<fieldset class="date_fieldset">
<%= f.label :user_event_date, "Date", class: "info_inline_control info_label" %>
<%= f.text_field :user_event_date, class: 'datepicker' %>
<div class="user_event_inline_container margin_left_ten padding_right_gone">
<%= f.label :start_time, "Start", class: 'info_inline_control info_label five_margin_right' %>
<%= f.time_select :start_time, {:ampm => true}, class: (field_class(#user_event, :start_time) + 'info_inline_control') %>
</div>
<div class="user_event_inline_container margin_left_ten padding_right_gone">
<%= f.label :end_time, "End", class: 'info_inline_control info_label five_margin_right' %>
<%= f.time_select :end_time, {:ampm => true}, class: (field_class(#user_event, :end_time) + 'info_inline_control') %>
</div>
<%= f.hidden_field :_destroy %>
<%= link_to "delete", '#', class: 'remove_fields margin_left_ten' %>
</fieldset>
<script type="text/javascript">
$(function() {
$('.datepicker').datepicker({
dateFormat: "dd-mm-yy"
});
});
</script>
But if some other, non-related field elsewhere on the form has a validation error, and the errors are reported at the top of the form, then the two lines for the user specified dates are gone, and clicking the Add Date button makes the user start over to specify the dates again. How can I prevent page refresh to show validation errors wiping out user selected dates?
Here are the new, edit, and create controller action methods:
def new
if !signed_in?
redirect_to signin_path
else
#user_event = UserEvent.new
#user_event.event_dates.build
end
end
def edit
end
def create
#user_event = current_user.user_events.build(params[:user_event])
if #user_event.save
flash[:success] = "Event was successfully posted!"
redirect_to root_url
else
render action: :new
end
end
As always, thanks very much for your answers in advance!
This solves it:
<div>
<%= f.fields_for :event_dates do |builder| %>
<%= render 'event_date_fields', f: builder %>
<% end %>
</div>
Before, I had an empty div, and Javascript would add an event date each time the Add Date link was clicked. But when the page is re-rendered, either due to validation errors, or else because used is editing the event, the div needs f.fields_for to render what already exists.
Man I'm loving Rails, and the community, because I get pieces of the puzzle, and figure out the rest.

Capybara::Element Not Found

I'm working along with the Rspec book as it develops a 'showtime' rails application, which provides information about films. As far as I can tell, I've copied the code exactly (the book's not that great at letting readers know every step to take), but I'm getting this error.
Unable to find select box "Release Year" (Capybara::ElementNotFound)
./features/step_definitions/movie_steps.rb:6:in `/^I create a movie Caddyshack in the Comedy genre$/'
My movie_steps.rb file has this code, which provides users a select box to select the release year, which is the element Capybara can't find.
#---
When /^I create a movie Caddyshack in the Comedy genre$/ do
visit movies_path
click_link "Add Movie"
fill_in "Title", :with => "Caddyshack"
select "1980", :from => "Release Year"
check "Comedy"
click_button "Save"
end
Then /^Caddyshack should be in the Comedy genre$/ do
visit genres_path
click_link "Comedy"
response.should contain("1 movie")
response.should contain("Caddyshack")
end
In the movies view, I have this code, which is, as far as I can tell, all i need to implement the select box.
<%= form_for #movie do |f| %>
<%= f.label :title %>
<%= f.text_field :title %>
<%= f.label :release_year %>
<%= f.select :release_year, (1900..2009).to_a.map(&:to_s) %>
<% #genres.each do |genre| %>
<label>
<%=h genre.name %>
<%= check_box_tag "genres[]", genre.id %>
</label>
<% end %>
<%= f.submit "Save" %>
<% end %>
I'd be grateful for any suggestions you could provide.
Try select "1980", :from => "Release year" instead. If you want it to display as "Release Year", then change your label to show as follows:
f.label :release_year, "Release Year"
Rails automatically formats the label for you using the humanize method, but you can change it to anything you like.

Resources