Rspec test failing when output indicates it should pass - ruby-on-rails

~~~~~~~~~~~~~~~
Edit/Update
~~~~~~~~~~~~~~~
Ok, I fixed the tests that were failing to pass by appending a ".to_s" to each user.password_digest in the change blocks. I assume this is working because before user.password_digest was sort of like a pointer, and calling "to_s" forces the test to compare the string values. If anyone can explain why the test compares the pointer and not the value, please enlighten me.
After adding the .to_s calls (added everywhere I was expecting a user attribute to change), Failure #3 is still occurring (and a new failure, actually, but I'm sure it's caused by the same issue causing Failure #3). Any ideas why the test "correct user with correct password should change email" isn't catching the change action that happens correctly in the browser?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I'm trying to validate behavior of a form to update a user's profile (change email and/or password). 3 of my tests are failing, and I can't figure out why. Take a look at the console output when I run the tests...
Failures:
1) User Pages Edit page correct user updates password with incorrect password should not change password
Failure/Error: expect { click_button "Save" }.not_to change{ user.password_digest }
result should not have changed, but did change from "$2a$10$Xrg1SHSyDmK5Of9HrjgYAuzkJzKk7HeaVjj4ZT9Ldz2R9BNji3D2S" to "$2a$10$Xrg1SHSyDmK5Of9HrjgYAuzkJzKk7HeaVjj4ZT9Ldz2R9BNji3D2S"
# ./spec/requests/user_pages_spec.rb:135:in `block (6 levels) in <top (required)>'
2) User Pages Edit page correct user updates password with confirmation mismatch should not change password
Failure/Error: expect { click_button "Save" }.not_to change{ user.password_digest }
result should not have changed, but did change from "$2a$10$bm2viuIuNCRIEEWe/qYVAOVl0r0EW7Y/1CqalKUwgR.ht/wVtQ8Zi" to "$2a$10$bm2viuIuNCRIEEWe/qYVAOVl0r0EW7Y/1CqalKUwgR.ht/wVtQ8Zi"
# ./spec/requests/user_pages_spec.rb:147:in `block (6 levels) in <top (required)>'
3) User Pages Edit page correct user updates email with correct password should change email
Failure/Error: expect { click_button "Save" }.to change{ user.email }.to(new_email)
result should have been changed to "new_email#example.com", but is now "person_7#example.com"
# ./spec/requests/user_pages_spec.rb:121:in `block (6 levels) in <top (required)>'
Finished in 2.99 seconds
8 examples, 3 failures
Failures #1 & 2 should be passing, right? The before and after strings match, and they're expected not to change! What could be going on here?
Furthermore, I can't figure out why failure #3 is happening.
The code works as expected in the browser. Could it have something to do with AJAX? The update action the form is hitting doesn't redirect_to anything -- it just renders the page again with flash notices. I'm a Rails newbie so I'm probably missing something obvious.
The form:
<%= form_tag user_path(params[:id]), method: :put do %>
<%= label_tag :email %>
<%= text_field_tag :email, params[:email] || #user.email %>
<%= label_tag :new_password %>
<%= password_field_tag :new_password %>
<%= label_tag :new_password_confirmation, "Confirm new password" %>
<%= password_field_tag :new_password_confirmation %>
<%= label_tag :password %>
<%= password_field_tag :password %>
<%= submit_tag "Save", class: "btn btn-primary pull-down" %>
<% end %>
The tests spec (unrelated tests removed for clarity):
require 'spec_helper'
describe "User Pages" do
subject { page }
describe "Edit page" do
let(:user) { FactoryGirl.create(:user) }
describe "correct user" do
before do
log_in user # helper method that logs the user in, a la Michael Hartl tutorial
visit edit_user_path(user)
end
it { current_path.should == edit_user_path(user) }
it { should have_selector('title', text: 'Edit') }
it { should_not have_content('not authorized') }
describe "updates email" do
let(:new_email) { "new_email#example.com" }
before { fill_in 'Email', with: new_email }
describe "with incorrect password" do
it "should not change email" do
expect { click_button "Save" }.not_to change{ user.email }
end
end
describe "with correct password" do
before { fill_in 'Password', with: user.password }
it "should change email" do
expect { click_button "Save" }.to change{ user.email }.to(new_email)
end
end
end
describe "updates password" do
describe "with incorrect password" do
before do
fill_in 'New password', with: 'newpassword'
fill_in 'Confirm new password', with: 'newpassword'
end
it "should not change password" do
expect { click_button "Save" }.not_to change{ user.password_digest }
end
end
describe "with confirmation mismatch" do
before do
fill_in 'New password', with: 'newpassword'
fill_in 'Confirm new password', with: 'password'
fill_in 'Password', with: user.password
end
it "should not change password" do
expect { click_button "Save" }.not_to change{ user.password_digest }
end
end
describe "with correct password" do
before do
fill_in 'New password', with: 'newpassword'
fill_in 'Confirm new password', with: 'newpassword'
fill_in 'Password', with: user.password
end
it "should change password" do
expect { click_button "Save" }.to change{ user.password_digest }
end
end
end
end
end
end
Relevant gem versions: Rails 3.2.9, Capybara 1.1.2, FactoryGirl 4.1.0

