Log in test failing with Devise and Cucumber - ruby-on-rails

I'm using Devise for user Authentication and have the following failing Cucumber scenario:
Scenario: Log in to the system
Given a user called "test" with a password of "secret"
And I am not logged in # Just visits /users/sign_out
When I go to the log in page
And I fill in "user_username" with "test"
And I fill in "user_password" with "secret"
And I press "Sign in"
Then I should see "Signed in successfully."
If I stick a "Then show me the page" at the end I'm shown a page with a blank log in form.
The following (very similar) test works:
Scenario: Fail to log in with invalid credentials
Given a user called "test" with a password of "secret"
And I am not logged in
When I go to the log in page
And I fill in "user_username" with "test"
And I fill in "user_password" with "invalid password"
And I press "Sign in"
Then I should see "Invalid email or password."
... so I'm assuming that the log in does a redirect after a successful validation that Cucumber isn't following (FWIW the log in all works when I do it manually in the browser)... can anyone tell me how to get the test to pass?
Thanks,
Ash
EDIT: It's the last step that is failing with an "expected #has_content?("Signed in successfully.") to return true, got false" error (...ahem... should have mentioned that before!)

is the id field user_username or is it user_email or something?
Also what does When I go to the log in page look like? you sure you go there?

Fixed it! I've just loaded my server with the test environment and reproduced the problem.
I'm using ldap_authenticatable with config.ldap_create_user = true. On the first log in the user account is created if it doesn't exist (which it doesn't in the freshly wiped test db), however this is then redirecting back to the log in page rather than following the root route. Subsequent log ins perform the expected behaviour. So the following test passes:
Scenario: Log in to the system
Given a user called "test" with a password of "secret"
And I am not logged in
When I go to the log in page
And I fill in "user_username" with "test"
And I fill in "user_password" with "secret"
And I press "Sign in"
And I fill in "user_username" with "test"
And I fill in "user_password" with "secret"
And I press "Sign in"
Then I should see "Signed in successfully."
Many thanks to pjammer for the rubber ducking!

Related

Cannot reach the password of the user after assigning it - RSpec

I am trying to write system tests. I want to run a classic login page test.
I have a field for email, password, and submit button.
It is working in production env and alive without any problem.
my test file is like this:
it "can login" do
user = User.create(email: 'mail#mail.com', password: 'password', role:1, name: 'test user')
user.save!
visit '/'
fill_in(:user_email, with: user.email)
fill_in(:user_password, with: 'password')
find(:button, 'Sign in').click
expect(page).to have_content('Signed in.')
end
Whenever I tried to create a user and try to use it in the system testing, it is not working. It is visiting the page, filling the places and clicking the button as it should but it cannot log in, giving error that email or password is not correct.
I believe there is a problem with password encryption or somehow I cannot match the passwords properly.
I have printed out the user after creation in the test case, I have a valid user but somehow I cannot reach its password. I checked the model, there is not a 'password' field. ( I am working on a company project, that is why I am having difficulty to find the problem )
I can assign a password with using user.password = ... but I cannot call it back it seems. (I tried this in rails console, assigning worked, calling back did not and I could use the user and the password for logging in manually)
EDIT:
I found out that the problem is database matching. I could create the user but the test is not using that user...
I found the problem. It was because of data transaction. I changed it truncation for system testing and it worked! It was basically flushing all the data before using it. That was why I was getting error.

Cucumber/Capybara test fails when it should pass

When I manually run the website, it doesn't show Incorrect account ID, please try again and logs in perfectly fine but when I try the same thing with Cucumber/Capybara tests, it fails for some reason. I even outputted the value it is enterring in the form and it seems to be the same id. Please help!
login.feature file
Feature:A user should be able to login
To fill in all the credentials and then go to the landing page of the website
Scenario:Fill the credentials and click login
Given I am on the login page of the website
When I enter my credentials and click the login button
Then I should be directed to the landing page of the website
my_steps.rb file
Given(/^I am on the login page of the website$/) do
visit root_path
end
When(/^I enter my credentials and click the login button$/) do
within("div.row") do
fill_in 'Account', with: 'a1757552'
fill_in 'Password', with: 'adelaideuni'
end
click_button 'Login'
end
Then(/^I should be directed to the landing page of the website$/) do
expect(page).to have_content 'IELTS'
end
Terminal output: (Printing the account id after ggg_d:)
Scenario: Fill the credentials and click login # features/login.feature:5
Given I am on the login page of the website # features/step_definitions/my_steps1.rb:1
When I enter my credentials and click the login button # features/step_definitions/my_steps1.rb:5
Then I should be directed to the landing page of the website # features/step_definitions/my_steps1.rb:13
expected to find text "IELTS" in "Course Advice Assistant\nHelping you choose courses!\nIncorrect account ID, please try again\nAccount\nPassword\nggg_d: a1757552" (RSpec::Expect
ations::ExpectationNotMetError)
./features/step_definitions/my_steps1.rb:14:in `/^I should be directed to the landing page of the website$/'
features/login.feature:8:in `I should be directed to the landing page of the website'
Failing Scenarios:
cucumber features/login.feature:5 # Scenario: Fill the credentials and click login
1 scenario (1 failed)
3 steps (1 failed, 2 passed)

Capybara test case for Login page authentication

I have capybara test case below.
it "Testing login page with valid data" do
fill_in 'email', with: 'kiran#gmail.com'
expect(page).to have_selector("input[value='kiran#gmail.com']")#Checking values are inserted in email field
fill_in 'password', with: 'Kiran.6565'
expect(page).to have_selector("input[value='Kiran.6565']")#Checking values are inserted in password field
click_button('submit')
expect(current_path).to eql(patient_detail_path(4))
end
I am checking Login page once the email and password fields are matches it should redirect to patient_details_path with id field value. In above code i specified email and password is working fine for manual login, but problem is in test case. Expected result: it should redirect to another page(patient_details_path) but it redirecting to home page(/) again.
Failures:
1) Login Page Interface Test login page with valid data
Failure/Error: expect(current_path).to eql(patient_detail_path(4))
expected: "/patient_details/4"
got: "/"
(compared using eql?)
# ./spec/views/login_spec.rb:41:in `block (2 levels) in <top (required)>'
Finished in 1.08 seconds (files took 2.13 seconds to load)
14 examples, 1 failure
I tried different solution's from stackoverflow but nothing work for me. Below are the different solution's tried.
#expect(current_path).to eql(patient_detail_path(4))
#expect(page).to have_current_path(patient_detail_path(4))
If email and password mismatch it will throw an error and redirect to login page again. In my scenario it was throwing an error even if email and password are valid . If i add below code in my test case it will work pass the test case.
#expect(page).to have_content "Invalid username/password combination"
Any one please help me i am new to ruby on rails and capybara.
I'm guessing the test you're trying to write should be written something like
before :each do
#user = # Create the required user with whatever method you're using
#patient = # Create the required patient with whatever method you're using
end
it "Logs in with valid data" do
visit(patient_detail_path(#patient)) # gets redirected to the login path
fill_in 'email', with: 'kiran#gmail.com'
fill_in 'password', with: 'Kiran.6565'
click_button('submit')
expect(page).to have_current_path(patient_detail_path(#patient))
end
That's a general guess and might not be 100% correct (tough to guess exactly what you're trying to do with half the test missing - the before block - from your question) but the general parts should be there. Since yours isn't logging in I'm guessing you're not actually creating a valid user with the given email and password, or you don't have a patient created with an id of 4 (you really shouldn't be relying on testing specific id numbers in feature tests though).
Additionally, you should always use the have_current_path matcher when checking for a given path/url since it will prevent test flakiness and since it's not a view test it shouldn't be in spec/views/login_spec.rb, more appropriate would be spec/features/login_spec.rb.
It seems to me that the driver is capturing the URL before Rails has a chance to update the URL to reflect the new page.
Asserting on URL is hard after performing a navigation change as a race condition might appear. I would suggest:
Assert on some other piece of info that could verify the user successfully logged in.
Assert using the wait option.
expect(page).to have_current_path(patient_detail_path(#patient), wait: 3)

How to access the same DB data that Capybara uses

I have a very simple password reset form, which is just a text field to enter an email and a submit button.
There are some client-side validations using JS, so I use the Capyabara JS driver when writing spec tests for it.
This test just tests that a password reset token is added to the user's auth_info table.
describe "password reset form", js: true do
let(:email) { "foo#example.com" }
# Create existing user with an email so we can reset it's password
let!(:user) { create(:user, email: email) }
before(:each) do
fill_in email_field, with: email
click_button reset_button
end
it "generates a new token" do
# `token` is definitely getting set properly when I pause it here
# with binding.pry and inspect the object using `user.reload`
# But when running the test it always shows up as `nil`
expect(user.reload.auth_info.token).to match(/[A-Fa-f0-9]{32}/)
end
end
As the comment notes, I know for a fact the token is getting properly set when I inspect it directly using binding.pry. But RSpec and Capybara are seeing it as nil, even after refreshing the model using reload.
Is Capybara maintaining a different cache or something?
Thanks!
EDIT: Also tried different combinations of applying the reload to the User model as well as the AuthInfo model, in case I needed to refresh the latter too
You're using a JS capable browser which means click_button is asynchronous. The result of this is you're executing click_button and then immediately checking for the token before the action triggered by the button has occurred. You can verify this by putting sleep 5 before the expect and the test should pass. The correct way to make the test wait before the check is to use capybaras matchers to look for info on the page that changes once the click_button has completed, something like either of the following
expect(page).to have_text('text that appears after click_button has succeeded')
expect(page).to have_selector('div.abcde') #element that appears after click_button has succeeded
Those will make the test wait until the action has completed and then you can check for the token

How do I avoid ambiguous step definitions in Cucumber?

I'm running into ambiguous step definition errors. The following scenarios live in different feature files, and have one identical step: Then I should see my profile page. How do I avoid this from happening?
# authentication.feature
Scenario: Successful sign in
Given I visit the sign in page
When I submit valid sign in information
Then I should see my profile page
# signing_up.feature
Scenario: Successful sign up
Given I visit the sign up page
When I submit valid information
Then I should see my profile page
# authentication_steps.rb
...
Then /^I should see my profile page$/ do
page.current_path.should == user_path(#user)
end
# signing_up.feature
...
Then /^I should see my profile page$/ do
page.current_path.should == user_path(#user)
end
I'm running into this problem with error messages too:
Scenario: Unsuccessful sign up
...
Then I should see an error message
Scenario: Unsuccessful login
...
Then I should see an error message
Why not stay only with the one in authentication_steps.rb ? I think you can use all steps in any feature file

Resources