You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
With FlaskClient, we can do something like client.post('/login') to login a user during testing. When using CSRF tokens, it's a bit more complicated and we have do do something like what flask-security does:
I know we can disable CSRF but sometimes that's counter productive. Also, the overhead of two full WSGI requests, while small, can add up in an application with a lot of view tests.
So, instead of running full WSGI requests, I want to just call the same code the libraries would call inside a request:
# CSRF token for form datatoken=flask_wtf.csrf.generate_csrf()
self.post(url,data=data| {'csrf_token': token})
# Or, to login a user entity/modelflask_security.login_user(user)
The obvious "challenge" here is that both functions need to be called inside a request context. But if you just do:
That request is detached from the Client instance so doesn't help you with future requests made from the client.
I initially tried to use Client's session helpers, but that failed for both CSRF and user login because both need a full request context present for it to work.
I ended up writing a modification of session_transaction() that yields the session while inside the request context. You can see how it's used to login a user and/or send form data with the correct CSRF token:
classClient(flask.testing.FlaskClient):
@contextmanagerdefrequest_context(self, *args, **kwargs):
""" Similar to parent's session_transaction() but yields inside the request context so code can be ran is if it was in a view. """ifself._cookiesisNone:
raiseTypeError('Cookies are disabled. use_cookies=True required')
ctx=self.application.test_request_context(*args, **kwargs)
self._add_cookies_to_wsgi(ctx.request.environ)
withctx:
yieldflask.sessionresp=self.application.response_class()
self.application.session_interface.save_session(
self.application,
flask.session,
resp,
)
# finally, update the client's cookie_jarself._update_cookies_from_response(
ctx.request.host.partition(':')[0],
ctx.request.path,
resp.headers.getlist('Set-Cookie'),
)
deflogin(self, user):
withself.request_context():
login_user(user, remember=False)
set_request_attr('fs_authn_via', 'session')
set_request_attr('fs_paa', session.get('fs_paa', 0))
defform_post(
self,
url: str,
data: dict|None=None,
follow_redirects=False,
expect: int|None=None,
headers: dict|None=None,
redirect_ok: bool=True,
**kwargs,
):
data= (dataor {}) |kwargswithself.request_context():
token=generate_csrf()
returnself.post(
url,
data=data| {'csrf_token': token},
follow_redirects=follow_redirects,
expect=expect,
headers=headers,
redirect_ok=redirect_ok,
)
Now that I have it all figured out, it seems somewhat obvious that this would be useful. Is there a reason the Client doesn't have a method like this? Is there something non-obvious behind the scenes that would make this a bad idea?
If not, does it make sense to add one? If yes, what's it's relationship to session_transaction() which is almost a duplicate?
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
With
FlaskClient
, we can do something likeclient.post('/login')
to login a user during testing. When using CSRF tokens, it's a bit more complicated and we have do do something like what flask-security does:I know we can disable CSRF but sometimes that's counter productive. Also, the overhead of two full WSGI requests, while small, can add up in an application with a lot of view tests.
So, instead of running full WSGI requests, I want to just call the same code the libraries would call inside a request:
The obvious "challenge" here is that both functions need to be called inside a request context. But if you just do:
That request is detached from the Client instance so doesn't help you with future requests made from the client.
I initially tried to use Client's session helpers, but that failed for both CSRF and user login because both need a full request context present for it to work.
I ended up writing a modification of
session_transaction()
that yields the session while inside the request context. You can see how it's used to login a user and/or send form data with the correct CSRF token:Now that I have it all figured out, it seems somewhat obvious that this would be useful. Is there a reason the Client doesn't have a method like this? Is there something non-obvious behind the scenes that would make this a bad idea?
If not, does it make sense to add one? If yes, what's it's relationship to
session_transaction()
which is almost a duplicate?Beta Was this translation helpful? Give feedback.
All reactions