aboutsummaryrefslogtreecommitdiffstats
path: root/alphabetlearning/users/tests
diff options
context:
space:
mode:
Diffstat (limited to 'alphabetlearning/users/tests')
-rw-r--r--alphabetlearning/users/tests/__init__.py0
-rw-r--r--alphabetlearning/users/tests/factories.py40
-rw-r--r--alphabetlearning/users/tests/test_admin.py65
-rw-r--r--alphabetlearning/users/tests/test_forms.py35
-rw-r--r--alphabetlearning/users/tests/test_managers.py55
-rw-r--r--alphabetlearning/users/tests/test_models.py5
-rw-r--r--alphabetlearning/users/tests/test_tasks.py17
-rw-r--r--alphabetlearning/users/tests/test_urls.py19
-rw-r--r--alphabetlearning/users/tests/test_views.py101
9 files changed, 337 insertions, 0 deletions
diff --git a/alphabetlearning/users/tests/__init__.py b/alphabetlearning/users/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/alphabetlearning/users/tests/__init__.py
diff --git a/alphabetlearning/users/tests/factories.py b/alphabetlearning/users/tests/factories.py
new file mode 100644
index 0000000..c0e94a3
--- /dev/null
+++ b/alphabetlearning/users/tests/factories.py
@@ -0,0 +1,40 @@
+from collections.abc import Sequence
+from typing import Any
+
+from factory import Faker
+from factory import post_generation
+from factory.django import DjangoModelFactory
+
+from alphabetlearning.users.models import User
+
+
+class UserFactory(DjangoModelFactory):
+ email = Faker("email")
+ name = Faker("name")
+
+ @post_generation
+ def password(self, create: bool, extracted: Sequence[Any], **kwargs): # noqa: FBT001
+ password = (
+ extracted
+ if extracted
+ else Faker(
+ "password",
+ length=42,
+ special_chars=True,
+ digits=True,
+ upper_case=True,
+ lower_case=True,
+ ).evaluate(None, None, extra={"locale": None})
+ )
+ self.set_password(password)
+
+ @classmethod
+ def _after_postgeneration(cls, instance, create, results=None):
+ """Save again the instance if creating and at least one hook ran."""
+ if create and results and not cls._meta.skip_postgeneration_save:
+ # Some post-generation hooks ran, and may have modified us.
+ instance.save()
+
+ class Meta:
+ model = User
+ django_get_or_create = ["email"]
diff --git a/alphabetlearning/users/tests/test_admin.py b/alphabetlearning/users/tests/test_admin.py
new file mode 100644
index 0000000..bd7296f
--- /dev/null
+++ b/alphabetlearning/users/tests/test_admin.py
@@ -0,0 +1,65 @@
+import contextlib
+from http import HTTPStatus
+from importlib import reload
+
+import pytest
+from django.contrib import admin
+from django.contrib.auth.models import AnonymousUser
+from django.urls import reverse
+from pytest_django.asserts import assertRedirects
+
+from alphabetlearning.users.models import User
+
+
+class TestUserAdmin:
+ def test_changelist(self, admin_client):
+ url = reverse("admin:users_user_changelist")
+ response = admin_client.get(url)
+ assert response.status_code == HTTPStatus.OK
+
+ def test_search(self, admin_client):
+ url = reverse("admin:users_user_changelist")
+ response = admin_client.get(url, data={"q": "test"})
+ assert response.status_code == HTTPStatus.OK
+
+ def test_add(self, admin_client):
+ url = reverse("admin:users_user_add")
+ response = admin_client.get(url)
+ assert response.status_code == HTTPStatus.OK
+
+ response = admin_client.post(
+ url,
+ data={
+ "email": "new-admin@example.com",
+ "password1": "My_R@ndom-P@ssw0rd",
+ "password2": "My_R@ndom-P@ssw0rd",
+ },
+ )
+ assert response.status_code == HTTPStatus.FOUND
+ assert User.objects.filter(email="new-admin@example.com").exists()
+
+ def test_view_user(self, admin_client):
+ user = User.objects.get(email="admin@example.com")
+ url = reverse("admin:users_user_change", kwargs={"object_id": user.pk})
+ response = admin_client.get(url)
+ assert response.status_code == HTTPStatus.OK
+
+ @pytest.fixture()
+ def _force_allauth(self, settings):
+ settings.DJANGO_ADMIN_FORCE_ALLAUTH = True
+ # Reload the admin module to apply the setting change
+ import alphabetlearning.users.admin as users_admin
+
+ with contextlib.suppress(admin.sites.AlreadyRegistered):
+ reload(users_admin)
+
+ @pytest.mark.django_db()
+ @pytest.mark.usefixtures("_force_allauth")
+ def test_allauth_login(self, rf, settings):
+ request = rf.get("/fake-url")
+ request.user = AnonymousUser()
+ response = admin.site.login(request)
+
+ # The `admin` login view should redirect to the `allauth` login view
+ target_url = reverse(settings.LOGIN_URL) + "?next=" + request.path
+ assertRedirects(response, target_url, fetch_redirect_response=False)
diff --git a/alphabetlearning/users/tests/test_forms.py b/alphabetlearning/users/tests/test_forms.py
new file mode 100644
index 0000000..9ab1f7e
--- /dev/null
+++ b/alphabetlearning/users/tests/test_forms.py
@@ -0,0 +1,35 @@
+"""Module for all Form Tests."""
+
+from django.utils.translation import gettext_lazy as _
+
+from alphabetlearning.users.forms import UserAdminCreationForm
+from alphabetlearning.users.models import User
+
+
+class TestUserAdminCreationForm:
+ """
+ Test class for all tests related to the UserAdminCreationForm
+ """
+
+ def test_username_validation_error_msg(self, user: User):
+ """
+ Tests UserAdminCreation Form's unique validator functions correctly by testing:
+ 1) A new user with an existing username cannot be added.
+ 2) Only 1 error is raised by the UserCreation Form
+ 3) The desired error message is raised
+ """
+
+ # The user already exists,
+ # hence cannot be created.
+ form = UserAdminCreationForm(
+ {
+ "email": user.email,
+ "password1": user.password,
+ "password2": user.password,
+ },
+ )
+
+ assert not form.is_valid()
+ assert len(form.errors) == 1
+ assert "email" in form.errors
+ assert form.errors["email"][0] == _("This email has already been taken.")
diff --git a/alphabetlearning/users/tests/test_managers.py b/alphabetlearning/users/tests/test_managers.py
new file mode 100644
index 0000000..1e5a5e3
--- /dev/null
+++ b/alphabetlearning/users/tests/test_managers.py
@@ -0,0 +1,55 @@
+from io import StringIO
+
+import pytest
+from django.core.management import call_command
+
+from alphabetlearning.users.models import User
+
+
+@pytest.mark.django_db()
+class TestUserManager:
+ def test_create_user(self):
+ user = User.objects.create_user(
+ email="john@example.com",
+ password="something-r@nd0m!", # noqa: S106
+ )
+ assert user.email == "john@example.com"
+ assert not user.is_staff
+ assert not user.is_superuser
+ assert user.check_password("something-r@nd0m!")
+ assert user.username is None
+
+ def test_create_superuser(self):
+ user = User.objects.create_superuser(
+ email="admin@example.com",
+ password="something-r@nd0m!", # noqa: S106
+ )
+ assert user.email == "admin@example.com"
+ assert user.is_staff
+ assert user.is_superuser
+ assert user.username is None
+
+ def test_create_superuser_username_ignored(self):
+ user = User.objects.create_superuser(
+ email="test@example.com",
+ password="something-r@nd0m!", # noqa: S106
+ )
+ assert user.username is None
+
+
+@pytest.mark.django_db()
+def test_createsuperuser_command():
+ """Ensure createsuperuser command works with our custom manager."""
+ out = StringIO()
+ command_result = call_command(
+ "createsuperuser",
+ "--email",
+ "henry@example.com",
+ interactive=False,
+ stdout=out,
+ )
+
+ assert command_result is None
+ assert out.getvalue() == "Superuser created successfully.\n"
+ user = User.objects.get(email="henry@example.com")
+ assert not user.has_usable_password()
diff --git a/alphabetlearning/users/tests/test_models.py b/alphabetlearning/users/tests/test_models.py
new file mode 100644
index 0000000..502536f
--- /dev/null
+++ b/alphabetlearning/users/tests/test_models.py
@@ -0,0 +1,5 @@
+from alphabetlearning.users.models import User
+
+
+def test_user_get_absolute_url(user: User):
+ assert user.get_absolute_url() == f"/users/{user.pk}/"
diff --git a/alphabetlearning/users/tests/test_tasks.py b/alphabetlearning/users/tests/test_tasks.py
new file mode 100644
index 0000000..92f0e8a
--- /dev/null
+++ b/alphabetlearning/users/tests/test_tasks.py
@@ -0,0 +1,17 @@
+import pytest
+from celery.result import EagerResult
+
+from alphabetlearning.users.tasks import get_users_count
+from alphabetlearning.users.tests.factories import UserFactory
+
+pytestmark = pytest.mark.django_db
+
+
+def test_user_count(settings):
+ """A basic test to execute the get_users_count Celery task."""
+ batch_size = 3
+ UserFactory.create_batch(batch_size)
+ settings.CELERY_TASK_ALWAYS_EAGER = True
+ task_result = get_users_count.delay()
+ assert isinstance(task_result, EagerResult)
+ assert task_result.result == batch_size
diff --git a/alphabetlearning/users/tests/test_urls.py b/alphabetlearning/users/tests/test_urls.py
new file mode 100644
index 0000000..e70dc03
--- /dev/null
+++ b/alphabetlearning/users/tests/test_urls.py
@@ -0,0 +1,19 @@
+from django.urls import resolve
+from django.urls import reverse
+
+from alphabetlearning.users.models import User
+
+
+def test_detail(user: User):
+ assert reverse("users:detail", kwargs={"pk": user.pk}) == f"/users/{user.pk}/"
+ assert resolve(f"/users/{user.pk}/").view_name == "users:detail"
+
+
+def test_update():
+ assert reverse("users:update") == "/users/~update/"
+ assert resolve("/users/~update/").view_name == "users:update"
+
+
+def test_redirect():
+ assert reverse("users:redirect") == "/users/~redirect/"
+ assert resolve("/users/~redirect/").view_name == "users:redirect"
diff --git a/alphabetlearning/users/tests/test_views.py b/alphabetlearning/users/tests/test_views.py
new file mode 100644
index 0000000..27e6064
--- /dev/null
+++ b/alphabetlearning/users/tests/test_views.py
@@ -0,0 +1,101 @@
+from http import HTTPStatus
+
+import pytest
+from django.conf import settings
+from django.contrib import messages
+from django.contrib.auth.models import AnonymousUser
+from django.contrib.messages.middleware import MessageMiddleware
+from django.contrib.sessions.middleware import SessionMiddleware
+from django.http import HttpRequest
+from django.http import HttpResponseRedirect
+from django.test import RequestFactory
+from django.urls import reverse
+from django.utils.translation import gettext_lazy as _
+
+from alphabetlearning.users.forms import UserAdminChangeForm
+from alphabetlearning.users.models import User
+from alphabetlearning.users.tests.factories import UserFactory
+from alphabetlearning.users.views import UserRedirectView
+from alphabetlearning.users.views import UserUpdateView
+from alphabetlearning.users.views import user_detail_view
+
+pytestmark = pytest.mark.django_db
+
+
+class TestUserUpdateView:
+ """
+ TODO:
+ extracting view initialization code as class-scoped fixture
+ would be great if only pytest-django supported non-function-scoped
+ fixture db access -- this is a work-in-progress for now:
+ https://github.com/pytest-dev/pytest-django/pull/258
+ """
+
+ def dummy_get_response(self, request: HttpRequest):
+ return None
+
+ def test_get_success_url(self, user: User, rf: RequestFactory):
+ view = UserUpdateView()
+ request = rf.get("/fake-url/")
+ request.user = user
+
+ view.request = request
+ assert view.get_success_url() == f"/users/{user.pk}/"
+
+ def test_get_object(self, user: User, rf: RequestFactory):
+ view = UserUpdateView()
+ request = rf.get("/fake-url/")
+ request.user = user
+
+ view.request = request
+
+ assert view.get_object() == user
+
+ def test_form_valid(self, user: User, rf: RequestFactory):
+ view = UserUpdateView()
+ request = rf.get("/fake-url/")
+
+ # Add the session/message middleware to the request
+ SessionMiddleware(self.dummy_get_response).process_request(request)
+ MessageMiddleware(self.dummy_get_response).process_request(request)
+ request.user = user
+
+ view.request = request
+
+ # Initialize the form
+ form = UserAdminChangeForm()
+ form.cleaned_data = {}
+ form.instance = user
+ view.form_valid(form)
+
+ messages_sent = [m.message for m in messages.get_messages(request)]
+ assert messages_sent == [_("Information successfully updated")]
+
+
+class TestUserRedirectView:
+ def test_get_redirect_url(self, user: User, rf: RequestFactory):
+ view = UserRedirectView()
+ request = rf.get("/fake-url")
+ request.user = user
+
+ view.request = request
+ assert view.get_redirect_url() == f"/users/{user.pk}/"
+
+
+class TestUserDetailView:
+ def test_authenticated(self, user: User, rf: RequestFactory):
+ request = rf.get("/fake-url/")
+ request.user = UserFactory()
+ response = user_detail_view(request, pk=user.pk)
+
+ assert response.status_code == HTTPStatus.OK
+
+ def test_not_authenticated(self, user: User, rf: RequestFactory):
+ request = rf.get("/fake-url/")
+ request.user = AnonymousUser()
+ response = user_detail_view(request, pk=user.pk)
+ login_url = reverse(settings.LOGIN_URL)
+
+ assert isinstance(response, HttpResponseRedirect)
+ assert response.status_code == HTTPStatus.FOUND
+ assert response.url == f"{login_url}?next=/fake-url/"