Skip to content

Commit 8057e58

Browse files
committed
test: extend test coverage
1 parent ab99bc3 commit 8057e58

File tree

1 file changed

+147
-100
lines changed

1 file changed

+147
-100
lines changed

chores/tests/test_views.py

Lines changed: 147 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import time_machine
44
from django.contrib.auth import get_user_model
5+
from django.core import mail
56
from django.test import TestCase
67
from django.urls import reverse
78
from faker import Faker
@@ -23,22 +24,11 @@ def load_schema(schema_path):
2324

2425
class ChoresViewsTest(TestCase):
2526
def setUp(self):
26-
self.user = UserFactory(
27-
password="testpassword"
28-
)
27+
self.user = UserFactory(password="testpassword")
2928

30-
def test_empty_chores_overview_200(self):
31-
"""Test that the empty chores overview returns a 200 response"""
32-
url = reverse("chores")
33-
success = self.client.login(email=self.user.email, password="testpassword")
34-
self.assertTrue(success)
35-
response = self.client.get(url)
36-
self.assertEqual(response.status_code, status.HTTP_200_OK)
37-
self.assertIn('data-test-hook="empty-chores"', response.content.decode("utf-8"))
38-
39-
def test_chores_overview_with_chore_200(self):
40-
url = reverse("chores")
41-
chore = Chore.objects.create(
29+
@time_machine.travel("2025-07-13 14:56")
30+
def create_chore(self, **kwargs):
31+
defaults = dict(
4232
name=fake.name(),
4333
description="A test chore that needs volunteers.",
4434
class_type="BasicChore",
@@ -51,42 +41,28 @@ def test_chores_overview_with_chore_200(self):
5141
"crontab": "0 22 * * sun",
5242
"take_one_every": 2,
5343
},
54-
"reminders": [
55-
{
56-
"reminder_type": "missing_volunteers",
57-
"when": {"days_before": 10, "time": "17:00"},
58-
"nudges": [
59-
{
60-
"nudge_type": "email",
61-
"nudge_key": "gentle_email_reminder",
62-
"destination": "[email protected]",
63-
"subject_template": "Volunteers needed next week",
64-
"body_template": "Hallo, we hebben {num_volunteers_needed} vrijwilliger nodig volgende week.\n\nOm stof in onze makerspace tegen te gaan willen we je vragen om te stofzuigen in de voorste ruimte en de houtwerkplaats, en eventueel de grote hal. \n\nAls je daar zin in hebt kun je ook de voorste ruimte dweilen met de hippe turbodweil die we hebben, maar als je weinig tijd hebt: Met alleen stofzuigen is al veel te winnen.\n\nDeze taak kan op elk moment gedurende de week worden gedaan. Je helpt wanneer het jou uitkomt, alle hulp is welkom!\n\nInformatie over schoonmaken op de Wiki: https://wiki.makerspaceleiden.nl/mediawiki/index.php/Chore_-_Dedustify \n\n\nClick here to sign up: {signup_url}",
65-
}
66-
],
67-
},
68-
{
69-
"reminder_type": "missing_volunteers",
70-
"when": {"days_before": 6, "time": "17:00"},
71-
"nudges": [
72-
{
73-
"nudge_type": "email",
74-
"nudge_key": "hard_email_reminder",
75-
"destination": "[email protected]",
76-
"subject_template": "Volunteers REALLY needed for this week",
77-
"body_template": "Hallo, we hebben nog steeds {num_volunteers_needed} vrijwilliger nodig voor deze week.\n\nOm stof in onze makerspace tegen te gaan willen we je vragen om te stofzuigen in de voorste ruimte en de houtwerkplaats, en eventueel de grote hal. \n\nAls je daar zin in hebt kun je ook de voorste ruimte dweilen met de hippe turbodweil die we hebben, maar als je weinig tijd hebt: Met alleen stofzuigen is al veel te winnen.\n\nDeze taak kan op elk moment gedurende de week worden gedaan. Je helpt wanneer het jou uitkomt, alle hulp is welkom!\n\nInformatie over schoonmaken op de Wiki: https://wiki.makerspaceleiden.nl/mediawiki/index.php/Chore_-_Dedustify \n\nClick here to sign up: {signup_url}",
78-
}
79-
],
80-
},
81-
{
82-
"reminder_type": "volunteers_who_signed_up",
83-
"when": {"days_before": 7, "time": "19:00"},
84-
},
85-
],
44+
"reminders": [],
8645
},
8746
creator=self.user,
8847
)
89-
48+
defaults.update(kwargs)
49+
return Chore.objects.create(**defaults)
50+
51+
@time_machine.travel("2025-07-13 14:56")
52+
def test_empty_chores_overview_200(self):
53+
"""Test that the empty chores overview returns a 200 response"""
54+
url = reverse("chores")
55+
success = self.client.login(email=self.user.email, password="testpassword")
56+
self.assertTrue(success)
57+
response = self.client.get(url)
58+
self.assertEqual(response.status_code, status.HTTP_200_OK)
59+
self.assertIn('data-test-hook="empty-chores"', response.content.decode("utf-8"))
60+
61+
@time_machine.travel("2025-07-13 14:56")
62+
def test_chores_overview_with_chore_200(self):
63+
url = reverse("chores")
64+
chore = self.create_chore()
65+
9066
success = self.client.login(email=self.user.email, password="testpassword")
9167
self.assertTrue(success)
9268
response = self.client.get(url)
@@ -97,61 +73,12 @@ def test_chores_overview_with_chore_200(self):
9773
self.assertNotIn('data-test-hook="chores-volunteer"', html)
9874
self.assertNotIn('data-test-hook="empty-chores"', html)
9975