Related

Find an element without an id for Capybara testing

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

Capybara login test

I want to test if login of a page works, so I create two tests if url change and if content change.
This is my view:
<%= f.email_field :email, :autofocus => true, placeholder: "Email" %>
<%= f.password_field :password, placeholder: "Password" %>
<%= f.submit "Login" %>
algorithm:
visit '/users/sign_in'
fill_in 'Email', with: email
fill_in 'Password', with: password
click_on 'Login'
Tests:
expect(page).to have_content('Welcome')
Result : expected to find text "Welcome" in "Login"
expect(current_path).to eql('/home')
Result: expected: "/home" got: "/"
All the tests fails and I don't know why, I use valid logins and I can manually use the login with success.
"expected to find text "Welcome" in "Login"", these errors generally occours when the page doesn't loads well but the test gets executed. So you should apply waits in your test. The following code should work for you:
visit '/users/sign_in'
page.should have_content("Wait for some text which is diaplayed on the page") //waits for the sign in page to load
fill_in 'Email', with: email
fill_in 'Password', with: password
click_on 'Login'
page.should have_no_content("Wait for the text which is available in the sign in page but not on next page") //waits for the sign in page to disappear and open welcome page.
page.should have_content("Welcome")
Note: Instead of waiting for some text you can also wait for css selectors
Hope this helps :)

Capybara element not found haml button

I have a diagnostic spec and i believe there is some inconsistency in my use of the language between the spec and the view files. However i have not been able to resolve the problem. The test is as follows
it "updates a diagnostic report" do
diagnostic_info = FG.create(:diagnostic_info)
diagnostic_info.save!
visit edit_admin_diagnostic_path(diagnostic_info)
fill_in 'diagnostic_info_notes', with: "test notes"
click_button "Save"
page.should have_content("Saved")
page.should have_content("test notes")
end
the view is
.field
= label_tag :notes
= f.text_field "notes"
= submit_tag #diagnostic.data["Save"], method: :put, data: { confirm: "Are you sure?" }
and the failure is
1) /admin/diagnostics updates a diagnostic report
Failure/Error: click_button "Save"
Capybara::ElementNotFound:
Unable to find button "Save"
I have been trying to change the syntax in the view file so that the submit tag is instead a button. This is because i thought the problem was the use of tag rather than button. However I have not been able to do this with haml syntax successfully.
Rails has built in support for localization and internationalization. No need to roll your own.
# app/views/diagnostics/edit.haml.erb
.field
= label_tag :notes
= f.text_field "notes"
= submit_tag I18n.t('.save'), method: :put, data: { confirm: "Are you sure?" }
The translations are stored in YAML files located in config/locales.
# config/locales/en.yml
en:
diagnostics:
edit:
save: 'Save'
You can also use your translations in your specs:
it "updates a diagnostic report" do
diagnostic_info = FG.create(:diagnostic_info)
diagnostic_info.save!
visit edit_admin_diagnostic_path(diagnostic_info)
fill_in 'diagnostic_info_notes', with: "test notes"
click_button I18n.t('diagnostics.edit.save') # Note that we need full path
page.should have_content(I18n.t('diagnostics.edit.save'))
page.should have_content("test notes")
end

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.

How do I solve rspec errors end of ROR tutorial CH 9

