Cannot reach the password of the user after assigning it - RSpec - ruby-on-rails

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.

Related

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

Trouble assigning user access levels

I'm following this tutorial, as I wanted to learn how to create user authorization with singular roles (each user has one role) from scratch rather than using a gem like rolify that does it all for me, but I'm hung up on assigning the users access levels.
When I type erin = User.find(9) in the console it finds my test#test.com user. I try to issue the erin.admin! command but it throws an error about the password? (ActiveRecord::RecordInvalid: Validation failed: Password can't be blank).
I've also tried erin.access_level = "admin" which returns "admin" while I'm still in the console but no longer exists when I exit the console, fire up the rails server and try to test out my test#test.com user in my app.
Is there any other way to assign access levels? Am I just doing it wrong?
The User record cannot be saved because a validation exists that requires a password. I don't know if there are special rules for the format of the password, but you can easily set a password so that you can save the user:
user = User.find(9)
user.password = 'Test1234'
user.password_confirmation = 'Test1234' # you might need this as well
user.access_level = 'admin'
user.save #=> true
If user.save returns false, check user.errors for any other validation errors that would cause the record not to save.
For the second part of my question, where my database didn't seem to deploy to Heroku, it's because I was working in the dev db, not the production db.
To do that, I ran "heroku run rails console" and then followed the above steps to give a user admin access levels. More here: https://devcenter.heroku.com/articles/getting-started-with-rails4#console

Devise user creation fails during Capybara integration testing (and Selenium webdriver)

I'm trying to create a user during an integration test to use for some operations. I'm using devise with :confirmable. The code is the following:
user = User.create({username: "user1", password: "pass1234", password_confirmation: "pass1234", email: "test#email.com"})
user.confirm!
fill_in "Username", :with => user.username
fill_in "Password", :with => user.password
click_button "Sign in"
The problem is that the login fails every time I try it. There are no errors about the user creation, but for some reason the user doesn't seem to "be there" when I try to login. I just get 'Invalid username or password' when I try to sign in. This seems like something to do with the fact that maybe Capybara/Selenium webdriver isn't waiting properly for the database operation to take place before it tries to sign in. If that's the case, how could I test it or fix it?
Is it "wrong" to even be trying to insert into the database during an integration test?
I don't use devise myself so can't really comment on the specifics of the problem you're encountering, but this question caught my eye:
Is it "wrong" to even be trying to insert into the database during an integration test?
Yes, I would say it generally is.
Your integration tests should test your code from the point of view of the user:
Expectations should only depend on what the user can actually see.
Actions should correspond only to what the user can actually do.
Inserting something into the database goes beyond the range of actions that the user has at their disposal. It is something for a unit test perhaps, but not for an integration test.
That being said, you could argue that seeding database data is a bit of an exception to this rule, since you're setting up context for your test (see my comments below).

Log in test failing with Devise and Cucumber

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!

Resources