Reputation: 18477
I am building a Flask-backed web app where all the interesting pages are behind a login. I would like to run automated tests against it using the Selenium WebDriver. I cannot seem to figure out how to log in a user and associate it with Selenium. Everything I try results in Selenium being presented with the "Please log in" page.
Many of the resources I have seen (1, 2, 3, among many others) suggest manually logging in with a scripted test, which is to say navigating Selenium to the log in page, filling out forms, and clicking buttons. This is a terrible solution for many reasons including but not limited to:
Something else I could do is open the browser I'm targeting myself before running the Selenium tests and log in. This keeps the credentials out of Selenium's hands. Problems:
Using something like this:
with client.session_transaction() as session:
session['user_id'] = test_user.id
session['_fresh'] = True
where client is an instance of app.test_client()
. (This is in a pytest fixture; I'm using Flask_login). This allows me to log in during regular unit tests, but I have not been able to figure out how I could get Selenium to use this same session.
Similar to the above I can try calling Flask_login.login_user(test_user)
in a fixture, but I have not successfully been able to associate Selenium with this user. Since the session already failed, the only thing I could think would be to set a cookie for this logged in user on Selenium driver.set_cookie
, but I have no idea how to get a proper one out of the test client or Flask login to do so.
According to the Flask-Login docs you can set LOGIN_DISABLED
in your app config to bypass the login_required
decorator. I did this but I'm still seeing a login page.
I dug into this a bit more and the issue is not that LOGIN_DISABLED isn't working but that a lot of views depend on the behavior of Flask_login's current_user.is_anonymous
. If I were going to go this route I'd also need a solution to make sure that current_user
is set to the test user, so that actions in the app are correctly grouped with the user that's "logged in".
How do I authenticate once without using Selenium and then get Selenium to use that authenticated user for the rest of its session?
Upvotes: 3
Views: 2486
Reputation: 2505
You can create an AuthenticatedUser and make it the current_user
before the tests.
In my case I use flask-security with Roles so I also create and embed a specific Role and call hooks so it integrates with flask-principal and overrides the user-lookup that occurs in flask-security.
Since you are seemingly not using these extra libraries I will try to recraft it to your case. When you want to disable login you would call what I have named force_authenticated(app)
before your first request occurs. (It will error if called after requests have already occurred.)
# This is a non-anonymous, authenticated user
class AuthenticatedUser(flask_login.UserMixin):
def get_id(self):
return 'TestUser'
def force_authenticated(app):
@app.before_request
def set_identity():
user = AuthenticatedUser()
flask_login.login_user(user)
Here is a full, really minimal, confirmed-working example:
from flask import Flask
import flask_login
class AuthenticatedUser(flask_login.UserMixin):
def get_id(self):
return 'TestUser'
def force_authenticated(app):
@app.before_request
def set_identity():
user = AuthenticatedUser()
flask_login.login_user(user)
app = Flask(__name__)
app.secret_key = 'blahblah'
lm = flask_login.LoginManager(app)
lm.init_app(app)
force_authenticated(app)
@app.route('/')
@flask_login.login_required
def hello_world():
return 'Hello, World!'
app.run()
Upvotes: 1
Reputation: 12875
How to get cookies after login. One can simulate login process, find you form take action
attribute from it and names of fields for username and password. Look what cookie is used for storing session key, suppose it is sid
.
get_cookie.py:
import requests
r = requests.post(action,
data={'login': 'your_username', 'password': 'You_p@ssw0rd'},
allow_redirects=False)
# now r.cookies contains all returned cookies,
# print cookie you need:
print(r.cookie['sid'])
Try to do it in a webdriver session initialisation. Or you may run it and feed this cookie to Selenium, for example as a command line parameter (just use your correct parameters):
selenium .... --session=$(./get_cookie.py)
Upvotes: 2
Reputation: 222
Cam you please read following link ?
In this, login is done using selenium and cookie is stored in a file for the later use. And after that you can use requests with the saved cookie to access other pages.
Upvotes: 1
Reputation: 1
We have a form just like what you are using flask. What we have done is create a default configuration file in the GIT project. Then I pulled this down to my box and created my own configuration file from this default and put my credentials in this file. It seems to work fine for us. I run all my tests from Eclipse using pydev. I recently started using the HTMLTestRunner
to get a better picture of results. I hope this helps you out.
Upvotes: 0