Coverage for website/tests/test_login_and_search_views.py: 100%
63 statements
« prev ^ index » next coverage.py v7.5.0, created at 2025-09-13 15:29 -0300
« prev ^ index » next coverage.py v7.5.0, created at 2025-09-13 15:29 -0300
1from types import SimpleNamespace
2from unittest.mock import patch
4from django.contrib.auth import get_user_model
5from django.contrib.messages.storage.fallback import FallbackStorage
6from django.contrib.sessions.backends.db import SessionStore
7from django.test import RequestFactory, TestCase
9from website.models.AuthorModel import Author
10from website.models.PostModel import Post
11from website.views.LoginView import login_user
12from website.views.SearchView import search_posts
14User = get_user_model()
17class LoginViewTests(TestCase):
18 def setUp(self):
19 self.factory = RequestFactory()
21 def _attach_session_and_messages(self, req):
22 req.session = SessionStore()
23 req._messages = FallbackStorage(req)
25 def test_login_success_redirects(self):
26 # create user
27 user = User.objects.create_user(
28 email="u1@example.com", username="u1", password="pw"
29 )
30 data = {"email": "u1@example.com", "password": "pw"}
31 req = self.factory.post("/login", data)
32 self._attach_session_and_messages(req)
34 # patch authenticate and check_password to ensure branch
35 with (
36 patch("website.views.LoginView.authenticate", return_value=user),
37 patch("website.views.LoginView.check_password", return_value=True),
38 ):
39 resp = login_user(req)
41 # successful login redirects to '/'
42 assert resp.status_code in (301, 302)
44 def test_login_email_not_found_renders_with_flag(self):
45 data = {"email": "noone@example.com", "password": "pw"}
46 req = self.factory.post("/login", data)
47 self._attach_session_and_messages(req)
49 # patch render to capture context
50 def fake_render(req_in, template, context=None, status=200):
51 return SimpleNamespace(status_code=status, context=context)
53 with patch("website.views.LoginView.render", fake_render):
54 resp = login_user(req)
56 assert resp.status_code == 200
57 assert getattr(resp, "context", None) is not None
58 assert resp.context.get("email_not_found", False) is True
61class SearchViewTests(TestCase):
62 def setUp(self):
63 self.factory = RequestFactory()
65 def test_search_returns_results_and_counts(self):
66 user = User.objects.create_user(
67 email="a@example.com", username="a", password="pw"
68 )
69 author = Author.objects.create(
70 user=user, author_name="AuthorX", author_url_slug="ax"
71 )
72 # create matching posts
73 Post.objects.create(author=author, title="FindMe", text="abc", url_slug="p1")
74 Post.objects.create(
75 author=author, title="FindMe two", text="def", url_slug="p2"
76 )
78 req = self.factory.get("/search", {"query": "FindMe"})
80 def fake_render(req_in, template, context=None):
81 return SimpleNamespace(status_code=200, context=context)
83 with patch("website.views.SearchView.render", fake_render):
84 resp = search_posts(req)
86 assert resp.status_code == 200
87 assert resp.context["results_count"] == 2
89 def test_search_page_not_integer_returns_first_page(self):
90 user = User.objects.create_user(
91 email="b@example.com", username="b", password="pw"
92 )
93 author = Author.objects.create(
94 user=user, author_name="AuthorY", author_url_slug="ay"
95 )
96 # one matching post
97 Post.objects.create(author=author, title="OnlyOne", text="x", url_slug="o1")
99 req = self.factory.get("/search", {"query": "OnlyOne", "page": "notint"})
101 def fake_render(req_in, template, context=None):
102 return SimpleNamespace(status_code=200, context=context)
104 resp = None
105 with patch("website.views.SearchView.render", fake_render):
106 resp = search_posts(req)
108 assert resp.status_code == 200
109 # posts is a Page object; ensure it corresponds to page 1
110 # by checking object_list length
111 assert len(list(resp.context["posts"])) == 1