Cucumber Test Cannot find field when its there - ruby-on-rails

While I was writing cucumber test code,
I get:
Unable to find field "username" (Capybara::ElementNotFound)
But I have the following on the page itself.
<%= f.text_field :username, :placeholder => "Username" %>
I've checked that it lands on the correct page using
save_and_open_page
fill_in "username", :with => "TESTUSER"
isn't the tag :username? What am I supposed to write instead?

Capybara will match fields based on their id, name or label text. See here for more details.
Since you are using the default text_field helper, id and name will default to include the model (e.g. user_username for the id, or user[username] for the name). You can change these defaults by simply using id: <id> or name: <name> on your text_field call but you might run into other problems later - so probably best to stay with the defaults.
Change your capybara test to fill_in "user_username" or fill_in "user[username]" to make it match. Alternatively, if you have a label_for on the field, you can match on the text of the label which can make your tests more readable.

Related

How to test ActionText rich_text_field in a System test?

I'm trying to fill in an ActionText rich_text field form input, but can't figure out how to select it. I'm using Rails 6 and ActionText.
With
class Activity
has_rich_text :description
end
and _form.rb
= f.label :description
= f.rich_text_area :description, class: 'form-control'
Test using:
fill_in "Description", with: "Some description.."
I'll get the error
Capybara::ElementNotFound: Unable to find field "Description" that is not disabled
I suspect the problem is with how the Trix editor dynamically fills in this field as you type. I'm just not sure how to do the input, replicating how the user would be entering text.
You can do so by find the trix editor and entering your details manually:
find(".trix-content").set("New value")
Since Rails 6.1, you can use the fill_in_rich_text_area system test helper. Added in b2b6341374.

How can I pass an translation interpolation variable to a failed form validation message?

So, I'm basically trying to show Devise's confirm_within time in the error message that comes when clicking the confirmation email link after the required time.
I am using YAML translation files.
The interpolation variable is called devise_confirm_within
My YAML is like this:
en:
activerecord:
errors:
models:
user:
attributes:
email:
confirmation_period_expired: "some text %{devise_confirm_within}"
Normally, I would find the appropriate view, and then pass the interpolation variable as a parameter to the translate or t method. Like this:
<p><%= t("devise.mailer.confirmation_instructions.please_click_the_below_link_to_confirm_your_new_email", :devise_confirm_within => distance_of_time_in_words(0, User.confirm_within, :locale => I18n.locale)) %></p>
However, there is no view that has the confirmation_period_expired translation key, so I can't do it in this same manner.
I have a view with:
<div class="form-inputs">
<%= f.input :email, :required => true %>
</div>
And a user model with:
validates :email, uniqueness: true
I want to keep all the translation text in the YAML file, so adding :message to the validates field won't do.
So how can I get the devise_confirm_within time into that confirmation_period_expired error message?
PS: I am using the simple_form gem for forms, and also the dotiw gem for overriding the default distance_of_time_in_words method (this doesn't influence this problem I'm having).
The problem was circumvented when I added this to devise.en.yml and similar to the other devise..yml files:
en:
errors:
messages:
confirmation_period_expired: "some text %{period}"
I however wasn't able to pass a translation interpolation variable to a failed form validation (i.e. add a variable to a devise message), of which I am still curious.

How does fill_in work in Rspec/Capybara?

