From 72b423c8ad1f6f7c38c5a16aa61597ff5f9f1272 Mon Sep 17 00:00:00 2001 From: Harkamal Randhawa Date: Sun, 29 Mar 2026 21:07:14 -0600 Subject: [PATCH] Add appointment tests --- .../service/AppointmentServiceTest.java | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/backend/src/test/java/com/petshop/backend/service/AppointmentServiceTest.java b/backend/src/test/java/com/petshop/backend/service/AppointmentServiceTest.java index fbc4ba4b..2a1e6eed 100644 --- a/backend/src/test/java/com/petshop/backend/service/AppointmentServiceTest.java +++ b/backend/src/test/java/com/petshop/backend/service/AppointmentServiceTest.java @@ -2,18 +2,26 @@ package com.petshop.backend.service; import com.petshop.backend.entity.Appointment; import com.petshop.backend.entity.Customer; +import com.petshop.backend.entity.Pet; import com.petshop.backend.entity.Service; import com.petshop.backend.entity.StoreLocation; +import com.petshop.backend.entity.User; import com.petshop.backend.repository.AppointmentRepository; import com.petshop.backend.repository.CustomerRepository; +import com.petshop.backend.repository.PetRepository; import com.petshop.backend.repository.ServiceRepository; import com.petshop.backend.repository.StoreRepository; +import com.petshop.backend.repository.UserRepository; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; import java.time.LocalDate; import java.time.LocalTime; @@ -21,8 +29,10 @@ import java.util.List; import java.util.Optional; import java.util.Set; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.any; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) @@ -34,12 +44,18 @@ class AppointmentServiceTest { @Mock private CustomerRepository customerRepository; + @Mock + private PetRepository petRepository; + @Mock private ServiceRepository serviceRepository; @Mock private StoreRepository storeRepository; + @Mock + private UserRepository userRepository; + @InjectMocks private AppointmentService appointmentService; @@ -47,6 +63,7 @@ class AppointmentServiceTest { private StoreLocation store; private Service grooming; private Service nailTrim; + private Pet pet; private LocalDate date; @BeforeEach @@ -70,7 +87,17 @@ class AppointmentServiceTest { nailTrim.setServiceName("Nail Trim"); nailTrim.setServiceDuration(30); + pet = new Pet(); + pet.setPetId(1L); + pet.setPetName("Milo"); + date = LocalDate.now().plusDays(1); + + } + + @AfterEach + void tearDown() { + SecurityContextHolder.clearContext(); } @Test @@ -97,6 +124,58 @@ class AppointmentServiceTest { assertFalse(slots.contains("10:00")); } + @Test + void cancelledAppointmentsDoNotBlockAvailability() { + when(storeRepository.findById(1L)).thenReturn(Optional.of(store)); + when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming)); + when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of()); + + List slots = appointmentService.checkAvailability(1L, 1L, date); + + assertTrue(slots.contains("10:00")); + } + + @Test + void updateAppointmentDoesNotConflictWithItself() { + Appointment existing = appointment(1L, date, LocalTime.of(10, 0), grooming, store); + User user = new User(); + user.setId(10L); + user.setUsername("pat"); + user.setRole(User.Role.CUSTOMER); + user.setTokenVersion(0); + when(userRepository.findById(10L)).thenReturn(Optional.of(user)); + + SecurityContextHolder.getContext().setAuthentication( + new UsernamePasswordAuthenticationToken( + new com.petshop.backend.security.AppPrincipal(10L, "pat", User.Role.CUSTOMER, 0), + "n/a", + List.of(new SimpleGrantedAuthority("ROLE_CUSTOMER")) + ) + ); + + when(appointmentRepository.findById(1L)).thenReturn(Optional.of(existing)); + when(customerRepository.findById(1L)).thenReturn(Optional.of(customer)); + when(storeRepository.findById(1L)).thenReturn(Optional.of(store)); + when(serviceRepository.findById(1L)).thenReturn(Optional.of(grooming)); + when(petRepository.findById(1L)).thenReturn(Optional.of(pet)); + when(appointmentRepository.findByStoreAndDate(1L, date)).thenReturn(List.of(existing)); + when(appointmentRepository.save(any(Appointment.class))).thenAnswer(invocation -> invocation.getArgument(0)); + + var request = new com.petshop.backend.dto.appointment.AppointmentRequest(); + request.setCustomerId(1L); + request.setStoreId(1L); + request.setServiceId(1L); + request.setAppointmentDate(date); + request.setAppointmentTime(LocalTime.of(10, 0)); + request.setAppointmentStatus("Booked"); + request.setPetIds(List.of(1L)); + + var response = appointmentService.updateAppointment(1L, request); + + assertEquals(1L, response.getAppointmentId()); + assertEquals("Booked", response.getAppointmentStatus()); + } + private Appointment appointment(Long id, LocalDate date, LocalTime time, Service service, StoreLocation storeLocation) { Appointment appointment = new Appointment(); appointment.setAppointmentId(id);