Skip to content

Commit 1e7d550

Browse files
test: tighten clear-all role coverage and forbidden assertions
Agent-Logs-Url: https://github.com/conorheffron/booking-sys/sessions/7e55bdd1-1b0d-4689-84ca-2cf7a1be16f0 Co-authored-by: conorheffron <8218626+conorheffron@users.noreply.github.com>
1 parent 9d4c336 commit 1e7d550

3 files changed

Lines changed: 46 additions & 7 deletions

File tree

backend/hr/test_apis.py

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,11 @@ def setUp(self):
3131
password="booking-pass-123",
3232
is_staff=True
3333
)
34+
self.superuser = User.objects.create_superuser(
35+
username="booking-admin",
36+
password="booking-pass-123",
37+
email="booking-admin@example.com"
38+
)
3439
self.reservation = Reservation.objects.create(
3540
first_name="Taylor",
3641
reservation_date=date.today() + timedelta(days=1),
@@ -159,6 +164,7 @@ def test_bookings_by_id_delete_forbidden_when_anonymous(self):
159164
response = self.views.bookings_by_id(request, self.reservation.id)
160165
assert response.status_code == 403
161166
assert "signed in" in json.loads(response.content.decode())["error"]
167+
assert Reservation.objects.filter(id=self.reservation.id).exists()
162168

163169
def test_bookings_by_id_delete_404(self):
164170
"""HR Test case test_bookings_by_id_delete_404"""
@@ -326,39 +332,63 @@ def test_table_view_without_query_date_returns_future(self):
326332

327333
def test_table_view_delete_clear_all_for_staff(self):
328334
"""HR Test case test_table_view_delete_clear_all_for_staff"""
335+
Reservation.objects.create(
336+
first_name="TodayA",
337+
reservation_date=date.today(),
338+
reservation_slot="09:30:00"
339+
)
329340
Reservation.objects.create(
330341
first_name="FutureA",
331-
reservation_date=str(date.today() + timedelta(days=3)),
342+
reservation_date=date.today() + timedelta(days=3),
332343
reservation_slot="10:00:00"
333344
)
334345
Reservation.objects.create(
335346
first_name="FutureB",
336-
reservation_date=str(date.today() + timedelta(days=4)),
347+
reservation_date=date.today() + timedelta(days=4),
337348
reservation_slot="11:00:00"
338349
)
339350
Reservation.objects.create(
340351
first_name="PastA",
341-
reservation_date=str(date.today() - timedelta(days=2)),
352+
reservation_date=date.today() - timedelta(days=2),
342353
reservation_slot="09:00:00"
343354
)
355+
upcoming_count = Reservation.objects.filter(
356+
reservation_date__gte=date.today()
357+
).count()
344358
request = self.factory.delete('/api/bookings')
345359
request.user = self.staff_user
346360
response = Views.table_view(request)
347361
data = json.loads(response.content.decode())
348362
assert response.status_code == 200
349363
assert data["success"] is True
350-
assert data["deleted_count"] == 3
351-
assert Reservation.objects.filter(reservation_date__gt=date.today()).count() == 0
364+
assert data["deleted_count"] == upcoming_count
365+
assert Reservation.objects.filter(reservation_date__gte=date.today()).count() == 0
352366
assert Reservation.objects.filter(first_name="PastA").exists()
353367

354368
def test_table_view_delete_clear_all_forbidden_for_non_staff(self):
355369
"""HR Test case test_table_view_delete_clear_all_forbidden_for_non_staff"""
370+
initial_count = Reservation.objects.count()
356371
request = self.factory.delete('/api/bookings')
357372
request.user = self.auth_user
358373
response = Views.table_view(request)
359374
data = json.loads(response.content.decode())
360375
assert response.status_code == 403
361376
assert "staff or superuser" in data["error"]
377+
assert Reservation.objects.count() == initial_count
378+
379+
def test_table_view_delete_clear_all_for_superuser(self):
380+
"""HR Test case test_table_view_delete_clear_all_for_superuser"""
381+
Reservation.objects.create(
382+
first_name="FutureSuper",
383+
reservation_date=date.today() + timedelta(days=5),
384+
reservation_slot="11:30:00"
385+
)
386+
request = self.factory.delete('/api/bookings')
387+
request.user = self.superuser
388+
response = Views.table_view(request)
389+
data = json.loads(response.content.decode())
390+
assert response.status_code == 200
391+
assert data["success"] is True
362392

363393
def test_bookings_by_id_put_invalid_reservation_date(self):
364394
"""HR Test case test_bookings_by_id_put_invalid_reservation_date"""

backend/hr/views.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,10 @@ def version(cls, request:WSGIRequest):
4040

4141
@classmethod
4242
def table_view(cls, request):
43-
"""GET bookings by date request parameter or DELETE all upcoming bookings"""
43+
"""GET bookings by date request parameter.
44+
45+
DELETE clears all bookings from today onward and requires a staff/superuser account.
46+
"""
4447
if request.method == "DELETE":
4548
user = getattr(request, "user", None)
4649
if not (user and user.is_authenticated and (user.is_staff or user.is_superuser)):
@@ -50,7 +53,7 @@ def table_view(cls, request):
5053
)
5154
today = dt_date.today()
5255
deleted_count, _ = Reservation.objects.filter(
53-
reservation_date__gt=today
56+
reservation_date__gte=today
5457
).delete()
5558
return JsonResponse(
5659
{"success": True, "deleted_count": deleted_count},

frontend/src/pages/__tests__/Reservationspage.test.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,12 @@ describe("ReservationsPage", () => {
177177
render(<ReservationsPage />);
178178
await waitFor(() => expect(screen.getByText("ClearMe")).toBeInTheDocument());
179179
fireEvent.click(screen.getByRole("button", { name: /Clear all/i }));
180+
await waitFor(() =>
181+
expect((global.fetch as jest.Mock)).toHaveBeenCalledWith(
182+
"/api/bookings",
183+
expect.objectContaining({ method: "DELETE" })
184+
)
185+
);
180186
await waitFor(() => expect(screen.queryByText("ClearMe")).not.toBeInTheDocument());
181187
});
182188

0 commit comments

Comments
 (0)