How to check page content after button click correctly? - ruby-on-rails

I want to check if there loads correct page after clicking 'sign in' button.
users_spec.rb
before :each do
user = User.create(:email => 'admin#cm.com', :password => '123')
end
it "signs me in" do
visit '/users/sign_in'
within("#new_user") do
fill_in 'Email', :with => 'admin#cm.com'
fill_in 'Password', :with => '123'
click_button 'Sign in'
end
expect(page).to have_content '#{user.name}'
end
expect(page).to have_content 'Dashboard' checks is there user.name word on the same page, where the form is located. So, what's the sense in click_button then? How to make it check content on the page that should load AFTER click_button? By the way, how to correctly name such tests?
Sorry, if it's a silly question, I'm a newbie in rspec :c
Thank you!

You have to pick some content that appears on the page after the user logs in. Does your app display a message saying something like "You are now logged in", if so you can do
expect(page).to have_content("You are now logged in")
If not, does it display the users name in a header bar? Then you can do something like
expect(page).to have_css("header", text: user.name)
etc... The key is that whatever you're searching for needs to appear on the next page but not on the page with the form. In both of those cases Capybara will wait up to Capybara.default_max_wait_time seconds while retrying to find the text (assuming you're using a driver other than rack-test) which should give the next page time to load. If you're using the rack-test driver then there is no JS or asynchronous support, the click_button should have submitted a form and the expect won't execute until the next page has loaded.
As for test naming -- name it something that makes sense to you so you know what its doing a year from now.

Related

Capybara::ElementNotFound: Unable to find button "Log in" that is not disabled

I'm running an acceptance test that includes logging in via /users/sign_in.
How do I set up the test so I can "click" the submit button within a Rspec Capybara test?
Seems that Devise disables the Login submit button and runs javascript to make things work.
<%= f.submit "Log in" %>
produces:
<input type="submit" name="commit" value="Log In" tabindex="4" data-disable-with="Log In" />
The data-disable-with, which devise needs, seems to be breaking capybara testing. I would just like to click the button as per my acceptance test below.
it "logs in and shows success message" do
visit '/users/sign_in'
login_as(user, :scope => :user)
within(".login-details") do
fill_in 'Email', with: user.email
fill_in 'Password', with: 'fakepassword'
end
click_button 'Log in'
expect(page).to have_content 'Success'
end
Is producing:
Capybara::ElementNotFound: Unable to find button "Log in" that is not disabled
Note: I have multiple pages that logging in can send a user to, this example is the simplest test that reveals this bug. So no my goal is not to 'make sure devise works', incase you were wondering 'why do they need this?'
The data-disable-with attribute is used by Rails UJS to change the buttons text after it's been clicked so wouldn't be affecting this test. Looking at the HTML element you posted the value of the button is 'Log In' so, since case matters, you'd need to do
click_button 'Log In'
rather than 'Log in'
I do wonder why you have login_as(user, :scope => :user) in the same code where you're filling in the username and password though, you'd normally only use login_as when you wanted to bypass actually filling in the form and logging in.

Why do I get the error in my acceptance test?

Tell me please,why does it happen?
I can't understand, if I write:
feature "Article Creation" do
#here i write (:all)
before(:all) do
sign_up_helper
end
I get the error:
Article Creation allows user to visit to creating article page
Failure/Error: fill_in :article_title, :with => 'test_title'
Capybara::ElementNotFound:
Unable to find field :article_title
or
1) Article Creation allows user to visit to article page
Failure/Error: expect(page).to have_content I18n.t('articles.articles_new')
expected to find text "New Article:" in "Toggle navigation Blog Rails New Contacts Sign in --- !ruby/hash:ActionController::Parameters controller: devise/sessions action: new {\"controller\"=>\"devise/sessions\", \"action\"=>\"new\"} nil You need to sign in or sign up before continuing. Sign in: Email Password Remember me Sign up Forgot your password?"
but, if I write:
feature "Article Creation" do
#here i write(:each)
before(:each) do
sign_up_helper
end
It's Ok. All tests works. My question -WHY?
This is my test:
*#before all test visitor signs up
#here I've changed :all and :each*
feature "Article Creation" do
before(:all) do
sign_up_helper
end
scenario "allows user to visit to article page" do
visit new_article_path
expect(page).to have_content I18n.t('articles.articles_new')
end
scenario "allows user to visit to created article page" do
visit new_article_path
fill_in :article_title, :with => 'test_title'
fill_in :article_text, :with => 'example_text'
click_button 'Save Article'
expect(page).to have_content 'example_text'
end
This is sign_up_helper method:
#spec/support/session_helper.rb
def sign_up_helper
visit new_user_registration_path
fill_in :user_email, :with => 'user#example.com'
fill_in :user_username, :with => 'mike'
fill_in :user_password, :with => 'secure123!##'
fill_in :user_password_confirmation, :with => 'secure123!##'
click_button 'Sign up'
end
This is html form:
<p>
<label for="article_title">Title</label><br/>
<input type="text" name="article[title]" id="article_title" />
</p>
<p>
<label for="article_text">Text</label><br/>
<textarea name="article[text]" id="article_text">
</textarea>
</p>
Environment for each test is set anew, I think. New session, cookies, etc. In many cases, even brand new users are generated. So one "global" login is not possible.
Even if it were possible, it would still be a problem, as it introduces spec order dependency which is bad. Imagine that one of your specs logs user out. Then each subsequent spec would fail, because user is not logged in anymore.
To prevent this, make sure that each spec sets its own environment as it needs it (user logins, method stubs, etc.), without relying on side-effects from previously executed specs (which may or may not persist).

