Hello,
I’d like to integrate some tests in a Tryton Flask application, using flask_tryton
.
I can’t quite find how to manage having a “test” transaction and the “route” transaction… since the route transaction asserts on None
values… Has someone integrated any test like this or could give any pointers? Thank you
❯ python -m unittest discover -s tests
/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/passlib/utils/__init__.py:854: DeprecationWarning: 'crypt' is deprecated and slated for removal in Python 3.13
from crypt import crypt as _crypt
<frozen importlib._bootstrap>:1049: ImportWarning: PluginImportFixer.find_spec() not found; falling back to find_module()
<frozen importlib._bootstrap>:283: DeprecationWarning: the load_module() method is deprecated and slated for removal in Python 3.12; use exec_module() instead
.F........................
======================================================================
FAIL: test_login (test_application.B2BApplicationTestCase.test_login)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/trytond/tests/test_tryton.py", line 209, in wrapper
result = func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/Developer/ack-eus/tryton/applications/b2b/tests/test_application.py", line 92, in test_login
response = self.client.post('/login', data={
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/werkzeug/test.py", line 1145, in post
return self.open(*args, **kw)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/testing.py", line 223, in open
response = super().open(
^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/werkzeug/test.py", line 1094, in open
response = self.run_wsgi_app(request.environ, buffered=buffered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/werkzeug/test.py", line 961, in run_wsgi_app
rv = run_wsgi_app(self.application, environ, buffered=buffered)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/werkzeug/test.py", line 1242, in run_wsgi_app
app_rv = app(environ, start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 2548, in __call__
return self.wsgi_app(environ, start_response)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 2528, in wsgi_app
response = self.handle_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 2525, in wsgi_app
response = self.full_dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 1822, in full_dispatch_request
rv = self.handle_user_exception(e)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 1820, in full_dispatch_request
rv = self.dispatch_request()
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask/app.py", line 1796, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask_tryton.py", line 37, in wrapper
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/flask_tryton.py", line 196, in wrapper
with Transaction().start(database, transaction_user,
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/hodeinavarro/.local/share/ack-eus/environments/zafra/lib/python3.11/site-packages/trytond/transaction.py", line 112, in start
assert self.user is None
^^^^^^^^^^^^^^^^^
AssertionError
----------------------------------------------------------------------
Ran 26 tests in 77.532s
FAILED (failures=1)
b2b/application/__init__.py
from flask import Flask
def create_app(config=None):
app = Flask(__name__)
if config is not None:
app.config.from_pyfile(config)
from .tryton import tryton
tryton.init_app(app)
from .views import view
app.register_blueprint(view)
return app
b2b/application/views.py
from functools import wraps
from flask import Blueprint, redirect, render_template, request, url_for
from werkzeug.wrappers import Response as BaseResponse
from .tryton import tryton
view = Blueprint('view', __name__, 'static', '/', 'templates')
def protected(f):
@wraps(f)
def wrapper(*args, **kwargs):
LOGIN_RESPONSE = redirect(url_for('view.login', r=request.path))
key = request.cookies.get('session')
if key is None:
return LOGIN_RESPONSE
return validate_session(key, f(*args, **kwargs), LOGIN_RESPONSE)
return wrapper
@tryton.transaction()
def validate_session(key: str, success_response: BaseResponse,
LOGIN_RESPONSE: BaseResponse) -> BaseResponse:
WebUserSession = tryton.pool.get('web.user.session')
user = WebUserSession.get_user(key)
if user is None:
response = LOGIN_RESPONSE
response.delete_cookie('session')
return response
return success_response
def authenticate(username: str, password: str) -> BaseResponse:
WebUser = tryton.pool.get('web.user')
WebUserSession = tryton.pool.get('web.user.session')
user = WebUser.authenticate(username, password)
if not user:
# TODO: Add flash message
return redirect(url_for('view.login', r=request.args.get('r')))
session = user.new_session()
response = redirect(request.args.get('r') or url_for('view.index'))
response.set_cookie('session', session, max_age=WebUserSession.timeout())
return response
@view.route('/login', methods={'GET', 'POST'})
@tryton.transaction()
def login():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
if username and password:
return authenticate(username, password)
else:
# TODO: Add flash message
return redirect(url_for('view.login', r=request.args.get('r')))
return render_template('login.html')
@view.route('/')
@protected
def index():
return 'Hello, World!'
b2b/application/config.test.py
from application.config import get_secret_key, get_tryton_database
TESTING = True
SECRET_KEY = get_secret_key()
TRYTON_DATABASE = get_tryton_database()
b2b/tests/test_application.py
import unittest
from application import create_app
from trytond.config import config
from trytond.pool import Pool
from trytond.tests.test_tryton import (activate_module, drop_db,
with_transaction)
class B2BApplicationTestCase(unittest.TestCase):
"Test B2B application"
module = 'b2b'
extras = []
language = 'es'
@classmethod
def setUpClass(cls):
drop_db()
modules = [cls.module]
if cls.extras:
modules.extend(cls.extras)
activate_module(modules, lang=cls.language)
super().setUpClass()
def setUp(self):
self.app = create_app('config.test.py')
self.client = self.app.test_client()
@classmethod
def tearDownClass(cls):
super().tearDownClass()
drop_db()
@with_transaction()
def test_login(self):
user = 'test'
password = 'test'.zfill(int(config.get('password', 'length')))
pool = Pool()
WebUser = pool.get('web.user')
WebUser.create([{
'email': user,
'password': password
}])
response = self.client.post('/login', data={
'username': user,
'password': password
})
self.assertEqual(response.status_code, 302)
self.assertEqual(response.location, '/')