I am following Michael Hartl's Ruby on Rails Tutorial. When I use rspec/capybara, the fill_in method makes me confused. I have the following view code:
<%= f.label :name %>
<%= f.text_field :name %>
This is my testing code:
fill_in "Name", with: "Example User"
It seems that label and text_field are both required for fill_in to locate the input field. If I either take off f.label or change <%= f.text_field :name %> to be <%= f.text_field :another_name %>, the test will give me ElementNotFound error. Can anyone explain how the fill_in works here? Are input field and label both required for fill_in method?
It is stated that fill_in looks for field name, id or label text. According to ActionView::Helpers::FormHelper section of rails guides, the view code which you ask about should be translated to the following html code:
# I assume that you made a form for a #user object
<label for="user_name">
Name
</label>
<input id="user_name" name="user[name]" type="text" />
As you see, label produced the "Name" text, which you ask for inside of your fill_in expression. But id and name properties of input field are slightly different, so you should have been using id based selector to achieve the same result:
fill_in "user_name", with: 'Example User'
So, to sum up, label field is not required, but you should watch for your html code carefully and select the appropriate parameters for fill_in expression.
Just to add to what twonegatives posted. Here's what the capybara docs say for the fill_in() method:
The field can be found via its name [attribute], id [attribute,] or label text
http://rubydoc.info/github/jnicklas/capybara/Capybara/Node/Actions:fill_in
When I delete the 'Name' label, I can use any of the following and the tests still pass:
fill_in 'user_name', with: "Example User" #locate text field by id attribute
fill_in :user_name, with: "Example User" #locate text field by id attribute
fill_in 'user[name]', with: "Example User" #locate text field by name attribute
fill_in :'user[name]' with: "Example User" #locate text field by name attribute
In ruby, some characters cannot be used in a symbol name unless the whole symbol is quoted.
Capybara must be retrieving all the text fields (or text areas) from the page, then getting the values of the id and name attributes(easily done with something like Nokogiri) then checking if either value is equal to the first argument to fill_in() (after converting the first argument to a String via to_s()).
I provided my 2 cents here: Capybara not finding form elements.
If you call the Rails text_field helper with underscore (:first_name), the DOM gets rendered as "First name" and its what Capybara will need. No need for an id attribute.
View:
<%= form.text_field :first_name %>
Test:
fill_in "First name", with: 'Elaine'

Capybara testing value of hidden field

I have a form with a hidden field that contains the current date.
I'm trying to figure out how to write a capybara finder to:
Check that the field is there
Check the value of the field
Is this possible with Capybara?
just do this:
find("#id_of_hidden_input", :visible => false).value
the matcher has_field? works with hidden fields as well. no need to do weird gymnastics with find or all in this context.
page.has_field? "label of the field", type: :hidden, with: "field value"
page.has_field? "id_of_the_field", type: :hidden, with: "field value"
the key here is setting the :type option to :hidden explicitly.
why use a label with a hidden field? this comes in handy if you're using a js library, like flatpickr, that cloaks your original text field to hide it. not coupling your behavior tests to specific markup is always a good thing.
You could also instruct Capybara to not ignore hidden elements globally in your spec_helper.rb or equivalent. The default behaviour can be overridden:
# default behavior for hidden elements
# Capybara.ignore_hidden_elements = false
# find all elements (hidden or visible)
page.all(".articles .article[id='foo']")
# find visible elements only (overwrite the standard behavior just for this query)
page.all(".articles .article[id='foo']", :visible => true)
# changing the default behavior (e.g. in your features/support/env.rb file)
Capybara.ignore_hidden_elements = true
# now the query just finds visible nodes by default
page.all(".articles .article[id='foo']")
# but you can change the default behaviour by passing the :visible option again
page.all(".articles .article[id='foo']", :visible => false)
Examples taken from this article.
its simple you can do it by using find_by_css or by using xpath as follow
page.find_by_css('#foo .bar a') #foo is the id the foo has .bar class
page.find('/table/tbody/tr[3]') #path of the element we want to find

Formtastic non-model form, integration with external site, override/specify the input ID values

I'm using formtastic to collect information from a form and post dirctly to an external site.
I have no problem generating the form itself. However, since this is being submitted to an external site, they require that each input field have the specific IDs they specify, eg email or last_name -- not the closest Formtastic form, eg _email_input or _last_name_input.
I've looked at the Formtastic v1.2.3 code and I'm 90% sure the answer is "sorry, can't do that." I figured it couldn't hurt to check if I'm missing something. I would like some way to specify the ID completely, as in:
= semantic_form_for('', :url => "https://external_site.com/handler, :method => "post") do |form|
= form.input :last_name, :id => "last_name"
[etc]
Is this possible?
(I will note that I recognize that another, arguably superior approach would be to create an appropriate controller, sanity check the parameters locally, and dispatch the remote call from within the app only when it's well formed; however, that's not what I'm trying to do at the moment.)
Firstly i think you need to use semantic_fields_for for non-model forms. Next, to pass ids to each field, you can use the input_html options to specify them. for eg
form.input :email, :input_html => {:name => 'email', :id => 'email' }

Resources