Capybara loses cookies between requests

I have the follow test:
def login_user(email, password)
visit new_user_session_path
fill_in 'E-mail', with: email
fill_in 'Password', with: password
click_button 'go'
end
scenario 'some test' do
order = Fabricate(:order_one, company: user.company)
visit "http://127.0.0.1:49645/orders/#{order.id}" # change to visit "/orders/#{order.id}"
login_user(user.email, user.password)
#assert
end
Whats happen is that in first step (visit...) the user is not logged, so I set some informations using cookie. But, when login_user is executed, this cookie is empty.
Usigin selenium-webdriver
Any idea here ?
Thanks in advance
When using a JS capable driver #visit is not guaranteed to have finished loading the page when it returns. Since the cookie is not set in the browser until the response is processed, your login_user is actually telling the browser to stop processing it's current visit and visit somewhere else which stops the cookie from ever being set in the browser. After the first visit you need to wait for something visible on the page to be sure the cookies are correctly set.
scenario 'some test' do
order = Fabricate(:order_one, company: user.company)
visit "http://127.0.0.1:49645/orders/#{order.id}"
expect(page).to have_content('you are not logged in') #or whatever shows on the page visited
login_user(user.email, user.password)
#assert
end

RSpec / Capybara - Failing to log in

I am trying to learn TDD, and can't get this integration test with Capybara and Rspec to work. The user visits the home page, clicks "Login", fills out the form with an "Email" and "Password", clicks "Log in", and then I expect the page to have the content "Signed in Successfully".
home_page_spec.rb
require 'spec_helper'
feature 'Login' do
scenario 'user logs in to the site' do
visit root_path
click_link 'Login'
expect(page).to have_content "Sign in to your account."
fill_in('Email', with: "test1#joijjoi.eud")
fill_in 'Password', with: "password"
click_button 'Log in'
expect(page).to have_content('Signed in Successfully')
end
end
I am getting "Failure/Error: expect(page).to have_content('Signed in Successfully'). Expected to find text "Signed in Successfully" in . . . . " The text that it finds is the sign in page. It is as if the test is finding the Log in button, but either not clicking it, or the button is not forwarding the page, but it works if I do this by hand in the browser. Any suggestions? Thanks.
you can use the gem capybara-screenshot that save the page html and screen shot when a test fails. That way you can debug the issues. Or you can temporarily switch to selenium webdriver for capybara which opens the default browser and executes your tests.

Determining Form Submission with RSpec/Capybara

I have a project in which I am using RSpec and Capybara to do unit testing. I have fully flushed out model and controller tests which are passing nicely and handle the heavy lifting for pre-database validation.
I am now testing user experience and front end items and want to know how i could verify that a form did NOT submit. If a user mismatches passwords or some other erred data, I have script to set the error and prevent submission.
I know i could search for error text but where there a way to check that the 'submit' never happened and feel confident that no server trip was made.
I want something like:
it "should not sumbit if user name is less than 3 characters" do
visit /edit_account_settings(#user)
fill_in "username", :with => "fo"
click_button "SAVE"
# HOW DO I DO THIS?
expect( ... ).not_to submit_to_server
end
This is not something that you should be testing in an integration test. In integration tests you are taking the point of view of the end user, and therefore you should only be testing what the user can actually see. If the only evidence the user sees that the form has not been submitted is an error message, then that is what you should test for.
In integration tests we most test what the user would see like if an empty field is given then there must be error message according to validations. But still if you want you check as follow
describe "User Registration" do
before do
visit /edit_account_settings(#user)
fill_in "username", :with => "fo"
click_button "SAVE"
end
it "should not sumbit if user name is less than 3 characters" do
page.should have_content "your error message"
end
it "should create the user and redirect to blah_path" do
current_path.should eq blah_path
end
it "should add user in users table" do
expect { user.create }.to change(User, :count).from(0).to(1)
end
end

Resources