Capybara::ElementNotFound: Unable to find button "Log in" that is not disabled - ruby-on-rails

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.

Related

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

How to check page content after button click correctly?

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.

Minitest/Capybara/Devise login is not progressing past sign in page

Following some information from this example: http://snippets.aktagon.com/snippets/644-how-to-test-authentication-with-devise-capybara-minitest I have the test half running. But the click_on method isn't submitting the form. I've also tried click_button 'Sign in' and page.execute_script("$('form').submit()") without any luck. Here' the test:
# test/integration/login_test.rb
require "test_helper"
require "minitest/rails/capybara"
class LoginTest < ActionDispatch::IntegrationTest
include Rails.application.routes.url_helpers
include Capybara::DSL
include Warden::Test::Helpers
Warden.test_mode!
let(:user) { User.new(email: "example#blah.com", password: "password") }
it "will login successfully" do
visit new_user_session_path
fill_in 'user_email', with: user.email
fill_in 'user_password', with: user.password
click_on 'Sign in'
current_path.must_equal dashboards_path
page.must_include 'Signed in successfully'
end
end
According to the page.execute_script method error it said Capybara::NotSupportedByDriverError Exception: Capybara::Driver::Base#execute_script and after reading another question on here I added cappybara-webkit to try and have that work. But no change with that.
The target form submit button is as follows:
<input class="btn btn-default" name="commit" value="Sign in" type="submit" />
The test error reads:
LoginTest
test_0001_will login successfully FAIL (0.38s)
Minitest::Assertion: Expected: "/dashboards"
Actual: "/users/sign_in"
test/integration/login_test.rb:17:in `block in <class:LoginTest>'
I've looked at the page.html with byebug and don't see any errors about invalid user or the like. And I do see the value for email and password are set. The page form just doesn't seem to be submitting.
Given your last comment, you are failing to authenticate. You want to avoid using a Factory. So you want to use a Fixture, which is what I am also using.
In my case, here's my users.yml file (I call my users owners), which for me is in test/fixtures:
owner:
# column: value
first_name: 'Testy'
last_name: 'McTesterton'
email: 'test#test.com'
encrypted_password: <%= Devise.bcrypt(Owner, 'password') %>
admin: false
confirmed_at: <%= Time.now %>
I have the Devise confirmable option selected so I have to feed it a confirmed_at for creation. If you don't, you won't need that. You will have to have a field for anything you have turned on though that would validate a user, which, hopefully, is no more than confirmed_at. I can only help with confirmed at :). The "admin" field is because I have an admin option.
This will create your user and you can log in with a the login method you have above. I'm guessing it will work for you since it works for me.

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.

"background(:all)" block doesn't work in rpsec feature spec

I'm using rspec, capybara and Selenium to test my whole application stack. I've turned off transactional fixtures, and I'm using database cleaner to clean my database only after the whole suite has been run. These allows me to test things based using objects created in preceding tests.
Anyway, let's say I want to create user a999 (via a form, so a test in itself) and then proceed to test logging him out and logging him back in.
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
feature "user a999 sign up", js: true do
before(:each){
sign_up( #a999.first_name, #a999.last_name, #a999.profile_name, #a999.email, #a999.password )
}
scenario "welcome message" do
expect(page).to have_content ("Welcome," + #a999.first_name)
end
scenario "can log out" do
end
scenario "can log in" do
end
end
The code above almost works. This is what happens when it's run:
The before block signs up the user before the "welcome message" expectation (I see it physically happening in Firefox thanks to Selenium), and then the welcome message appears after a redirect so the "welcome message" spec passes.
However, because I have the before block set to 'each' the before block is run another two times, meaning I now have three a999 users in the database.
Of course, and setting the before block to (:all) should fix this problem. The user is signed up one, and we go from there, signing the exact same user in and out. It's a feature test that tests the whole stack remember, so I want to do this properly, emulate how a real user will be using my app.
def sign_up(first_name, last_name, profile_name, email, password)
visit "/"
click_link "Register"
fill_in('First name', with: first_name)
fill_in('Last name', with: last_name)
fill_in('Profile name', with: profile_name)
fill_in('Email', with: email)
fill_in('Password', with: password)
fill_in('Password confirmation', with: password)
click_button 'Sign up'
end
feature "user a999 sign up", js: true do
before(:all){
sign_up( #a999.first_name, #a999.last_name, #a999.profile_name, #a999.email, #a999.password )
}
scenario "welcome message" do
expect(page).to have_content ("Welcome," + #a999.first_name)
end
scenario "can log out" do
end
scenario "can log in" do
end
end
But with this code nothing happens at all. Seriously, just nothing. Selenium doesn't follow the code in the before block at all! Firefox doesn't even start up.
Why is this? I mean, that should work at the very least.
before(:each) = signs user up before my eyes
before(:all) = completely dead
I can't explain why nothing comes up at all, but based on numerous posts*, you can't reasonable use before(:all) with capybara, since it resets the session between each example.
*Related posts:
Capybara and before(:all) in rspec
capybara/selenium with rspec before :all hook

Resources