100-
76+
@time_machine.travel("2025-07-13 14:56")
10177
def test_chores_overview_with_chore_and_volunteer_200(self):
10278
url = reverse("chores")
103-
chore = Chore.objects.create(
104-
name=fake.name(),
105-
description="A test chore that needs volunteers.",
106-
class_type="BasicChore",
107-
wiki_url=fake.url(),
108-
configuration={
109-
"min_required_people": 1,
110-
"events_generation": {
111-
"event_type": "recurrent",
112-
"starting_time": "21/7/2021 8:00",
113-
"crontab": "0 22 * * sun",
114-
"take_one_every": 2,
115-
},
116-
"reminders": [
117-
{
118-
"reminder_type": "missing_volunteers",
119-
"when": {"days_before": 10, "time": "17:00"},
120-
"nudges": [
121-
{
122-
"nudge_type": "email",
123-
"nudge_key": "gentle_email_reminder",
124-
"destination": "[email protected]",
125-
"subject_template": "Volunteers needed next week",
126-
"body_template": "Hallo, we hebben {num_volunteers_needed} vrijwilliger nodig volgende week.\n\nOm stof in onze makerspace tegen te gaan willen we je vragen om te stofzuigen in de voorste ruimte en de houtwerkplaats, en eventueel de grote hal. \n\nAls je daar zin in hebt kun je ook de voorste ruimte dweilen met de hippe turbodweil die we hebben, maar als je weinig tijd hebt: Met alleen stofzuigen is al veel te winnen.\n\nDeze taak kan op elk moment gedurende de week worden gedaan. Je helpt wanneer het jou uitkomt, alle hulp is welkom!\n\nInformatie over schoonmaken op de Wiki: https://wiki.makerspaceleiden.nl/mediawiki/index.php/Chore_-_Dedustify \n\n\nClick here to sign up: {signup_url}",
127-
}
128-
],
129-
},
130-
{
131-
"reminder_type": "missing_volunteers",
132-
"when": {"days_before": 6, "time": "17:00"},
133-
"nudges": [
134-
{
135-
"nudge_type": "email",
136-
"nudge_key": "hard_email_reminder",
137-
"destination": "[email protected]",
138-
"subject_template": "Volunteers REALLY needed for this week",
139-
"body_template": "Hallo, we hebben nog steeds {num_volunteers_needed} vrijwilliger nodig voor deze week.\n\nOm stof in onze makerspace tegen te gaan willen we je vragen om te stofzuigen in de voorste ruimte en de houtwerkplaats, en eventueel de grote hal. \n\nAls je daar zin in hebt kun je ook de voorste ruimte dweilen met de hippe turbodweil die we hebben, maar als je weinig tijd hebt: Met alleen stofzuigen is al veel te winnen.\n\nDeze taak kan op elk moment gedurende de week worden gedaan. Je helpt wanneer het jou uitkomt, alle hulp is welkom!\n\nInformatie over schoonmaken op de Wiki: https://wiki.makerspaceleiden.nl/mediawiki/index.php/Chore_-_Dedustify \n\nClick here to sign up: {signup_url}",
140-
}
141-
],
142-
},
143-
{
144-
"reminder_type": "volunteers_who_signed_up",
145-
"when": {"days_before": 7, "time": "19:00"},
146-
},
147-
],
148-
},
149-
creator=self.user,
150-
)
79+
chore = self.create_chore()
15180
volunteer = UserFactory()
152-
ChoreVolunteer.objects.create(
153-
user=volunteer, chore=chore, timestamp=1753041600
154-
)
81+
ChoreVolunteer.objects.create(user=volunteer, chore=chore, timestamp=1753041600)
15582

15683
success = self.client.login(email=self.user.email, password="testpassword")
15784
self.assertTrue(success)
@@ -163,4 +90,124 @@ def test_chores_overview_with_chore_and_volunteer_200(self):
16390
self.assertIn(volunteer.first_name, html)
16491
self.assertNotIn('data-test-hook="empty-chores"', html)
16592

