lingthio / Flask-User

Customizable User Authorization & User Management: Register, Confirm, Login, Change username/password, Forgot password and more.
http://flask-user.readthedocs.io/
MIT License
1.06k stars 292 forks source link

pytest a roles_required route fails #337

Closed schoolsplay closed 2 years ago

schoolsplay commented 2 years ago

As app I use the quick_start_app from the flask_user 1.0 documentation and am using a python 3.6 virtual environment on Linux. I have started the app and used the browser to register a user with username: flask and password Flask2021 The app works perfectly when using a browser. But I can't find a way to pytest the sign-in.

I create a pytest, test_quick_start_app.py, like this:

from quick_start_app import create_app
app = create_app()

@pytest.fixture(scope='module')
def client():
    with app.test_client() as client:
        with app.app_context():
            yield client

def login(client, username, password):
    return client.post('/user/sign-in',
                       data=dict(username=username, password=password),
                       follow_redirects=True)

def test_get_admin_login_logout(client):
    user = 'flask'
    password = 'Flask2021'
    rv = login(client, user, password)
    assert b'You have signed in successfully' in rv.data , f"Expected login but got: {rv.data}"

But whenever I try to run the test, python3 test_quick_start_app.py, I get an TypeError.

test_quick_start_app.py F                                                                                                        [100%]

=============================================================== FAILURES ===============================================================
_____________________________________________________ test_get_admin_login_logout ______________________________________________________

client = <FlaskClient <Flask 'quick_start_app'>>

    def test_get_admin_login_logout(client):
        user = b'flask'
        password = b'Flask2021'
>       rv = login(client, user, password)

test_quick_start_app.py:31: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
test_quick_start_app.py:25: in login
    follow_redirects=True)
../.venv3.6/lib/python3.6/site-packages/werkzeug/test.py:1134: in post
    return self.open(*args, **kw)
../.venv3.6/lib/python3.6/site-packages/flask/testing.py:220: in open
    follow_redirects=follow_redirects,
../.venv3.6/lib/python3.6/site-packages/werkzeug/test.py:1074: in open
    response = self.run_wsgi_app(request.environ, buffered=buffered)
../.venv3.6/lib/python3.6/site-packages/werkzeug/test.py:945: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
../.venv3.6/lib/python3.6/site-packages/werkzeug/test.py:1231: in run_wsgi_app
    app_rv = app(environ, start_response)
../.venv3.6/lib/python3.6/site-packages/flask/app.py:2091: in __call__
    return self.wsgi_app(environ, start_response)
../.venv3.6/lib/python3.6/site-packages/flask/app.py:2076: in wsgi_app
    response = self.handle_exception(e)
../.venv3.6/lib/python3.6/site-packages/flask/app.py:2073: in wsgi_app
    response = self.full_dispatch_request()
../.venv3.6/lib/python3.6/site-packages/flask/app.py:1518: in full_dispatch_request
    rv = self.handle_user_exception(e)
../.venv3.6/lib/python3.6/site-packages/flask/app.py:1516: in full_dispatch_request
    rv = self.dispatch_request()
../.venv3.6/lib/python3.6/site-packages/flask/app.py:1502: in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**req.view_args)
../.venv3.6/lib/python3.6/site-packages/flask_user/user_manager.py:416: in login_stub
    return self.login_view()
../.venv3.6/lib/python3.6/site-packages/flask_user/user_manager__views.py:397: in login_view
    return self._do_login_user(user, safe_next_url, login_form.remember_me.data)
../.venv3.6/lib/python3.6/site-packages/flask_user/user_manager__views.py:694: in _do_login_user
    return redirect(safe_next_url)
../.venv3.6/lib/python3.6/site-packages/werkzeug/utils.py:554: in redirect
    display_location = html.escape(location)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

s = b'', quote = True

    def escape(s, quote=True):
        """
        Replace special characters "&", "<" and ">" to HTML-safe sequences.
        If the optional flag quote is true (the default), the quotation mark
        characters, both double quote (") and single quote (') characters are also
        translated.
        """
>       s = s.replace("&", "&amp;") # Must be done first!
E       TypeError: a bytes-like object is required, not 'str'

/usr/lib/python3.6/html/__init__.py:19: TypeError
--------------------------------------------------------- Captured stdout call ---------------------------------------------------------
[2021-12-28 13:13:38,765] DEBUG in bcrypt- line 625: detected 'bcrypt' backend, version '3.2.0'
[2021-12-28 13:13:38,766] DEBUG in bcrypt- line 406: 'bcrypt' backend lacks $2$ support, enabling workaround
---------------------------------------------------------- Captured log call -----------------------------------------------------------
DEBUG    passlib.handlers.bcrypt:bcrypt.py:625 detected 'bcrypt' backend, version '3.2.0'
DEBUG    passlib.handlers.bcrypt:bcrypt.py:406 'bcrypt' backend lacks $2$ support, enabling workaround
======================================================= short test summary info ========================================================
FAILED test_quick_start_app.py::test_get_admin_login_logout - TypeError: a bytes-like object is required, not 'str'

I can't find what's causing the error, or how to properly test routes that use the flask_user decorators

schoolsplay commented 2 years ago

After I create a basic app myself with a roles_required route that gets redirected to the flask_user login the test does work. The quick start app isn't suitable for pytest testing I assume