diff --git a/tests/conftest.py b/tests/conftest.py
index 62e5f25..1707b1d 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -23,7 +23,7 @@ from utils import populate_data, Response
@pytest.fixture()
-def app():
+def app(request):
app = Flask(__name__)
app.response_class = Response
app.debug = True
@@ -32,6 +32,14 @@ def app():
app.config['LOGIN_DISABLED'] = False
app.config['WTF_CSRF_ENABLED'] = False
+ for opt in ['changeable', 'recoverable', 'registerable',
+ 'trackable', 'passwordless', 'confirmable']:
+ app.config['SECURITY_' + opt.upper()] = opt in request.keywords
+
+ if 'settings' in request.keywords:
+ for key, value in request.keywords['settings'].kwargs.items():
+ app.config['SECURITY_' + key.upper()] = value
+
mail = Mail(app)
app.mail = mail
diff --git a/tests/test_changeable.py b/tests/test_changeable.py
index 66e9cba..e63d2b2 100644
--- a/tests/test_changeable.py
+++ b/tests/test_changeable.py
@@ -6,23 +6,16 @@
Changeable tests
"""
+import pytest
+
from flask_security.signals import password_changed
-from utils import authenticate, init_app_with_options
+from utils import authenticate
+
+pytestmark = pytest.mark.changeable()
-def _get_client(app, datastore, **options):
- config = {
- 'SECURITY_CHANGEABLE': True
- }
- config.update(options)
- init_app_with_options(app, datastore, **config)
- return app.test_client()
-
-
-def test_recoverable_flag(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore)
-
+def test_recoverable_flag(app, client, get_message):
recorded = []
@password_changed.connect_via(app)
@@ -97,32 +90,22 @@ def test_recoverable_flag(app, sqlalchemy_datastore, get_message):
assert response.headers['Content-Type'] == 'application/json'
-def test_custom_change_url(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_CHANGE_URL': '/custom_change'
- })
-
+@pytest.mark.settings(change_url='/custom_change')
+def test_custom_change_url(client):
authenticate(client)
response = client.get('/custom_change')
assert response.status_code == 200
-def test_custom_change_template(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_CHANGE_PASSWORD_TEMPLATE': 'custom_security/change_password.html'
- })
-
+@pytest.mark.settings(change_password_template='custom_security/change_password.html')
+def test_custom_change_template(client):
authenticate(client)
response = client.get('/change')
assert b'CUSTOM CHANGE PASSWORD' in response.data
-def test_disable_change_emails(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_SEND_PASSWORD_CHANGE_EMAIL': False
- })
- authenticate(client)
-
+@pytest.mark.settings(send_password_change_email=False)
+def test_disable_change_emails(app, client):
with app.mail.record_messages() as outbox:
client.post('/change', data={
'password': 'password',
@@ -132,12 +115,9 @@ def test_disable_change_emails(app, sqlalchemy_datastore):
assert len(outbox) == 0
-def test_custom_post_change_view(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_POST_CHANGE_VIEW': '/profile',
- })
+@pytest.mark.settings(post_change_view='/profile')
+def test_custom_post_change_view(client):
authenticate(client)
-
response = client.post('/change', data={
'password': 'password',
'new_password': 'newpassword',
diff --git a/tests/test_common.py b/tests/test_common.py
index 2aebee3..7eeb298 100644
--- a/tests/test_common.py
+++ b/tests/test_common.py
@@ -40,8 +40,8 @@ def test_authenticate_with_invalid_next(client, get_message):
assert get_message('INVALID_REDIRECT') in response.data
-def test_authenticate_case_insensitive_email(client):
- response = authenticate(client, email='MATT@lp.com', follow_redirects=True)
+def test_authenticate_case_insensitive_email(app, client):
+ response = authenticate(client, 'MATT@lp.com', follow_redirects=True)
assert b'Hello matt@lp.com' in response.data
diff --git a/tests/test_configuration.py b/tests/test_configuration.py
index 69e6fd8..9a75ae0 100644
--- a/tests/test_configuration.py
+++ b/tests/test_configuration.py
@@ -8,20 +8,18 @@
import base64
-from utils import authenticate, logout, init_app_with_options
+import pytest
+
+from utils import authenticate, logout
-def test_view_configuration(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_LOGOUT_URL': '/custom_logout',
- 'SECURITY_LOGIN_URL': '/custom_login',
- 'SECURITY_POST_LOGIN_VIEW': '/post_login',
- 'SECURITY_POST_LOGOUT_VIEW': '/post_logout',
- 'SECURITY_DEFAULT_HTTP_AUTH_REALM': 'Custom Realm',
- })
-
- client = app.test_client()
-
+@pytest.mark.settings(
+ logout_url='/custom_logout',
+ login_url='/custom_login',
+ post_login_view='/post_login',
+ post_logout_view='/post_logout',
+ default_http_auth_realm='Custom Realm')
+def test_view_configuration(client):
response = client.get('/custom_login')
assert b"
Login
" in response.data
@@ -39,10 +37,7 @@ def test_view_configuration(app, sqlalchemy_datastore):
assert 'Basic realm="Custom Realm"' == response.headers['WWW-Authenticate']
-def test_template_configuration(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_LOGIN_USER_TEMPLATE': 'custom_security/login_user.html',
- })
- client = app.test_client()
+@pytest.mark.settings(login_user_template='custom_security/login_user.html')
+def test_template_configuration(client):
response = client.get('/login')
assert b'CUSTOM LOGIN USER' in response.data
diff --git a/tests/test_confirmable.py b/tests/test_confirmable.py
index 32fd3e1..f1c0b9e 100644
--- a/tests/test_confirmable.py
+++ b/tests/test_confirmable.py
@@ -8,20 +8,18 @@
import time
+import pytest
+
from flask_security.signals import user_confirmed, confirm_instructions_sent
from flask_security.utils import capture_registrations
-from utils import authenticate, logout, init_app_with_options
+from utils import authenticate, logout
+
+pytestmark = pytest.mark.confirmable()
-def test_confirmable_flag(app, sqlalchemy_datastore, get_message):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_CONFIRMABLE': True,
- 'SECURITY_REGISTERABLE': True,
- })
-
- client = app.test_client()
-
+@pytest.mark.registerable()
+def test_confirmable_flag(app, client, sqlalchemy_datastore, get_message):
recorded_confirms = []
recorded_instructions_sent = []
@@ -100,16 +98,9 @@ def test_confirmable_flag(app, sqlalchemy_datastore, get_message):
assert get_message('INVALID_CONFIRMATION_TOKEN') in response.data
-def test_expired_confirmation_token(app, sqlalchemy_datastore, get_message):
- within = '1 milliseconds'
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_CONFIRMABLE': True,
- 'SECURITY_REGISTERABLE': True,
- 'SECURITY_CONFIRM_EMAIL_WITHIN': within
- })
-
- client = app.test_client()
-
+@pytest.mark.registerable()
+@pytest.mark.settings(confirm_email_within='1 milliseconds')
+def test_expired_confirmation_token(client, get_message):
with capture_registrations() as registrations:
data = dict(email='mary@lp.com', password='password')
client.post('/register', data=data, follow_redirects=True)
@@ -120,32 +111,21 @@ def test_expired_confirmation_token(app, sqlalchemy_datastore, get_message):
time.sleep(1)
response = client.get('/confirm/' + token, follow_redirects=True)
- assert get_message('CONFIRMATION_EXPIRED', within=within, email=user.email) in response.data
+ msg = get_message('CONFIRMATION_EXPIRED', within='1 milliseconds', email=user.email)
+ assert msg in response.data
-def test_login_when_unconfirmed(app, sqlalchemy_datastore, get_message):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_CONFIRMABLE': True,
- 'SECURITY_REGISTERABLE': True,
- 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True
- })
-
- client = app.test_client()
-
+@pytest.mark.registerable()
+@pytest.mark.settings(login_without_confirmation=True)
+def test_login_when_unconfirmed(client, get_message):
data = dict(email='mary@lp.com', password='password')
response = client.post('/register', data=data, follow_redirects=True)
assert b'mary@lp.com' in response.data
-def test_confirmation_different_user_when_logged_in(app, sqlalchemy_datastore, get_message):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_CONFIRMABLE': True,
- 'SECURITY_REGISTERABLE': True,
- 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True
- })
-
- client = app.test_client()
-
+@pytest.mark.registerable()
+@pytest.mark.settings(login_without_confirmation=True)
+def test_confirmation_different_user_when_logged_in(client, get_message):
e1 = 'dude@lp.com'
e2 = 'lady@lp.com'
diff --git a/tests/test_context_processors.py b/tests/test_context_processors.py
index cf4cd91..dd8de0f 100644
--- a/tests/test_context_processors.py
+++ b/tests/test_context_processors.py
@@ -6,26 +6,24 @@
Context processor tests
"""
-from utils import authenticate, init_app_with_options
+import pytest
+
+from utils import authenticate
-def test_context_processors(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_RECOVERABLE': True,
- 'SECURITY_REGISTERABLE': True,
- 'SECURITY_CONFIRMABLE': True,
- 'SECURITY_CHANGEABLE': True,
- 'SECURITY_LOGIN_WITHOUT_CONFIRMATION': True,
- 'SECURITY_CHANGE_PASSWORD_TEMPLATE': 'custom_security/change_password.html',
- 'SECURITY_LOGIN_USER_TEMPLATE': 'custom_security/login_user.html',
- 'SECURITY_RESET_PASSWORD_TEMPLATE': 'custom_security/reset_password.html',
- 'SECURITY_FORGOT_PASSWORD_TEMPLATE': 'custom_security/forgot_password.html',
- 'SECURITY_SEND_CONFIRMATION_TEMPLATE': 'custom_security/send_confirmation.html',
- 'SECURITY_REGISTER_USER_TEMPLATE': 'custom_security/register_user.html'
- })
-
- client = app.test_client()
-
+@pytest.mark.recoverable()
+@pytest.mark.registerable()
+@pytest.mark.confirmable()
+@pytest.mark.changeable()
+@pytest.mark.settings(
+ login_without_confirmation=True,
+ change_password_template='custom_security/change_password.html',
+ login_user_template='custom_security/login_user.html',
+ reset_password_template='custom_security/reset_password.html',
+ forgot_password_template='custom_security/forgot_password.html',
+ send_confirmation_template='custom_security/send_confirmation.html',
+ register_user_template='custom_security/register_user.html')
+def test_context_processors(client, app):
@app.security.forgot_password_context_processor
def forgot_password():
return {'foo': 'bar'}
@@ -77,17 +75,12 @@ def test_context_processors(app, sqlalchemy_datastore):
client.post('/reset', data=dict(email='matt@lp.com'))
email = outbox[0]
- assert b'bar' in email.html
+ assert 'bar' in email.html
-def test_passwordless_login_context_processor(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_PASSWORDLESS': True,
- 'SECURITY_SEND_LOGIN_TEMPLATE': 'custom_security/send_login.html',
- })
-
- client = app.test_client()
-
+@pytest.mark.passwordless()
+@pytest.mark.settings(send_login_template='custom_security/send_login.html')
+def test_passwordless_login_context_processor(app, client):
@app.security.send_login_context_processor
def send_login():
return {'foo': 'bar'}
diff --git a/tests/test_datastore.py b/tests/test_datastore.py
index d75ab49..85e2ae9 100644
--- a/tests/test_datastore.py
+++ b/tests/test_datastore.py
@@ -133,8 +133,11 @@ def test_add_role_to_user(app, datastore):
def test_create_user_with_roles(app, datastore):
init_app_with_options(app, datastore)
+ role = datastore.find_role('admin')
+ datastore.commit()
+
user = datastore.create_user(email='dude@lp.com', username='dude',
- password='password', roles=['admin'])
+ password='password', roles=[role])
datastore.commit()
user = datastore.find_user(email='dude@lp.com')
assert user.has_role('admin') is True
diff --git a/tests/test_misc.py b/tests/test_misc.py
index 8649c36..8be2a7d 100644
--- a/tests/test_misc.py
+++ b/tests/test_misc.py
@@ -6,7 +6,7 @@
Email functionality tests
"""
-from pytest import raises
+import pytest
from flask_security import Security
from flask_security.forms import LoginForm, RegisterForm, ConfirmRegisterForm, \
@@ -17,18 +17,14 @@ from flask_security.utils import capture_reset_password_requests
from utils import authenticate, init_app_with_options, populate_data
-def test_async_email_task(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_RECOVERABLE': True
- })
-
+@pytest.mark.recoverable()
+def test_async_email_task(app, client):
app.mail_sent = False
@app.security.send_mail_task
def send_email(msg):
app.mail_sent = True
- client = app.test_client()
client.post('/reset', data=dict(email='matt@lp.com'))
assert app.mail_sent is True
@@ -40,11 +36,10 @@ def test_register_blueprint_flag(app, sqlalchemy_datastore):
assert response.status_code == 404
+@pytest.mark.registerable()
+@pytest.mark.recoverable()
+@pytest.mark.changeable()
def test_basic_custom_forms(app, sqlalchemy_datastore):
- app.config['SECURITY_REGISTERABLE'] = True
- app.config['SECURITY_RECOVERABLE'] = True
- app.config['SECURITY_CHANGEABLE'] = True
-
class MyLoginForm(LoginForm):
email = TextField('My Login Email Address Field')
@@ -70,7 +65,6 @@ def test_basic_custom_forms(app, sqlalchemy_datastore):
change_password_form=MyChangePasswordForm)
populate_data(app)
-
client = app.test_client()
response = client.get('/login')
@@ -95,6 +89,8 @@ def test_basic_custom_forms(app, sqlalchemy_datastore):
assert b'My Change Password Field' in response.data
+@pytest.mark.registerable()
+@pytest.mark.confirmable()
def test_confirmable_custom_form(app, sqlalchemy_datastore):
app.config['SECURITY_REGISTERABLE'] = True
app.config['SECURITY_CONFIRMABLE'] = True
@@ -154,7 +150,7 @@ def test_flash_messages_off(app, sqlalchemy_datastore, get_message):
def test_invalid_hash_scheme(app, sqlalchemy_datastore, get_message):
- with raises(ValueError):
+ with pytest.raises(ValueError):
init_app_with_options(app, sqlalchemy_datastore, **{
'SECURITY_PASSWORD_HASH': 'bogus'
})
diff --git a/tests/test_passwordless.py b/tests/test_passwordless.py
index 7cf964a..eddf479 100644
--- a/tests/test_passwordless.py
+++ b/tests/test_passwordless.py
@@ -8,19 +8,17 @@
import time
+import pytest
+
from flask_security.signals import login_instructions_sent
from flask_security.utils import capture_passwordless_login_requests
-from utils import logout, init_app_with_options
+from utils import logout
+
+pytestmark = pytest.mark.passwordless()
-def test_trackable_flag(app, sqlalchemy_datastore, get_message):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_PASSWORDLESS': True
- })
-
- client = app.test_client()
-
+def test_trackable_flag(app, client, get_message):
recorded = []
@login_instructions_sent.connect_via(app)
@@ -75,14 +73,8 @@ def test_trackable_flag(app, sqlalchemy_datastore, get_message):
assert get_message('USER_DOES_NOT_EXIST') in response.data
-def test_expired_login_token(app, sqlalchemy_datastore, get_message):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_PASSWORDLESS': True,
- 'SECURITY_LOGIN_WITHIN': '1 milliseconds',
- })
-
- client = app.test_client()
-
+@pytest.mark.settings(login_within='1 milliseconds')
+def test_expired_login_token(client, app, get_message):
e = 'matt@lp.com'
with capture_passwordless_login_requests() as requests:
diff --git a/tests/test_recoverable.py b/tests/test_recoverable.py
index 94f0950..ade31a0 100644
--- a/tests/test_recoverable.py
+++ b/tests/test_recoverable.py
@@ -8,24 +8,17 @@
import time
+import pytest
+
from flask_security.signals import reset_password_instructions_sent, password_reset
from flask_security.utils import capture_reset_password_requests
-from utils import authenticate, logout, init_app_with_options
+from utils import authenticate, logout
+
+pytestmark = pytest.mark.recoverable()
-def _get_client(app, datastore, **options):
- config = {
- 'SECURITY_RECOVERABLE': True
- }
- config.update(options)
- init_app_with_options(app, datastore, **config)
- return app.test_client()
-
-
-def test_recoverable_flag(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore)
-
+def test_recoverable_flag(app, client, get_message):
recorded_resets = []
recorded_instructions_sent = []
@@ -105,12 +98,8 @@ def test_recoverable_flag(app, sqlalchemy_datastore, get_message):
assert get_message('INVALID_RESET_PASSWORD_TOKEN') in response.data
-def test_expired_reset_token(app, sqlalchemy_datastore, get_message):
- within = '1 milliseconds'
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_RESET_PASSWORD_WITHIN': within
- })
-
+@pytest.mark.settings(reset_password_within='1 milliseconds')
+def test_expired_reset_token(client, get_message):
with capture_reset_password_requests() as requests:
client.post('/reset', data=dict(email='joe@lp.com'), follow_redirects=True)
@@ -124,24 +113,19 @@ def test_expired_reset_token(app, sqlalchemy_datastore, get_message):
'password_confirm': 'newpassword'
}, follow_redirects=True)
- assert get_message('PASSWORD_RESET_EXPIRED', within=within, email=user.email) in response.data
+ msg = get_message('PASSWORD_RESET_EXPIRED', within='1 milliseconds', email=user.email)
+ assert msg in response.data
-def test_custom_reset_url(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_RESET_URL': '/custom_reset'
- })
-
+@pytest.mark.settings(reset_url='/custom_reset')
+def test_custom_reset_url(client):
response = client.get('/custom_reset')
assert response.status_code == 200
-def test_custom_reset_templates(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_RESET_PASSWORD_TEMPLATE': 'custom_security/reset_password.html',
- 'SECURITY_FORGOT_PASSWORD_TEMPLATE': 'custom_security/forgot_password.html'
- })
-
+@pytest.mark.settings(reset_password_template='custom_security/reset_password.html',
+ forgot_password_template='custom_security/forgot_password.html')
+def test_custom_reset_templates(client):
response = client.get('/reset')
assert b'CUSTOM FORGOT PASSWORD' in response.data
diff --git a/tests/test_registerable.py b/tests/test_registerable.py
index 09acaf4..542e1e4 100644
--- a/tests/test_registerable.py
+++ b/tests/test_registerable.py
@@ -6,23 +6,17 @@
Registerable tests
"""
+import pytest
+
from flask_security.signals import user_registered
-from utils import authenticate, logout, init_app_with_options
+from utils import authenticate, logout
+
+pytestmark = pytest.mark.registerable()
-def _get_client(app, datastore, **options):
- config = {
- 'SECURITY_REGISTERABLE': True,
- 'SECURITY_POST_REGISTER_VIEW': '/post_register',
- }
- config.update(options)
- init_app_with_options(app, datastore, **config)
- return app.test_client()
-
-
-def test_registerable_flag(app, sqlalchemy_datastore, get_message):
- client = _get_client(app, sqlalchemy_datastore)
+@pytest.mark.settings(post_register_view='/post_register')
+def test_registerable_flag(client, app, get_message):
recorded = []
# Test the register view
@@ -66,7 +60,6 @@ def test_registerable_flag(app, sqlalchemy_datastore, get_message):
# Test registering with invalid JSON
data = '{ "email": "bogus", "password": "password"}'
response = client.post('/register', data=data, headers={'Content-Type': 'application/json'})
- print response.data
assert response.headers['content-type'] == 'application/json'
assert response.jdata['meta']['code'] == 400
@@ -81,11 +74,8 @@ def test_registerable_flag(app, sqlalchemy_datastore, get_message):
assert b'Page 1' in response.data
-def test_custom_register_url(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_REGISTER_URL': '/custom_register'
- })
-
+@pytest.mark.settings(register_url='/custom_register', post_register_view='/post_register')
+def test_custom_register_url(client):
response = client.get('/custom_register')
assert b"Register
" in response.data
@@ -97,18 +87,14 @@ def test_custom_register_url(app, sqlalchemy_datastore):
assert b'Post Register' in response.data
-def test_custom_register_tempalate(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_REGISTER_USER_TEMPLATE': 'custom_security/register_user.html'
- })
+@pytest.mark.settings(register_user_template='custom_security/register_user.html')
+def test_custom_register_tempalate(client):
response = client.get('/register')
assert b'CUSTOM REGISTER USER' in response.data
-def test_disable_register_emails(app, sqlalchemy_datastore):
- client = _get_client(app, sqlalchemy_datastore, **{
- 'SECURITY_SEND_REGISTER_EMAIL': False
- })
+@pytest.mark.settings(send_register_email=False)
+def test_disable_register_emails(client, app):
data = dict(email='dude@lp.com', password='password', password_confirm='password')
with app.mail.record_messages() as outbox:
client.post('/register', data=data, follow_redirects=True)
diff --git a/tests/test_trackable.py b/tests/test_trackable.py
index 8667fe3..d47f7d3 100644
--- a/tests/test_trackable.py
+++ b/tests/test_trackable.py
@@ -6,16 +6,14 @@
Trackable tests
"""
-from utils import authenticate, logout, init_app_with_options
+import pytest
+
+from utils import authenticate, logout
+
+pytestmark = pytest.mark.trackable()
-def test_trackable_flag(app, sqlalchemy_datastore):
- init_app_with_options(app, sqlalchemy_datastore, **{
- 'SECURITY_TRACKABLE': True
- })
-
- client = app.test_client()
-
+def test_trackable_flag(app, client):
e = 'matt@lp.com'
authenticate(client, email=e)
logout(client)