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.
Related
I have tried a couple of ways like using browser.manage.delete_cookie and also setting cookie to empty by doing something like this : page.driver.browser.manage.set_cookie("#{'cookie_name'}:") but none of them helped.
This is my Step Defn file
Given('I am on Learn Page') do
page.driver.browser.manage.window.resize_to(1800,990)
#tried this to click on the radio button from chrome settings to disable all cookies, but failed
visit "chrome://settings/cookies"
find('.//*[#id="label"]/text()').click
#find('#radioCollapse').click
#failed with this too
visit "https://mylearnwebsite.com/"
browser = Capybara.current_session.driver.browser
browser.manage.delete_cookie 'my_cookie'
#and with this as well
page.driver.browser.manage.set_cookie("{'my_cookie'}:")
end
All of them either says, unable to locate element or Selenium::WebDriver::Error::NoSuchElementError
I am a newbie to Capybara and trying to automate a couple of web application features using the same.It would be a great help if anyone from the group suggest how to proceed here.
You need to be on a page where the cookie would be valid in order to interact with the cookies (WebDriver spec limitation). Assuming that https://mylearnwebsite.com/ is the site where the cookie is valid and you're using the selenium driver then
visit "https://mylearnwebsite.com/"
page.driver.browser.manage.delete_cookie 'my_cookie' # this is driver specific
page.refresh # to reload the page without the cookie
...
would delete the cookie. Since you haven't shown what you're actually checking after removing the cookie it's hard to guess what behavior you're looking to actually test, so the code above is just calling refresh to see the page state without the cookie.
Noe: From a general system/feature testing purpose it's usually not valuable to manually interact with cookies, you're generally better off just testing the user behaviors which have a side-effect of modifying cookies.
I am new to write integration tests in rails. Let's say i have below scenarios,
Admin logs in.
Creates a new user.
Assign new role to user.
So currently for every scenario , it opens a new browser window (or may be resetting the session).
As for login we are using 3rd party oauth it takes huge amount of time for login.
So i do not want to login for each scenario. Once after login it should execute scenarios one by one without asking for login again and again. But i am not sure how to achieve the same using rspec and selenium.
Any help would be greatly appreciated .
Capybara.current_session.instance_variable_set(:#touched, false)
Executing the above after each scenario maintains the session.
Selenium shouldn't be opening a new browser window for each scenario (unless you're specifically closing the tab in an after block), but it should reset it to about:blank. As for the rest of your request, it would be completely bypassing the intention of feature/integration tests where each test should be completely isolated from the other tests. What you should be doing, if you don't want to manually login for each test, is using the test mode of whatever auth library you're using to allow you to shortcut the login.
For instance, if using OmniAuth - see https://github.com/omniauth/omniauth/wiki/Integration-Testing
I'm looking to add 2 factor login to my Silex app.
However, I'm having some road blocks on how to get this working correctly.
my biggest sticking point is having the firewall not fully log the user in and instead direct them to a page to confirm their identity.
I've thought about using Symfony Guard, but looking at the documentation, I didn't see anything that would let me prevent the user from being logged in.
I don't have any code yet, at this point, I'm just tying to design the flow and after I have a concrete execution plan, I was going to then begin writing code.
I remember reading a blog post about doing this in Sf2, but I cannot find it now. Here's the gist:
the login part is the usual one
create a listener for the controller event, and redirect to the 2FA controller unless the user has a role (ROLE_GOOGLE_AUTHENTICATED or similar) and unless the user is requesting that route
on that url render a form and check if it's a post, and if the code verifies add that role to the user
I'm sure you can adapt it for silex. You can also check the bundles that exist for Sf2 on how they work exactly.
I was trying to automate some functional tests using Spock (Grails app) and I'm not able to figure out how to automate the following:
I need to be able to login to one Web app and click on a link (from the web app) and open a new browser window and be logged in to the second app (because they share the user credentials - they use SSO). All the functionalities I need to test are on the second web app and there is NO direct login to that app.
I was wondering if there is a way to use the current browser session (and share the cookie) between web apps.
I would appreciate any ideas.
Answer found
I have managed to find the answers to my query. As mentioned in my comments below, I used withNewWindow() method as follows:
withNewWindow({ AnchorForNewPage.click()}){
assert at(NewPage)
do something
and something else
}
Make sure that actions you perform on the second page are all within this closure, otherwise the tests will fail.
Let me quote The Book of Geb:
The geb.spock.GebSpec class will clear the cookies in the cleanup()
method unless the spec is #Stepwise, in which case they are cleared in
cleanupSpec() (meaning that all feature methods in a stepwise spec
share the same browser state).
Not sure will it do for SSO and session sharing between two web-apps, but you may give it a try. Just keep the test steps requiring shared session as fixture methods in single Specification class.
I'd like to have a Cucumber feature testing the rememberable functionality of devise (a remember me cookie).
It is easy to check the remember me check box using capybara but how should I simulate a user returning to the site after closing their window?
I came up with the following rack-test hack, and slightly cleaner selenium api use, to test Devise remember-me functionality in cucumber/capybara. It just tells the driver to manually erase the session cookie. Not all drivers are supported, I only implemented the two I've used:
http://gist.github.com/484787
This assumes cookie storage of the session. Remove #announce tag from the scenario to get rid of the verbosity.
Another option, suggested by Matt Wynne in the mailing list discussion, may be looking at other cookie stores, and deleting them by query or file deletion:
lifted from agile rails book:
config.action_controller.session_store = CGI::Session::PStore (or just :p_store)
config.action_controller.session_options[:tmpdir] = "/Users/dave/tmp"
config.action_controller.session_options[:prefix] = "myapp_session_"
or
rake db:sessions:create
config.action_controller.session_store = :active_record_store
Rails also has a reset session method, but I believe we don't have access to this because we can't hook into the rails session when testing with capybara.
Hope this helps,
Nick
nruth's gist was really helpful but I felt like deleting the cookie by name was cheating. I created a step that deletes the cookies a browser would delete when it was closed and restarted (any cookie without an expiry date set and set in the future).
You can see it in this commit (though I've only done it for the RackTest driver as I don't have Selenium setup). You can also see my login/remember_me feature in this commit. And I refactored the classes to separate files in this commit.
I hope that's helpful.
I used email-spec to accomplish this. My Scenario looks like the following:
#allow-rescue
Scenario: Create New Account (Everything cool)
Given I am not authenticated
When I go to register
And I fill in "Name" with "bill"
And I fill in "Email" with "bill#example.com"
And I fill in "Password" with "please"
And I fill in "Password Confirmation" with "please"
And I press "Sign up"
Then "bill#example.com" should receive an email
And I open the email
And I should see "Confirm my account" in the email body
When I follow "Confirm my account" in the email
Then I should see "Your account was successfully confirmed. You are now signed in."
Note the #allow-rescue decoration above the scenario that is necessary when using Devise.
Hope this helps.
I guess you could log out with capybara, and then log back in something like
Given I am on the login screen
And I select 'Remember Me'
And I click 'login'
Then I should be 'logged in'
When I click 'log out'
Then I should be 'logged out' #=> potentially destroy a session here?
When I click log in
Then I should be logged in
And I should not be directed to the login form.
This should use cabybara's current cookie state to model this flow.
You can use show_me_the_cookies for this as shown below:
And(/^I leave the site$/) do
expire_cookies
end