Please understand that I cannot speak English well.
I'm having trouble with the rails rspec error not being resolved.
Rails web app login integration test error.
I'll attach the error and test details here.
error details
test details
I designed the controller's create method to "redirect to home after login".
create method for "login and redirect to home"
And it has been confirmed that it returns to home after logging in on the development server. But it doesn't work in integration tests.
I wondered why.
Perhaps the user data prepared for testing is not loaded properly?
so i can't redirect to home after login?
Factory bot gems and user data generation files required to create RSpec test user data
gem for tests
As an aside, this is my first time writing integration tests in RSpec.
So there may be some rookie mistakes. Thank you very much.
FactoryBot.build(:user) initializes a user in memory, but doesn't save it into the database. That means the login fails, because a user with that email is not found in the database. And because the login failed, the user is still on /login.
To fix this, just change
before do
#user = FactoryBot.build(:user)
end
to
before do
#user = FactoryBot.create(:user)
end
in your user_login_spec.rb.
Related
I have a Rails application which has some User authentication which is built without Devise (or any gem for that matter). It uses the typical session[:user_id] to track the current user.
My understanding of the current state of controller tests is that the Rspec team and Rails teams both recommend against using them. This is fine, but I'm not seeing how to actually sign in as a user from within a request spec. I've done it with Devise with no issue, but Devise uses Warden and such.
I've tried to access the session from within the test but the level of abstraction within request specs seems to prevent access to it.
How can I sign in a user from within a request spec?
You can change the session before the request:
#request.session['user_id'] = '1'
Or add anything else that you require on the session to validate your user.
Or you could create a helper method that actually performs the request needed to login, which is what #dhh recommends.
I have a private rails application that uses Rspec as the test suite and I want to ensure that none of the routes are accessible without logging in.
Is there a way to loop through all the routes and try to access them using the requests part of Rspec and make sure they return a 401 status?
Get all routes and loop through them to test
all_routes = Rails.application.routes.routes.to_a
I'm a bit stumped on how (and where) to write some rspec tests for the "stay signed in" functionality you see all over, including on the google login.
The examples I found on the web weren't much help. Specifically I want to test these two scenarios.
1
a) user signs in with valid credentials without having clicked "stay
signed in"
b) user closes the browser, re-opens it and requests a protect page.
The user should not see the protected page.
The user should see the page asking them to signed in.
2
a) user signs in with valid credentials and having clicked "stay
signed in"
b) user closes the browser, re-opens it and requests a protected page.
The user should not see the page asking them to sign in.
The user should be taken to the protected page.
My first attempt at solving the problem involved simulating a browser close by deleting the user_id I stored in the session (since it gets deleted on browser close). However, these tests failed because I was working in the request spec folder and have no access there to the session variables. My earlier related question: session available in some rspec files and not others. how come?
What is the best way to do these test with rspec?
I think you should try standard rails method for integration tests - open_session.
Personally I never did that and can't give you tested code.
See multiple sessions example on rails guides.
There are two problems here, that I think belong into different tests:
User cannot access protected page when not logged in. That's a controller test.
User gets logged in automatically even after the session has been destroyed, so long the "remember" me flag was set in the cookie.
For #1, you can try something like:
describe UsersController do
context "when not logged in" do
context "GET users/edit" do
it "redirects to login" do
get :edit, :id => 123
response.should redirect_to login_path
end
end
end
end
You can make a more general test case that asserts all actions which aren't explicitly listed, so that you don't have test gaps if the access code later becomes more permissive by accident. But that's a more subtle point.
For #2 you can write a request spec that sets the "remember me flag", then logs out, then logs in again and checks that you get to the page you expected. Drive all this from the browser by filling out credentials, checking the remember me box, clicking buttons.
The question is: Why? Why do you want to test this? Are you using a home-grown login system? Highly discouraged, unless you're a top-notch security expert. If you're not using a home-grown system, but instead Devise which comes tested, then don't re-test the library functionality. Just only test your application code, such as access rights to certain pages, which is covered by #1. You can also take a look at the tests that come with Devise how they test for this condition.
Hope this helps.
Update To clarify the request spec for #2. As mentioned in the other answer by #cutalion (who deserves the credit for the right answer), the mechanism for verifying that login can persist across session closing is built into the ActionDispatch IntegrationTest framework with open_session.
See Rails docs IntegrationTest API which includes examples. A blog post expanding on the use of a custom DSL.
This still seems to be a recurring problem in 2018. Some basic documentation is clearly missing. I finally found a solution: "Show me the cookies" gem.
Switching the Capybara driver clears the session, so one possibility would be changing the driver in the middle of a test to simulate browser close/open. But getting an alternative driver (for example selenium, or selenium_chrome) to work is not trivial, and besides this method would probably delete all cookies.
Also this simple command resets the session: Capybara.reset_sessions! But the problem again is that it not only destroys the session cookie but also permanent cookies. So it's useless for testing "Remember me" functionality.
I finally settled on Show me the cookies gem. It was very simple to install and implement. I just followed the provided directions for rspec. The command expire_cookies provides a satisfying simulation of quitting and opening a browser.
I am new to BDD and I have this controller that requires a user session how can I test that in RSpec? Thank You!
You could directly set the required key in the session variable which is used for verifying that the user session is set. From the RSpec documentation you can access the session variable using session like in Rails.
Do you use some Authentication Plugin/Gem, such as Devise, Restful_Authentication or Authlogic?
Normally they come with certain TestHelper-Methods, that allow you to do kind of an authentication while testing.
Don't. Integration testing is a job for Cucumber, not RSpec.
First off - I know that this is generally horrible practice, because Cucumber is meant to only test outputs. I just want to do this for one veryveryvery specific case.
I have an app that handles user authentication using a cookie set by another app I maintain. I'd like to write a very simple integration test for authentication:
Given I have logged as "some_user" on the SSO server
When I visit any page
Then I should be logged in as "some_user"
My current step definition for the Then is as follows:
Then /^I should be logged in as "([^"]*)"$/ do |username|
user = User.find_by_username(username)
assert_equal #controller.current_user, user
end
Obviously, this is failing with "Undefined method 'current_user' for nil:NilClass".
In case it's not obvious - ApplicationController#current_user returns either the user currently logged in or nil.
You can visit some page where currently logged on user's name is displayed.
Like:
When I go to the account page
Then I should see "Welcome user" within "div#login"