Find an element without an id for Capybara testing - ruby-on-rails

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

Related

Rails 5, simple_form_for, RSpec & Capybara - click_button does not work with my form

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

Capybara unable to find field "search"

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

Capybara::ElementNotFound: Unable to find field "title"

I could not resolve this issue. Please help me. It gives me element not found error.
spec/features/todos/create_spec.rb
require 'spec_helper'
describe "Creating todos" do
let(:user) { FactoryGirl.create(:user)}
before(:each) do
visit root_path
click_link "Login"
fill_in "Email", with: "user#gmail.com"
fill_in "Password", with: "password"
click_button "Sign in"
end
it "redirects to the todos index page" do
visit "/todos"
fill_in "title", with: "MyString"
click_button "Create"
expect(page).to have_title("MyString")
end
my view code.
_new_form.html.erb
<%= form_for current_user.todos.new, remote:true do |f| %>
<div class="input-group">
<%= f.text_field :title, class: "form-control", placeholder: "title" %>
<span class="input-group-btn">
<%= f.submit "Create", class: "btn btn-success" %>
</span>
</div>
<% end %>
spec_helper.rb
def sign_in
#user = FactoryGirl.create(:user)
controller.stub(:authenticate_user!).and_return(true)
#user
end
If you have the code running on a server locally, inspect the element and the name of the field is what Capybara needs to run. Generally, if the form is nested, the name rails will come up with (in this case) is something like todos[title].
So, spec/features/todos/create_spec.rb should look something like:
require 'spec_helper'
...
it "redirects to the todos index page" do
visit "/todos"
fill_in "todos[title]", with: "MyString"
click_button "Create"
expect(page).to have_title("MyString")
end
Found my answer.
In the view file I've a text_field with title with an id. The id = todo_title in the console
But am calling title in the test . Here the capybara not been able to find title. It was todo_title
After using
fill_in "todo_title"
It worked like charm.
In your form, there must be an element with the name as "title". From the docs:
fill_in(locator, options = {}) ⇒ Object
Locate a text field or text area and fill it in with the given text The field can be found via its name, id or label text.

Fill in a field without label

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'

Test a form text_field presence with capybara

I have the following form and I want to check if the text field is present or not. How can I do that ?
<%= form_for(ownership, remote: true) do |f| %>
<div>
<%= f.text_field :confirm, value: nil %>
<%= f.hidden_field :start_date, value: Time.now %>
</div>
<%= f.submit t('button.ownership.take.confirmation'), class: "btn btn-small"%>
<% end %>
Here my test :
describe "for not confirmed ownership" do
before do
FactoryGirl.create(:agreed_ownership, user: current_user, product: product)
be_signed_in_as(current_user)
visit current_page
end
# it { should_not have_text_field(confirm) }
it { should_not have_button(t('button.ownership.take.confirmation')) }
end
You'd use a has_css? expectation:
it "should have the confirm input field" do
visit current_page
expect(page).to have_css('input[type="text"]')
end
You can use additional jQuery-style selectors to filter for other attributes on the input field, too. For example, 'input[type="text"][name*="confirm"]' would select for confirm appearing in the input field's name attribute.
To set an expectation the field isn't present, you'd use to_not on your expectation: expect(page).to_not have_css('input[type="text"]')
Bonus: Here's the older, should-style syntax:
it "should have the confirm input field" do
visit current_page
page.should have_css('input[type="text"]')
end
it "shouldn't have the confirm input field" do
visit current_page
page.should_not have_css('input[type="text"]')
end

Resources