Browse Source

first functional tests

funding-tag
Holger Frey 5 years ago
parent
commit
1d72e8ee39
  1. 4
      Makefile
  2. 9
      development.ini
  3. 2
      ordr3/__init__.py
  4. 14
      ordr3/views/__init__.py
  5. 194
      tests/functional/conftest.py
  6. 45
      tests/functional/test_login.py
  7. 42
      tests/functional/test_password_reset.py
  8. 43
      tests/functional/test_registration.py

4
Makefile

@ -59,6 +59,10 @@ lint: ## reformat with black and check style with flake8 @@ -59,6 +59,10 @@ lint: ## reformat with black and check style with flake8
test: lint ## run tests quickly with the default Python
pytest tests -x --disable-warnings -m "not app"
functest: lint ## run tests quickly with the default Python
pytest tests/functional -x --disable-warnings -m "not app"
coverage: lint ## full test suite, check code coverage and open coverage report
pytest tests --cov=ordr3
coverage html

9
development.ini

@ -31,15 +31,6 @@ mail.host = localhost @@ -31,15 +31,6 @@ mail.host = localhost
mail.port = 2525
mail.default_sender = ordr@example.com
# custom jinja2 filters:
jinja2.filters =
resource_url = pyramid_jinja2.filters:resource_url_filter
as_date = ordr3.views:jinja_date
as_time = ordr3.views:jinja_time
as_datetime = ordr3.views:jinja_datetime
view_comment = ordr3.views:jinja_view_comment
extract_links = ordr3.views:jinja_extract_links
nl2br = ordr3.views:jinja_nl2br
# By default, the toolbar only appears for clients from IP addresses
# '127.0.0.1' and '::1'.

2
ordr3/__init__.py

@ -23,8 +23,6 @@ def main(global_config, **settings): @@ -23,8 +23,6 @@ def main(global_config, **settings):
require_csrf=settings["session.auto_csrf"]
)
config.include("pyramid_jinja2")
config.include(".adapters")
config.include(".events")
config.include(".resources")

14
ordr3/views/__init__.py

