Coverage for website/tests/test_author_view.py: 100%

76 statements  

« prev     ^ index     » next       coverage.py v7.5.0, created at 2025-09-13 15:29 -0300

1from unittest.mock import MagicMock, patch 

2 

3from django.contrib.auth import get_user_model 

4from django.core.files.uploadedfile import SimpleUploadedFile 

5from django.http import HttpResponse 

6from django.test import RequestFactory, TestCase 

7 

8import website.views.AuthorView as av 

9from website.models.AuthorModel import Author 

10from website.models.AuthorSocialMediaModel import SocialMedia 

11 

12User = get_user_model() 

13 

14 

15class AuthorViewTests(TestCase): 

16 def setUp(self): 

17 self.factory = RequestFactory() 

18 self.owner = User.objects.create_user( 

19 email="owner@example.com", password="pw", username="owner" 

20 ) 

21 self.other = User.objects.create_user( 

22 email="other@example.com", password="pw", username="other" 

23 ) 

24 self.author = Author.objects.create( 

25 user=self.owner, author_name="Owner", author_url_slug="owner" 

26 ) 

27 

28 def test_view_author_page_owner_and_non_owner(self): 

29 # Patch render to capture context without rendering templates 

30 captured = {} 

31 

32 def fake_render(request, template_name=None, context=None, status=200): 

33 resp = HttpResponse(status=status) 

34 resp.context = context or {} 

35 captured["ctx"] = context or {} 

36 return resp 

37 

38 with patch.object(av, "render", side_effect=fake_render): 

39 # non-owner 

40 req = self.factory.get("/") 

41 req.user = self.other 

42 resp = av.view_author_page(req, slug=self.author.author_url_slug) 

43 assert resp.status_code == 200 

44 assert captured["ctx"]["author_connected"] is False 

45 

46 # owner 

47 req2 = self.factory.get("/") 

48 req2.user = self.owner 

49 resp2 = av.view_author_page(req2, slug=self.author.author_url_slug) 

50 assert resp2.status_code == 200 

51 assert captured["ctx"]["author_connected"] is True 

52 

53 def test_check_request_post_parses_post_and_files(self): 

54 # create a dummy social media entry so counts compare 

55 SocialMedia.objects.create( 

56 user_social_media=self.author, social_media=1, social_media_profile="p1" 

57 ) 

58 

59 data = { 

60 "username": "owner", 

61 "author_name": "New Owner", 

62 "social_media": ["1", "2"], 

63 "social_media_profile": ["p1", "p2"], 

64 "exclude-social": ["", ""], 

65 } 

66 img = SimpleUploadedFile("pic.jpg", b"filecontent", content_type="image/jpeg") 

67 req = self.factory.post("/", data, FILES={"image": img}) 

68 req.user = self.owner 

69 parsed = av.check_request_post(req) 

70 assert parsed["username"] == "owner" 

71 assert parsed["name"] == "New Owner" 

72 assert "image" in parsed 

73 assert isinstance(parsed["exclude_social_media"], list) 

74 

75 def test_edit_author_profile_post_success_path(self): 

76 # Prepare a POST request and patch internal helpers to simulate success path 

77 data = {"username": "owner", "author_name": "Owner New"} 

78 req = self.factory.post("/", data) 

79 req.user = self.owner 

80 

81 # Patch helpers: check_request_post, check_author_form, update_social_media, create_social_media, exclude_social_media 

82 fake_check = { 

83 "username": "owner", 

84 "name": "Owner New", 

85 "check_username_request": None, 

86 "image": None, 

87 "new_social_addition": False, 

88 "exclude_social_media": [], 

89 } 

90 

91 # Patch form classes and formset factory so validations pass and redirect occurs 

92 

93 class FakeFormSet: 

94 def __init__(self, *a, **k): 

95 self.instance = None 

96 

97 def is_valid(self): 

98 return True 

99 

100 def save(self): 

101 return None 

102 

103 user_form_mock = MagicMock() 

104 user_form_mock.is_valid.return_value = True 

105 user_form_mock.save.return_value = req.user 

106 user_form_mock.cleaned_data = {"password": None} 

107 

108 author_form_mock = MagicMock() 

109 author_form_mock.is_valid.return_value = True 

110 author_form_mock.save.return_value = self.author 

111 

112 with ( 

113 patch.object(av, "check_request_post", return_value=fake_check), 

114 patch.object(av, "check_author_form", return_value=True), 

115 patch.object(av, "update_social_media", return_value=False), 

116 patch.object(av, "create_social_media") as mock_create, 

117 patch.object(av, "exclude_social_media") as mock_exclude, 

118 patch.object(av, "messages"), 

119 patch.object(av, "redirect", return_value=HttpResponse(status=302)), 

120 patch.object(av, "UserChangeForm", return_value=user_form_mock), 

121 patch.object(av, "EditAuthorForm", return_value=author_form_mock), 

122 patch.object(av, "inlineformset_factory", return_value=FakeFormSet), 

123 ): 

124 resp = av.edit_author_profile(req, slug=self.author.author_url_slug) 

125 assert resp.status_code in (301, 302) 

126 # ensure create/exclude not called in this path 

127 mock_create.assert_not_called() 

128 mock_exclude.assert_not_called() 

129 

130 def test_edit_author_profile_post_username_conflict_shows_error(self): 

131 # Simulate a username conflict path where check_author_form is False due to username taken 

132 data = {"username": "taken", "author_name": "Name"} 

133 req = self.factory.post("/", data) 

134 req.user = self.owner 

135 fake_check = { 

136 "username": "taken", 

137 "name": "Name", 

138 "check_username_request": True, # indicates another exists -> conflict 

139 "image": None, 

140 "new_social_addition": False, 

141 "exclude_social_media": [], 

142 } 

143 

144 with ( 

145 patch.object(av, "check_request_post", return_value=fake_check), 

146 patch.object(av, "check_author_form", return_value=False), 

147 patch.object(av, "messages"), 

148 patch.object(av, "render", return_value=HttpResponse(status=200)), 

149 ): 

150 resp = av.edit_author_profile(req, slug=self.author.author_url_slug) 

151 # In conflict case the view renders the edit page (status 200) 

152 assert resp.status_code == 200 

153 # messages.error should have been called by the view; ensure messages exists 

154 # We patched messages module with a dummy object; here we assert render returned 200