93+
@time_machine.travel("2025-07-13 14:56")
94+
def test_signup_success(self):
95+
chore = self.create_chore()
96+
ts = 1753041600
97+
url = reverse("signup_chore", args=[chore.id, ts])
98+
self.client.login(email=self.user.email, password="testpassword")
99+
response = self.client.get(url + "?redirect_to=chores")
100+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
101+
self.assertIn("chores", response.url)
102+
self.assertTrue(
103+
ChoreVolunteer.objects.filter(
104+
user=self.user, chore=chore, timestamp=ts
105+
).exists()
106+
)
107+
self.assertEqual(len(mail.outbox), 1)
108+
self.assertIn("volunteer", mail.outbox[0].body)
109+
110+
@time_machine.travel("2025-07-13 14:56")
111+
def test_signup_chore_not_found(self):
112+
self.client.login(email=self.user.email, password="testpassword")
113+
url = reverse("signup_chore", args=[9999, 1753041600])
114+
response = self.client.get(url)
115+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
116+
self.assertIn("Chore not found", response.content.decode())
117+
118+
@time_machine.travel("2025-07-13 14:56")
119+
def test_signup_double(self):
120+
chore = self.create_chore()
121+
ts = 1753041600
122+
ChoreVolunteer.objects.create(user=self.user, chore=chore, timestamp=ts)
123+
self.client.login(email=self.user.email, password="testpassword")
124+
url = reverse("signup_chore", args=[chore.id, ts])
125+
response = self.client.get(url)
126+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
127+
# Should not create duplicate
128+
self.assertEqual(
129+
ChoreVolunteer.objects.filter(
130+
user=self.user, chore=chore, timestamp=ts
131+
).count(),
132+
2,
133+
)
134+
135+
@time_machine.travel("2025-07-13 14:56")
136+
def test_signup_requires_login(self):
137+
chore = self.create_chore()
138+
ts = 1753041600
139+
url = reverse("signup_chore", args=[chore.id, ts])
140+
response = self.client.get(url)
141+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
142+
self.assertIn("/login/", response.url)
143+
144+
@time_machine.travel("2025-07-13 14:56")
145+
def test_remove_signup_success(self):
146+
chore = self.create_chore()
147+
ts = 1753041600
148+
ChoreVolunteer.objects.create(user=self.user, chore=chore, timestamp=ts)
149+
self.client.login(email=self.user.email, password="testpassword")
150+
url = reverse("remove_signup_chore", args=[chore.id, ts])
151+
response = self.client.get(url + "?redirect_to=chores")
152+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
153+
self.assertIn("/chores", response.url)
154+
self.assertFalse(
155+
ChoreVolunteer.objects.filter(
156+
user=self.user, chore=chore, timestamp=ts
157+
).exists()
158+
)
159+
self.assertEqual(len(mail.outbox), 1)
160+
self.assertIn("can no longer volunteer", mail.outbox[0].body)
161+
162+
@time_machine.travel("2025-07-13 14:56")
163+
def test_remove_signup_chore_not_found(self):
164+
self.client.login(email=self.user.email, password="testpassword")
165+
url = reverse("remove_signup_chore", args=[9999, 1753041600])
166+
response = self.client.get(url)
167+
self.assertEqual(response.status_code, status.HTTP_404_NOT_FOUND)
168+
self.assertIn("Chore not found", response.content.decode())
169+
170+
@time_machine.travel("2025-07-13 14:56")
171+
def test_remove_signup_not_signed_up(self):
172+
chore = self.create_chore()
173+
ts = 1753041600
174+
self.client.login(email=self.user.email, password="testpassword")
175+
url = reverse("remove_signup_chore", args=[chore.id, ts])
176+
response = self.client.get(url)
177+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
178+
self.assertFalse(
179+
ChoreVolunteer.objects.filter(
180+
user=self.user, chore=chore, timestamp=ts
181+
).exists()
182+
)
183+
self.assertEqual(len(mail.outbox), 1)
184+
self.assertIn("can no longer volunteer", mail.outbox[0].body)
166185

186+
@time_machine.travel("2025-07-13 14:56")
187+
def test_remove_signup_requires_login(self):
188+
chore = self.create_chore()
189+
ts = 1753041600
190+
url = reverse("remove_signup_chore", args=[chore.id, ts])
191+
response = self.client.get(url)
192+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
193+
self.assertIn("login/", response.url)
194+
195+
@time_machine.travel("2025-07-13 14:56")
196+
def test_index_requires_login(self):
197+
url = reverse("chores")
198+
response = self.client.get(url)
199+
self.assertEqual(response.status_code, status.HTTP_302_FOUND)
200+
self.assertIn("/login/", response.url)
201+
202+
@time_machine.travel("2025-07-13 14:56")
203+
def test_remove_me_as_volunteer_button_visible_for_volunteer(self):
204+
"""Test that the 'Remove me as volunteer' button is visible for the logged-in user who volunteered."""
205+
chore = self.create_chore()
206+
ts = 1753041600
207+
# The logged-in user volunteers for the chore
208+
ChoreVolunteer.objects.create(user=self.user, chore=chore, timestamp=ts)
209+
self.client.login(email=self.user.email, password="testpassword")
210+
url = reverse("chores")
211+
response = self.client.get(url)
212+
html = response.content.decode("utf-8")
213+
self.assertIn('data-test-hook="chores-remove-volunteer"', html)

0 commit comments

Comments
 (0)