@ -65,3 +65,17 @@ def includeme(config): @@ -65,3 +65,17 @@ def includeme(config):
Activate this setup using ``config.include('ordr3.views')``.
"""
import pyramid_jinja2.filters
config.include("pyramid_jinja2")
config.commit()
j2_env = config.get_jinja2_environment()
j2_env.filters["resource_url"] = pyramid_jinja2.filters.resource_url_filter
j2_env.filters["as_date"] = jinja_date
j2_env.filters["as_time"] = jinja_time
j2_env.filters["as_datetime"] = jinja_datetime
j2_env.filters["view_comment"] = jinja_view_comment
j2_env.filters["extract_links"] = jinja_extract_links
j2_env.filters["nl2br"] = jinja_nl2br

194
tests/functional/conftest.py

@ -0,0 +1,194 @@ @@ -0,0 +1,194 @@
from collections import namedtuple
import pytest
from sqlalchemy.orm import clear_mappers
from ordr3.views import RE_SIMPLE_URL
ParsedMail = namedtuple("ParsedMail", ["body", "link"])
@pytest.fixture
def _pyramid_app():
from ordr3 import main
config = {
"pyramid.includes": ["pyramid_debugtoolbar", "pyramid_mailer.testing"],
"sqlalchemy.url": "sqlite:///:memory:",
"retry.attempts": "3",
"auth.secret": "change me for production",
"session.secret": "change me for production",
"session.auto_csrf": "true",
"static_views.cache_max_age": "0",
"mail.host": "localhost",
"mail.port": "2525",
"mail.default_sender": "ordr@example.com",
"jinja2.filters ": [
"resource_url = pyramid_jinja2.filters:resource_url_filter",
"as_date = ordr3.views:jinja_date",
"as_time = ordr3.views:jinja_time",
"as_datetime = ordr3.views:jinja_datetime",
"view_comment = ordr3.views:jinja_view_comment",
"extract_links = ordr3.views:jinja_extract_links",
"nl2br = ordr3.views:jinja_nl2br",
],
}
yield main({}, **config)
clear_mappers()
@pytest.fixture
def _sqlite_repo(_pyramid_app):
from pyramid.scripting import prepare
from ordr3 import adapters
with prepare() as env:
with env["request"].tm:
repo = env["root"].request.repo
adapters.metadata.create_all(repo.session.get_bind())
yield repo
@pytest.fixture
def _example_data(_sqlite_repo):
from ordr3 import models, security
from datetime import datetime, timedelta
today = datetime.utcnow()
crypt_context = security.get_passlib_context()
user = models.User(
1,
"TestUser",
"Jon",
"Smith",
"jon@example.com",
crypt_context.hash("jon"),
models.UserRole.USER,
)
_sqlite_repo.add_user(user)
admin = models.User(
2,
"TestAdmin",
"Jane",
"Doe",
"jane@example.com",
crypt_context.hash("jane"),
models.UserRole.ADMIN,
)
_sqlite_repo.add_user(admin)
inactive = models.User(
3,
"TestInactive",
"Peter",
"Peter",
"peter@example.com",
crypt_context.hash("peter"),
models.UserRole.INACTIVE,
)
_sqlite_repo.add_user(inactive)
order_1 = models.OrderItem(
1,
"Ethanol",
"123",
"VWR",
models.OrderCategory.SOLVENT,
"1 l",
12.3,
1,
"EUR",
"",
"",
)
_sqlite_repo.add_order(order_1)
log_entry = models.LogEntry(
order_1.id,
models.OrderStatus.COMPLETED,
admin.username,
today - timedelta(days=1),
)
order_1.add_to_log(log_entry)
order_2 = models.OrderItem(
2,
"NaCl",
"234",
"Carl Roth",
models.OrderCategory.CHEMICAL,
"2 kg",
23.4,
2,
"EUR",
"Haushalt",
"Kochsalz",
)
_sqlite_repo.add_order(order_2)
log_entry = models.LogEntry(
order_2.id,
models.OrderStatus.APPROVAL,
admin.username,
today - timedelta(days=2),
)
order_2.add_to_log(log_entry)
order_3 = models.OrderItem(
3,
"Eppis",
"345",
"VWR",
models.OrderCategory.BIOLAB,
"3 St",
34.5,
3,
"USD",
"Toto",
"gefunden bei http://www.example.com/foo",
)
_sqlite_repo.add_order(order_3)
log_entry = models.LogEntry(
order_3.id,
models.OrderStatus.COMPLETED,
user.username,
today - timedelta(days=3),
)
order_3.add_to_log(log_entry)
@pytest.fixture
def testapp(_pyramid_app, _example_data):
from webtest import TestApp
yield TestApp(_pyramid_app)
@pytest.fixture
def login_as(testapp):
def _do_login(username, password):
response = testapp.get("/login")
form = response.form
form["username"] = username
form["password"] = password
return form.submit("submit")
yield _do_login
@pytest.fixture
def parse_latest_mail(testapp):
from pyramid_mailer import get_mailer
def _parse_mail():
registry = testapp.app.registry
mailer = get_mailer(registry)
last_mail = mailer.outbox[-1]
body = last_mail.body
links = RE_SIMPLE_URL.findall(body)
link = links[0] if links else None
return ParsedMail(body, link)
yield _parse_mail

45
tests/functional/test_login.py

@ -0,0 +1,45 @@ @@ -0,0 +1,45 @@
def test_login_ok(testapp):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
form = response.form
form["username"] = "TestAdmin"
form["password"] = "jane"
response = form.submit("submit").follow()
assert "My Orders" in response
def test_login_wrong_password(testapp):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
form = response.form
form["username"] = "TestAdmin"
form["password"] = "wrong password"
response = form.submit("Log In")
assert "Credentials are invalid" in response
def test_login_fails_inactive_user(testapp):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
form = response.form
form["username"] = "TestInactive"
form["password"] = "peter"
response = form.submit("Log In")
assert "Credentials are invalid" in response
def test_logout(testapp):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
form = response.form
form["username"] = "TestAdmin"
form["password"] = "jane"
response = form.submit("submit").follow()
assert "My Orders" in response
response = testapp.get("/logout", status=302).follow(status=200)
assert "Please Log In" in response

42
tests/functional/test_password_reset.py

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
def test_password_reset(testapp, parse_latest_mail):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
form = response.form
form["username"] = "TestAdmin"
form["password"] = "jixx"
response = form.submit("Log In")
assert "Credentials are invalid" in response
response = testapp.get("/forgot", status=200)
assert "Forgot your Password?" in response
form = response.form
form["email_or_username"] = "jane@example.com"
response = form.submit("submit").follow()
assert "An email for the password reset was sent" in response
parsed = parse_latest_mail()
assert "If you forgot your password" in parsed.body
response = testapp.get(parsed.link)
assert "You can now set a new password" in response
form = response.form
form["new_password"] = "jixx"
response = form.submit("Reset Password").follow()
assert "You changed your Password." in response
response = testapp.get("/", status=302).follow(status=200)
form = response.form
form["username"] = "TestAdmin"
form["password"] = "jane"
response = form.submit("Log In")
assert "Credentials are invalid" in response
response = testapp.get("/", status=302).follow(status=200)
form = response.form
form["username"] = "TestAdmin"
form["password"] = "jixx"
response = form.submit("Log In").follow()
assert "My Orders" in response

43
tests/functional/test_registration.py

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
def test_registration_procedure(testapp, login_as, parse_latest_mail):
response = testapp.get("/", status=302).follow(status=200)
assert "Please Log In" in response
response = testapp.get("/registration", status=200)
assert "Register a new account" in response
form = response.form
form["user_name"] = "TestNew"
form["first_name"] = "Eric"
form["last_name"] = "Idle"
form["email"] = "eric@example.com"
form["password"] = "eric"
response = form.submit("Create account").follow()
assert "The account needs to be activated" in response
response = login_as("TestNew", "eric")
assert "Credentials are invalid" in response
login_as("TestAdmin", "jane")
response = testapp.get("/users/?role=new", status=200)
assert "TestNew" in response
response = testapp.get("/users/TestNew/edit", status=200)
assert "Edit User" in response
form = response.forms[1]
form["role"].select(text="User")
response = form.submit("Save changes").follow()
assert "TestNew" in response
response = testapp.get("/users/?role=new", status=200)
assert "TestNew" not in response
response = testapp.get("/users/?role=user", status=200)
assert "TestNew" in response
parsed = parse_latest_mail()
assert "Your account was activated" in parsed.body
response = login_as("TestNew", "eric").follow()
assert "My Orders" in response
Loading…
Cancel
Save