I got to the end of Chapter 9 of Michael Hartl's Ruby on Rails Tutorial and got failed rspec tests. I have gone through the chapter many times and can't find what I did wrong. Please help! Also, I am a two week old programmer so if you could detail the steps you went through debugging that would help me a lot!
My git repo is at https://github.com/kerrieyee/sample_app and The rspec results are as follows:
Macintosh-143:sample_app jeffreyyee$ bundle exec rspec spec/
..................................................................FF........FFFF.........
Failures:
1) User pages index delete links as an admin user
Failure/Error: it { should have_link('delete', href: user_path(User.first)) }
expected link "delete" to return something
# ./spec/requests/user_pages_spec.rb:45:in `block (5 levels) in <top (required)>'
2) User pages index delete links as an admin user should be able to delete another user
Failure/Error: expect { click_link('delete') }.to change(User, :count).by(-1)
Capybara::ElementNotFound:
no link with title, id or text 'delete' found
# (eval):2:in `click_link'
# ./spec/requests/user_pages_spec.rb:47:in `block (6 levels) in <top (required)>'
# ./spec/requests/user_pages_spec.rb:47:in `block (5 levels) in <top (required)>'
3) User pages signup with valid information should create a user
Failure/Error: fill_in "Confirmation", with: "foobar"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Confirmation' found
# (eval):2:in `fill_in'
# ./spec/requests/user_pages_spec.rb:96:in `block (4 levels) in <top (required)>'
4) User pages signup with valid information after saving the user
Failure/Error: fill_in "Confirmation", with: "foobar"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Confirmation' found
# (eval):2:in `fill_in'
# ./spec/requests/user_pages_spec.rb:96:in `block (4 levels) in <top (required)>'
5) User pages signup with valid information after saving the user
Failure/Error: fill_in "Confirmation", with: "foobar"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Confirmation' found
# (eval):2:in `fill_in'
# ./spec/requests/user_pages_spec.rb:96:in `block (4 levels) in <top (required)>'
6) User pages signup with valid information after saving the user
Failure/Error: fill_in "Confirmation", with: "foobar"
Capybara::ElementNotFound:
cannot fill in, no text field, text area or password field with id, name, or label 'Confirmation' found
# (eval):2:in `fill_in'
# ./spec/requests/user_pages_spec.rb:96:in `block (4 levels) in <top (required)>'
Finished in 4.83 seconds
89 examples, 6 failures
Failed examples:
rspec ./spec/requests/user_pages_spec.rb:45 # User pages index delete links as an admin user
rspec ./spec/requests/user_pages_spec.rb:46 # User pages index delete links as an admin user should be able to delete another user
rspec ./spec/requests/user_pages_spec.rb:99 # User pages signup with valid information should create a user
rspec ./spec/requests/user_pages_spec.rb:108 # User pages signup with valid information after saving the user
rspec ./spec/requests/user_pages_spec.rb:109 # User pages signup with valid information after saving the user
rspec ./spec/requests/user_pages_spec.rb:110 # User pages signup with valid information after saving the user
please note the password_confirmation label text is Confirm Password, you need udpate the spec like below:
change
fill_in "Confirmation", with: "foobar
to
fill_in "Confirm Password", with: "foobar
I met this issue too, and get solved with above way.
I ended up solving the first 4 failed tests by first taking out the partial I was rendering to in new.html.erb and edit.html.erb. Because I am not an experienced programmer, I am not sure how to fix the code in the tutorial and would appreciate anyone who can tell me what is wrong. This is the refactored code:
<% provide(:title, 'Sign up') %>
<h1>Sign up</h1>
<div class="row">
<div class="span6 offset3">
<%= form_for(#user) do |f| %>
<%= render 'fields', f: f %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
</div>
</div>
This is the partial:
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
The last two errors I solved by looking at Michael Hartl's index.html.erb file on github. Essentially, the issue was that the index.html.erb code needed to call the partial _users.html.erb.
Make sure the text in the label for :password_confirmation matches in both user_pages_spec.rb and new.html.erb. For instance, you would want the partial in new.html.erb to look like this:
<%= render 'shared/error_messages' %>
<%= f.label :name %>
<%= f.text_field :name %>
<%= f.label :email %>
<%= f.text_field :email %>
<%= f.label :password %>
<%= f.password_field :password %>
<%= f.label :password_confirmation, "Confirm Password" %>
<%= f.password_field :password_confirmation %>
<%= f.submit "Create my account", class: "btn btn-large btn-primary" %>
<% end %>
and user_pages_spec.rb like this:
describe "with valid information" do
before do
fill_in "Name", with: "Example User"
fill_in "Email", with: "user#example.com"
fill_in "Password", with: "foobar"
fill_in "Confirm Password", with: "foobar"
end
it "should create a user" do
expect { click_button submit}.to change(User, :count).by(1)
end
end
Alex De Simone is correct I had the same problem and he solved it. Much thanks. Capybara does what we call browser testing. Meaning its kind of like go here click that.
As an example of the problem I had and how I solved it.
the error
Capybara::ElementNotFound
means it was looking for the button to click on and it could not find it. If u look at the code
fill_in "Confirmation", with: "foobar"
then you look at the webpage and it says Confirm Password. You could get your test to pass by typing in
fill_in "Confirm Password", with: "foobar"
you basically just have to match the strings in your capybara test with what it says on the webpage when you look at it.

Resources