Skip to content
This repository has been archived by the owner on Mar 19, 2024. It is now read-only.

Commit

Permalink
Add tests for registration url
Browse files Browse the repository at this point in the history
  • Loading branch information
syndicut committed Sep 27, 2023
1 parent 352aa9b commit 4811647
Show file tree
Hide file tree
Showing 6 changed files with 292 additions and 104 deletions.
264 changes: 163 additions & 101 deletions poetry.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,15 @@ structlog = "^23.1"
requests = "^2.28"
attrs = "^23.1"
pydantic = "^2.3"
punq = "^0.6"
punq = "^0.6.2"

[tool.poetry.group.dev.dependencies]
django-debug-toolbar = "^4.2"
django-querycount = "^0.8"
django-migration-linter = "^5.0"
django-extra-checks = "^0.13"
nplusone = "^1.0"
mimesis = "^11.1.0"

wemake-python-styleguide = "^0.18"
flake8-pytest-style = "^1.7"
Expand Down Expand Up @@ -66,6 +67,7 @@ dennis = "^1.1"
dump-env = "^1.3"
ipython = "^8.15"
import-linter = "^1.11"
faker = "^19.6.1"

[tool.poetry.group.docs]
optional = true
Expand Down
3 changes: 1 addition & 2 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@
pytest_plugins = [
# Should be the first custom one:
'plugins.django_settings',

# TODO: add your own plugins here!
'plugins.identity.user',
]
Empty file added tests/plugins/__init__.py
Empty file.
105 changes: 105 additions & 0 deletions tests/plugins/identity/user.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import datetime as dt
from typing import Callable, Protocol, TypeAlias, TypedDict, Unpack, final

import pytest
from mimesis import Field, Locale, Schema

from server.apps.identity.models import User


class UserData(TypedDict, total=False):
"""
Represent the simplified user data that is required to create a new user.
It does not include ``password``, because it is very special in django.
"""

email: str
first_name: str
last_name: str
date_of_birth: dt.datetime
address: str
job_title: str
phone: str


@final
class RegistrationData(UserData, total=False):
"""Represent the registration data that is required to create a new user."""

password1: str
password2: str


@final
class RegistrationDataFactory(Protocol):
"""User data factory protocol."""

def __call__(self, **fields: Unpack[RegistrationData]) -> RegistrationData:
"""Method to call as a function with RegistrationData as kwargs."""


UserAssertion: TypeAlias = Callable[[str, UserData], None]


@pytest.fixture()
def registration_data_factory(faker_seed: int) -> RegistrationDataFactory:
"""Returns factory for random data generation."""
def factory(**fields: Unpack[RegistrationData]) -> RegistrationData:
mf = Field(locale=Locale.RU, seed=faker_seed)
password = mf('password')
schema = Schema(
schema=lambda: {
'email': mf('person:email'),
'first_name': mf('person:first_name'),
'last_name': mf('person:last_name'),
'date_of_birth': mf('datetime:date'),
'address': mf('address.city'),
'job_title': mf('person.occupation'),
'phone': mf('person.telephone'),
}, iterations=1,
)
return {
**schema.create()[0], # type: ignore[misc]
**{'password1': password, 'password2': password},
**fields,
}

return factory


@pytest.fixture()
def registration_data(
registration_data_factory: RegistrationDataFactory,
) -> RegistrationData:
"""Returns fake random data for regitration."""
return registration_data_factory()


@pytest.fixture()
def user_data(registration_data: RegistrationData) -> UserData:
"""
We need to simplify registration data to drop passwords.
Basically, it is the same as ``registration_data``, but without passwords.
"""
return { # type: ignore[return-value]
key_name: value_part
for key_name, value_part in registration_data.items()
if not key_name.startswith('password')
}


@pytest.fixture(scope='session')
def assert_correct_user() -> UserAssertion:
"""Factory to compare all user fields."""
def factory(email: str, expected: UserData) -> None:
user = User.objects.get(email=email)
assert user.id
assert user.is_active
assert not user.is_superuser
assert not user.is_staff
for field_name, data_value in expected.items():
assert getattr(user, field_name) == data_value

return factory
20 changes: 20 additions & 0 deletions tests/test_apps/test_identity/test_registration.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
from http import HTTPStatus

import pytest
from django.test.client import Client
from plugins.identity.user import RegistrationData, UserAssertion, UserData


@pytest.mark.django_db()
def test_valid_registration(
client: Client,
registration_data: RegistrationData,
user_data: UserData,
assert_correct_user: UserAssertion,
) -> None:
"""Test that registration works with correct user data."""
response = client.post('/identity/registration', data=registration_data)

assert response.status_code == HTTPStatus.FOUND
assert response.get('Location') == '/identity/login'
assert_correct_user(registration_data['email'], user_data)

0 comments on commit 4811647

Please sign in to comment.