How to test disabled field in ruby on rails and assert_select? - ruby-on-rails

I want to test presence of disabled field generated in rails(5) view helper
form_for(#metric) do |f|
f.text_field :type, disabled: true
end
it creates HTML
<input id="metric_type" type="text" name="metric[type]" value="Gamfora::Metric::Point" disabled="disabled">
It should be probably just
<input id="metric_type" type="text" name="metric[type]" value="Gamfora::Metric::Point" disabled>
but it is OK and do the job.
In Firebug I verify that CSS selector is input#metric_type:disabled.
But when I use it in controller(+view) tests
assert_select "input#metric_type:disabled"
I get error
RuntimeError: xmlXPathCompOpEval: function disabled not found
Is there any way, how to test that input selected by ID is disabled?

One solution is
assert_select ".field input#metric_type" do |input|
assert input.attr("disabled").present?
end

Related

Capybara doesn't want to select an input node

My HTML/ERB looks like this
<fieldset class="row notifications">
<legend>
<hr class="dash blue inline">
<%= t :my_notifications %>
</legend>
<label>
<%= f.check_box(:subscribed_to_news) %>
<span></span>
<span class="checkbox-text"><%= t :accepts_to_receive_news %></span>
<br>
</label>
</fieldset>
When I debug my Cucumber test with Capybara, I do find the notification checkbox f.check_box(:subscribed_to_news) in this mess
page.find('.notifications label')['innerHTML']
# => "\n\t\t<input name=\"user[subscribed_to_news]\" type=\"hidden\" value=\"0\"><input type=\"checkbox\" value=\"1\" checked=\"checked\" name=\"user[subscribed_to_news]\" id=\"user_subscribed_to_news\">\n\t\t<span></span>\n\t\t<span class=\"checkbox-text\">blahblahblah</span>\n\t\t<br>\n\t"
But for some reason I cannot find the nested inputs nor find them by ID
page.find('.notifications label input')
# => Capybara::ElementNotFound Exception: Unable to find css ".notifications label input"
page.find('.notifications label #user_subscribed_to_news') # => Capybara::ElementNotFound Exception: Unable to find css ".notifications label #user_subscribed_to_news"
Selecting the label does work though
page.find('.notifications label')
# => #<Capybara::Node::Element tag="label" path="//HTML[1]/BODY[1]/DIV[1]/MAIN[1]/SECTION[1]/FORM[1]/FIELDSET[3]/LABEL[1]">
What am I doing wrong ? I just want to check the damn checkbox :'(
Most likely reason is the checkbox is actually hidden by CSS and then replaced with images to enable identical styling of checkboxes across different browsers. If you're using the latest Capybara you can have it click it the label when the checkbox is hidden by calling
page.check('user_subscribed_to_news', allow_label_click: true) # you can also set Capybara.automatic_label_click = true to default to this behavior
or if using an older capybara you would need to click the label yourself
page.find(:label, "blahblahblah").click #match on labels text
or
page.find(:label, for: 'user_subscribed_to_news').click #match on labels for attribute if set
It would seem that the checkbox is unreachable via normal css /xpath...
I got away using some javascript
page.execute_script(%Q{document.querySelector('#{area} input##{selector}').click()})

RSpec/Capybara: Strange behaviour doesn't find <input type="hidden">, but it definitely is there

I have the following spec:
within dom_id_selector(#boilerplate_copy) do
within '.copied_attributes_differing_from_original' do
within 'form.title[action="http://www.textdiff.com/"]' do
expect(page).to have_css 'button', text: 'Title'
expect(page).to have_css 'input[name="string1"]'
expect(page).to have_css 'input[name="string2"]'
end
end
end
Here is the HTML in question:
<div class="copied_attributes_differing_from_original">
<form action="http://www.textdiff.com/" class="title" method="post" target="_blank">
<input name="string1" type="hidden" value="Boilerplate Original test title">
<input name="string2" type="hidden" value="Boilerplate Copy test title">
<button type="submit">Title</button>
</form>
<form action="http://www.textdiff.com/" class="success_criterion_id" method="post" target="_blank">
<input name="string1" type="hidden">
<input name="string2" type="hidden" value="1">
<button type="submit">Success criterion</button>
</form>
// More of them...
<form action="http://www.textdiff.com/"...
</div>
While the first have_css passes (the button is found), the second have_css fails:
Failure/Error: expect(page).to have_css 'input[name="string1"]'
expected to find css "input[name=\"string1\"]" but there were no matches. Also found "", which matched the selector but not all filters.
But in my opinion this element definitely is there! I also don't understand the output Also found "", which matched the selector but not all filters., what does it mean?
Thank you.
By default Capybara doesn't find non-visible elements (which hidden inputs are) because a user can't see/interact with them. If you really need to check the presence of a non-visible element you can do
expect(page).to have_css('input[name="string1"]', visible: false)
That being said, since feature tests should be testing that the page functionality works rather than the details of exactly how it works you may not want to check for the presence of hidden inputs but rather just make sure the functionality they implement works.

undefined method `map' for "1,2":String

I need to pass an array in a params, possible? Values can be, for example, ["1","2","3","4","5"] and these are strings but needs to eb converted to integers later.
I use a react_component in between a rails form_for. The html is like this:
<input type="hidden" name="people_id" id="people_id" value={this.state.people} />
The people array looks like this:
How can I pass the array in the value of the hidden field? The server error I got was
Im trying to do something like this in a model:
ids = params[:people_id]
ids.map do |b|
Foo.create!(people_id: b.to_i)
end
If I ids.split(",").map I get symbol to int error.
Edit:
––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Still not sure what the issue is as nothing works. Here is a minimal reproduction of my code:
This answer is my react component and that's how I add to the array. Still in the component, I have the hidden field:
<input type="hidden" name="[people_id][]" id="people_id" value={this.state.people} />
_form.html.erb:
<%= form_for resource, as: resource_name, url: registration_path(resource_name), :html => { :data => {:abide => ''}, :multipart => true } do |f| %>
<!-- react component goes here -->
<%= f.submit "Go", class: "large button" %>
<% end %>
The story is, guest can select few people during registration in one go. Those people will be notified when registration is complete. Think of it as "I am inviting these people to bid on my tender". Those numbers, in the array, are user_ids.
users/registrations_controller.rb
class Users::RegistrationsController < Devise::RegistrationsController
# POST /resource
def create
super do |resource|
ids = params[:people_id].pop # logs now as "people_id"=>["1,2"]
resource.save!(ids.split(",").map |b| Foo.create!(people_id: b.to_i) end)
end
end
end
New error on line resource.save:
no implicit conversion of Symbol into Integer
Edit #2
If I only have, in the create method:
ids.split(",").map do |b|
resource.save!(Foo.create!(people_id: b.to_i))
end
It works! Foo is created two times each with the correct people_id.
Because I am creating more objects: Bar, I do not know how to do that in:
resource.save!(<the loop for Foo> && Bar.create!())
The flow must be:
Device creates the User
Foo is created with the loop
Bar is created
etc
It has to be done that way as an User object is created on the fly.
In Rails you use parameter keys with brackets on the end to pass arrays.
However you should not concatenate the values as a comma seperated list but rather send each value as a seperate param:
GET /foo?people_ids[]=1&people_ids[]=2&people_ids[]=3
That way Rails will unpack the parameters into an array:
Parameters: {"people_ids"=>["1", "2", "3"]}
The same principle applies to POST except that the params are sent as formdata.
If you want a good example of how this works then look at the rails collection_check_boxes helper and the inputs it generates.
<input id="post_author_ids_1" name="post[author_ids][]" type="checkbox" value="1" checked="checked" />
<label for="post_author_ids_1">D. Heinemeier Hansson</label>
<input id="post_author_ids_2" name="post[author_ids][]" type="checkbox" value="2" />
<label for="post_author_ids_2">D. Thomas</label>
<input id="post_author_ids_3" name="post[author_ids][]" type="checkbox" value="3" />
<label for="post_author_ids_3">M. Clark</label>
<input name="post[author_ids][]" type="hidden" value="" />
Updated:
If you intend to implement you own array parameters by splitting a string you should not end the input with brackets:
<input type="hidden" name="[people_id][]" value="1,2,3">
{"people_id"=>["1,2,3"]}
Notice how people_id is treated as an array and the input value is the first element.
While you could do params[:people_id].first.split(",") it makes more sense to use the correct key from the get go:
<input type="hidden" name="people_id" value="1,2,3">
Also you don't really want to wrap the "root" key in brackets. Thats used in rails to nest a param key in a hash eg. user[name].

Rails and simple form: novalidate attribute doesn't work

my login page( build with simple form) add by default html attributes for browser validation on email input that chrome doesn't recognize and show "Please match the requested format."
Maybe is Chrome bug(on firefox works), so have tried to disable browser validation with simple form config
SimpleForm.html5 and SimpleForm.browser_validations(false by default), restarted rails but remain the same input:
<input autofocus="autofocus" class="string email optional form-control
input-xlarge" id="customer_email" maxlength="255"
name="customer[email]" pattern="\A[^#\s]+#([^#\s]+\.)+[^#\s]+\z"
size="255" type="email">
have tried also to add on form html: {novalidate: true}, same output
finally have tried to add on input_filed :novalidate => true, the html output change to:
<input autofocus="autofocus" class="string email optional form-control
input-xlarge" id="customer_email" maxlength="255"
name="customer[email]" pattern="\A[^#\s]+#([^#\s]+\.)+[^#\s]+\z"
size="255" type="email" novalidate="novalidate">
but browser validation and chrome error is present.
Any idea to resolve?
PS: Use Bootstrap and the login form is from Devise resource.
You can remove the pattern attribute from the input element that is causing a problem. You just need to set pattern: false on the input field.
So your input field might look something like this:
<%= f.input_field :email, type: 'email', required: true, autofocus: true, class: 'form-control', pattern: false %>
(nil doesn't work; it has to be false.)
This worked for me in Rails 4.

Integration Testing a Backbone.js application with Cucumber and Capybara

I am trying to test a Backbone application running on top of a Rails 3.2.8 one using Cucumber, capybara, capybara-webkit, selenium-webdriver, rspec and jasmine. I am using eco as template engine for the backbone template.
My problem is when I run the scenario using the #javascript tag, wether with capybara-webkit or selenium, the page displayed doesn't contain all the model attribute datas.
Here is the scenario :
#javascript
Scenario : first scenario
Given There is Model with "name" as name and "What is it about ?" as associated questions
When I want to fill the questionnaire
Then I should be on the SPA form
And I should see "name"
And I should see "What is it about?"
The scenario fails on the "And I should see 'what is it about?'" step, the page doesn't show the question, but it shows the "name"
I put several debug statement in my backbone code with console.log and I can see that the model is correct with all its attributes. Moreover it is working in live without issue
The template looks like this : 'show.jst.eco'
<p class="text-info"><%= #model.name %></p>
<form id="quidget-form" class="form-vertical">
<% for question in #model.questions: %>
<div class="issue_field">
<label class="string optional control-label"><%= question.question.question_text %></label>
<div class="control-group text">
<textarea class="text answer" name="question-<%= question.question.id %>" id="question_<%= question.question.id %>" data-question="<%= question.question.question_text %>" rows="3">
</textarea>
</div>
</div>
<% end %>
<div class="controls">
<input type="submit" value="Additional Informations" id="quidget-step-one" class="btn btn-success">
The textarea is displayed but not the label above with the question text
Any idea ? I would like to see this pass so i can test more complicated logic with more steps.
Thanks
I've been doing some research into this sort of things as well. Most of it has been focused around Ember.js instead of Backbone but Pamela Fox just wrote a blog post about testing the Backbone.js frontend for Coursera, it could be helpful http://blog.pamelafox.org/2013/06/testing-backbone-frontends.html Also, have you tried testing with capybara in same manner you would a generic rails application with :js => true? Might be worth trying.

Resources