diff --git a/bootstrap/src/test/java/gohigher/acceptance/ApplicationAcceptanceTest.java b/bootstrap/src/test/java/gohigher/acceptance/ApplicationAcceptanceTest.java index b47ae999..a8c35558 100644 --- a/bootstrap/src/test/java/gohigher/acceptance/ApplicationAcceptanceTest.java +++ b/bootstrap/src/test/java/gohigher/acceptance/ApplicationAcceptanceTest.java @@ -44,6 +44,31 @@ void findAllByUserId_application() { .body("success", equalTo(true)); } + @DisplayName("지원서 모아보기 기능을 종료 여부 필터링에 해당되는 경우 테스트한다.") + @Test + void findAllByUserId_application_filter_completed() { + // given + int page = 1; + int size = 10; + String sort = "processType"; + String accessToken = signUp("azpi@email.com", Provider.GOOGLE); + assignDesiredPositions(accessToken); + SimpleApplicationRequest simpleApplicationRequest = new SimpleApplicationRequest("카카오", "개발자", null, + new SimpleApplicationProcessRequest("TO_APPLY", "서류전형", null)); + post(accessToken, "/v1/applications/simple", simpleApplicationRequest); + + String uri = String.format( + "%s?page=%d&size=%d&sort=%s&completed=%s", "/v1/applications", page, size, sort, "false"); + + // when + ValidatableResponse response = get(accessToken, uri); + + // then + response.statusCode(HttpStatus.OK.value()) + .body("success", equalTo(true)) + .body("data.content.size()", is(1)); + } + @DisplayName("지원서를 작성하는 기능을 테스트한다") @Test void create_application() { diff --git a/core-application/src/main/java/gohigher/application/port/in/MyApplicationResponse.java b/core-application/src/main/java/gohigher/application/port/in/MyApplicationResponse.java index a1174d4b..b4158e62 100644 --- a/core-application/src/main/java/gohigher/application/port/in/MyApplicationResponse.java +++ b/core-application/src/main/java/gohigher/application/port/in/MyApplicationResponse.java @@ -9,19 +9,21 @@ @RequiredArgsConstructor public class MyApplicationResponse { - private final long applicationId; - private final String companyName; - private final String position; - private final String specificPosition; - private final ProcessResponse process; + private final long applicationId; + private final String companyName; + private final String position; + private final String specificPosition; + private final Boolean isCompleted; + private final ProcessResponse process; - public static MyApplicationResponse of(Application application, Process process) { - return new MyApplicationResponse( - application.getId(), - application.getCompanyName(), - application.getPosition(), - application.getSpecificPosition(), - ProcessResponse.from(process) - ); - } + public static MyApplicationResponse of(Application application, Process process) { + return new MyApplicationResponse( + application.getId(), + application.getCompanyName(), + application.getPosition(), + application.getSpecificPosition(), + application.isCompleted(), + ProcessResponse.from(process) + ); + } } diff --git a/core-domain/src/main/java/gohigher/common/ProcessType.java b/core-domain/src/main/java/gohigher/common/ProcessType.java index a7d492cf..79143511 100644 --- a/core-domain/src/main/java/gohigher/common/ProcessType.java +++ b/core-domain/src/main/java/gohigher/common/ProcessType.java @@ -24,6 +24,10 @@ public static ProcessType from(String value) { } public static List from(List values) { + if (values == null) { + return null; + } + return values.stream() .map(ProcessType::from) .toList(); diff --git a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepository.java b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepository.java index dc100bac..cd96e09e 100644 --- a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepository.java +++ b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepository.java @@ -27,7 +27,8 @@ public interface ApplicationRepository extends JpaRepository findByUserIdAndMonth(Long userId, int year, int month); @Query("SELECT a FROM ApplicationJpaEntity a " @@ -35,7 +36,8 @@ public interface ApplicationRepository extends JpaRepository= :startOfDate " - + "AND p.schedule < :endOfDate") + + "AND p.schedule < :endOfDate " + + "AND a.isCompleted = false") List findByUserIdAndDate(Long userId, LocalDateTime startOfDate, LocalDateTime endOfDate); @Query("SELECT a FROM ApplicationJpaEntity a " @@ -43,14 +45,16 @@ public interface ApplicationRepository extends JpaRepository findUnscheduledByUserId(Long userId, Pageable pageable); @Query("SELECT a FROM ApplicationJpaEntity a " + "JOIN FETCH a.processes p " + "WHERE a.userId = :userId " + "AND p.isCurrent = true " - + "AND a.deleted = false") + + "AND a.deleted = false " + + "AND a.isCompleted = false") List findOnlyWithCurrentProcessByUserId(Long userId); @Query("SELECT a FROM ApplicationJpaEntity a " @@ -58,6 +62,7 @@ public interface ApplicationRepository extends JpaRepository findOnlyCurrentProcessByUserIdAndProcessType(Long userId, ProcessType processType); } diff --git a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepositoryCustomImpl.java b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepositoryCustomImpl.java index f8881ead..f5a49897 100644 --- a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepositoryCustomImpl.java +++ b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/ApplicationRepositoryCustomImpl.java @@ -1,7 +1,7 @@ package gohigher.application.entity; -import static gohigher.application.entity.QApplicationJpaEntity.applicationJpaEntity; -import static gohigher.application.entity.QApplicationProcessJpaEntity.applicationProcessJpaEntity; +import static gohigher.application.entity.QApplicationJpaEntity.*; +import static gohigher.application.entity.QApplicationProcessJpaEntity.*; import java.util.List; import java.util.stream.Collectors; @@ -24,96 +24,106 @@ @RequiredArgsConstructor public class ApplicationRepositoryCustomImpl implements ApplicationRepositoryCustom { - private final JPAQueryFactory jpaQueryFactory; - - @Override - public Slice findAllByUserId(Long userId, Pageable pageable, ApplicationSortingType sortingType, - List process, List completed, String companyName) { - - JPAQuery query = jpaQueryFactory - .select(Projections.bean( - ProcessWithApplicationResponse.class, - applicationJpaEntity.id.as("applicationId"), - applicationJpaEntity.companyName, - applicationJpaEntity.position, - applicationJpaEntity.specificPosition, - applicationProcessJpaEntity.id.as("processId"), - applicationProcessJpaEntity.type, - applicationProcessJpaEntity.description, - applicationProcessJpaEntity.schedule - )) - .from(applicationProcessJpaEntity) - .join(applicationProcessJpaEntity.application, applicationJpaEntity) - .where( - eqUserId(userId), - applicationProcessJpaEntity.application.deleted.eq(false), - applicationProcessJpaEntity.isCurrent.eq(true), - inProcessType(process), - containsCompanyName(companyName) - ) - .offset(pageable.getOffset()) - .limit(pageable.getPageSize() + 1) - .orderBy(selectOrderSpecifierAboutFindAll(sortingType)) - ; - - List applications = convertToApplicationJpaEntity(query); - - boolean hasNext = applications.size() > pageable.getPageSize(); - if (hasNext) { - applications.remove(applications.size() - 1); - } - - return new SliceImpl<>(applications, pageable, hasNext); - } - - private BooleanExpression containsCompanyName(String companyName) { - if (companyName == null) { - companyName = ""; - } - return applicationProcessJpaEntity.application.companyName.contains(companyName); - } - - private BooleanExpression eqUserId(Long userId) { - if (userId == null) { - return applicationProcessJpaEntity.application.userId.isNull(); - } - return applicationProcessJpaEntity.application.userId.eq(userId); - } - - private BooleanExpression inProcessType(List process) { - if (process.isEmpty()) { - return null; - } - return applicationProcessJpaEntity.type.in(process); - } - - private OrderSpecifier selectOrderSpecifierAboutFindAll(ApplicationSortingType sortingType) { - return switch (sortingType) { - case CREATED -> applicationProcessJpaEntity.id.desc(); - case PROCESS_TYPE -> applicationProcessJpaEntity.schedule.asc(); - case REVERSE_PROCESS_TYPE -> applicationProcessJpaEntity.schedule.desc(); - case CLOSING -> applicationProcessJpaEntity.id.asc(); - }; - } - - private List convertToApplicationJpaEntity(JPAQuery query) { - return query.fetch().stream() - .map(processResponse -> - ApplicationJpaEntity.builder() - .id(processResponse.getApplicationId()) - .companyName(processResponse.getCompanyName()) - .position(processResponse.getPosition()) - .specificPosition(processResponse.getSpecificPosition()) - .processes( - List.of( - ApplicationProcessJpaEntity.builder() - .id(processResponse.getProcessId()) - .type(processResponse.getType()) - .description(processResponse.getDescription()) - .schedule(processResponse.getSchedule()) - .build()) - ) - .build()) - .collect(Collectors.toList()); - } + private final JPAQueryFactory jpaQueryFactory; + + @Override + public Slice findAllByUserId(Long userId, Pageable pageable, + ApplicationSortingType sortingType, + List process, List completed, String companyName) { + + JPAQuery query = jpaQueryFactory + .select(Projections.bean( + ProcessWithApplicationResponse.class, + applicationJpaEntity.id.as("applicationId"), + applicationJpaEntity.companyName, + applicationJpaEntity.position, + applicationJpaEntity.specificPosition, + applicationProcessJpaEntity.id.as("processId"), + applicationProcessJpaEntity.type, + applicationProcessJpaEntity.description, + applicationProcessJpaEntity.schedule, + applicationJpaEntity.isCompleted + )) + .from(applicationProcessJpaEntity) + .join(applicationProcessJpaEntity.application, applicationJpaEntity) + .where( + eqUserId(userId), + applicationProcessJpaEntity.application.deleted.eq(false), + applicationProcessJpaEntity.isCurrent.eq(true), + inProcessType(process), + inCompleted(completed), + containsCompanyName(companyName) + ) + .offset(pageable.getOffset()) + .limit(pageable.getPageSize() + 1) + .orderBy(selectOrderSpecifierAboutFindAll(sortingType)); + + List applications = convertToApplicationJpaEntity(query); + + boolean hasNext = applications.size() > pageable.getPageSize(); + if (hasNext) { + applications.remove(applications.size() - 1); + } + + return new SliceImpl<>(applications, pageable, hasNext); + } + + private BooleanExpression inCompleted(List completed) { + if (completed == null || completed.isEmpty()) { + return null; + } + return applicationJpaEntity.isCompleted.in(completed); + } + + private BooleanExpression containsCompanyName(String companyName) { + if (companyName == null) { + companyName = ""; + } + return applicationProcessJpaEntity.application.companyName.contains(companyName); + } + + private BooleanExpression eqUserId(Long userId) { + if (userId == null) { + return applicationProcessJpaEntity.application.userId.isNull(); + } + return applicationProcessJpaEntity.application.userId.eq(userId); + } + + private BooleanExpression inProcessType(List process) { + if (process == null || process.isEmpty()) { + return null; + } + return applicationProcessJpaEntity.type.in(process); + } + + private OrderSpecifier selectOrderSpecifierAboutFindAll(ApplicationSortingType sortingType) { + return switch (sortingType) { + case CREATED -> applicationProcessJpaEntity.id.desc(); + case PROCESS_TYPE -> applicationProcessJpaEntity.schedule.asc(); + case REVERSE_PROCESS_TYPE -> applicationProcessJpaEntity.schedule.desc(); + case CLOSING -> applicationProcessJpaEntity.id.asc(); + }; + } + + private List convertToApplicationJpaEntity(JPAQuery query) { + return query.fetch().stream() + .map(processResponse -> + ApplicationJpaEntity.builder() + .id(processResponse.getApplicationId()) + .companyName(processResponse.getCompanyName()) + .position(processResponse.getPosition()) + .specificPosition(processResponse.getSpecificPosition()) + .isCompleted(processResponse.isCompleted()) + .processes( + List.of( + ApplicationProcessJpaEntity.builder() + .id(processResponse.getProcessId()) + .type(processResponse.getType()) + .description(processResponse.getDescription()) + .schedule(processResponse.getSchedule()) + .build()) + ) + .build()) + .collect(Collectors.toList()); + } } diff --git a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/dto/response/ProcessWithApplicationResponse.java b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/dto/response/ProcessWithApplicationResponse.java index acd89e23..06d07f7b 100644 --- a/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/dto/response/ProcessWithApplicationResponse.java +++ b/out-adapter-persistence-jpa/src/main/java/gohigher/application/entity/dto/response/ProcessWithApplicationResponse.java @@ -12,12 +12,13 @@ @NoArgsConstructor public class ProcessWithApplicationResponse { - private long applicationId; - private String companyName; - private String position; - private String specificPosition; - private long processId; - private ProcessType type; - private String description; - private LocalDateTime schedule; + private long applicationId; + private String companyName; + private String position; + private String specificPosition; + private long processId; + private ProcessType type; + private String description; + private LocalDateTime schedule; + private boolean isCompleted; } diff --git a/out-adapter-persistence-jpa/src/test/java/gohigher/application/entity/ApplicationRepositoryCustomImplTest.java b/out-adapter-persistence-jpa/src/test/java/gohigher/application/entity/ApplicationRepositoryCustomImplTest.java index cb77ba23..c23c26e1 100644 --- a/out-adapter-persistence-jpa/src/test/java/gohigher/application/entity/ApplicationRepositoryCustomImplTest.java +++ b/out-adapter-persistence-jpa/src/test/java/gohigher/application/entity/ApplicationRepositoryCustomImplTest.java @@ -1,15 +1,10 @@ package gohigher.application.entity; -import static gohigher.application.ApplicationFixture.COUPANG_APPLICATION; -import static gohigher.application.ApplicationFixture.KAKAO_APPLICATION; -import static gohigher.application.ApplicationFixture.LINE_APPLICATION; -import static gohigher.application.ApplicationFixture.NAVER_APPLICATION; -import static gohigher.application.ProcessFixture.DOCUMENT; -import static gohigher.application.ProcessFixture.TEST; -import static gohigher.fixtureConverter.ApplicationFixtureConverter.convertToApplicationEntity; -import static gohigher.fixtureConverter.ApplicationFixtureConverter.convertToApplicationProcessEntity; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertAll; +import static gohigher.application.ApplicationFixture.*; +import static gohigher.application.ProcessFixture.*; +import static gohigher.fixtureConverter.ApplicationFixtureConverter.*; +import static org.assertj.core.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.*; import java.time.LocalDateTime; import java.util.List; @@ -32,245 +27,273 @@ @JpaQueryTest class ApplicationRepositoryCustomImplTest { - @Autowired - private ApplicationRepositoryCustomImpl applicationRepositoryCustom; - - @Autowired - private ApplicationRepository applicationRepository; - - @Autowired - private ApplicationProcessRepository applicationProcessRepository; - - @DisplayName("findAllByUserId 메소드는") - @Nested - class Describe_findAllByUserId { - - private final LocalDateTime today = LocalDateTime.now(); - private final LocalDateTime yesterday = today.minusDays(1); - private final LocalDateTime tomorrow = today.plusDays(1); - - private final Long userId = 0L; - private final PageRequest pageRequest = PageRequest.of(0, 10); - - private ApplicationJpaEntity naverApplicationEntity; - private ApplicationJpaEntity kakaoApplicationEntity; - private ApplicationJpaEntity coupangApplicationEntity; - - @BeforeEach - void setUp() { - Application naverApplication = NAVER_APPLICATION.toDomain(TEST.toDomainWithSchedule(yesterday)); - naverApplicationEntity = saveApplicationAndProcesses(userId, naverApplication); - - Application kakoaApplication = KAKAO_APPLICATION.toDomain(TEST.toDomainWithSchedule(tomorrow)); - kakaoApplicationEntity = saveApplicationAndProcesses(userId, kakoaApplication); - - Application coupangApplication = COUPANG_APPLICATION.toDomain(TEST.toDomainWithSchedule(today)); - coupangApplicationEntity = saveApplicationAndProcesses(userId, coupangApplication); - } - - @DisplayName("조회를 요청할 경우") - @Nested - class Context_request { - - @DisplayName("삭제되지 않은 현재 프로세스 전형을 조회한다.") - @Test - void it_returns_processes() { - Application deletedApplication = LINE_APPLICATION.toDomain(); - ApplicationJpaEntity deletedApplicationJpaEntity = saveApplicationAndProcesses(userId, deletedApplication); - deletedApplicationJpaEntity.delete(); - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, ApplicationSortingType.CREATED, List.of(), List.of(), null); - - assertAll( - () -> assertThat(applications.getContent()).hasSizeGreaterThan(1), - () -> assertThat(applications.getContent().get(0).getProcesses()).hasSize(1), - () -> assertThat(applications.getContent()).doesNotContain(deletedApplicationJpaEntity) - ); - } - } - - @DisplayName("정렬 기준을 생략할 경우") - @Nested - class Context_without_scheduled { - - @DisplayName("지원서를 작성한 순서대로 조회한다.") - @Test - void it_returns_desc_id() { - ApplicationSortingType sortingType = ApplicationSortingType.CREATED; - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, sortingType, List.of(), List.of(), null); - - assertAll( - () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), - () -> assertThat(applications.getContent().get(0).getId()).isEqualTo(coupangApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(1).getId()).isEqualTo(kakaoApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(naverApplicationEntity.getId()) - ); - } - } - - @DisplayName("정렬 기준이 '전형순' 일 경우") - @Nested - class Context_with_scheduled { - - @DisplayName("전형일 오름차순으로 정렬되어 조회한다.") - @Test - void it_returns_asc_scheduled() { - ApplicationSortingType sortingType = ApplicationSortingType.PROCESS_TYPE; - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, sortingType, List.of(), List.of(), null); - - assertAll( - () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), - () -> assertThat(applications.getContent().get(0).getId()).isEqualTo(naverApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(1).getId()).isEqualTo(coupangApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(kakaoApplicationEntity.getId()) - ); - } - } - - @DisplayName("정렬 기준이 '전형역순' 일 경우") - @Nested - class Context_with_re_scheduled { - - @DisplayName("전형일 내림차순으로 정렬되어 조회한다.") - @Test - void it_returns_desc_scheduled() { - ApplicationSortingType sortingType = ApplicationSortingType.REVERSE_PROCESS_TYPE; - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, sortingType, List.of(), List.of(), null); - - assertAll( - () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), - () -> assertThat(applications.getContent().get(0).getId()).isEqualTo(kakaoApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(1).getId()).isEqualTo(coupangApplicationEntity.getId()), - () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(naverApplicationEntity.getId()) - ); - } - } - - // @DisplayName("정렬 기준이 '마감임박순' 일 경우") - // @Nested - // class Context_with_closing { - // - // @DisplayName("마감일이 가까운 순으로 정렬되어 조회한다.") - // @Test - // void it_returns_asc_deadline() { - // ApplicationSortingType sortingType = ApplicationSortingType.CLOSING; - // - // Slice applications = applicationRepositoryCustom.findAllByUserId( - // userId, pageRequest, sortingType, null, null, null); - // - // assertAll( - // () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), - // () -> assertThat(applications.getContent().get(0).getCompanyName()).isEqualTo(kakaoApplicationEntity.getCompanyName()), - // () -> assertThat(applications.getContent().get(1).getCompanyName()).isEqualTo(coupangApplicationEntity.getCompanyName()), - // () -> assertThat(applications.getContent().get(2).getCompanyName()).isEqualTo(naverApplicationEntity.getCompanyName()) - // ); - // } - // } - - @DisplayName("전형별로 보기 필터링을 선택하지 않을 경우") - @Nested - class Context_without_process_filter { - - @DisplayName("전체 항목을 조회한다.") - @Test - void it_returns_all_applications() { - List processTypes = List.of(); - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, ApplicationSortingType.CREATED, processTypes, List.of(), null); - - List ids = applications.getContent().stream() - .map(ApplicationJpaEntity::getId) - .toList(); - assertAll( - () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), - () -> assertThat(ids).contains(naverApplicationEntity.getId(), kakaoApplicationEntity.getId(), coupangApplicationEntity.getId()) - ); - } - } - - @DisplayName("전형별로 보기 필터링을 선택할 경우") - @Nested - class Context_with_process_filter { - - @DisplayName("선택된 전형 목록만 조회한다.") - @Test - void it_returns_selected_applications() { - List processTypes = List.of(ProcessType.DOCUMENT); - Application naverApplication = NAVER_APPLICATION.toDomain(DOCUMENT.toDomain()); - ApplicationJpaEntity applicationJpaEntity = saveApplicationAndProcesses(userId, naverApplication); - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, ApplicationSortingType.CREATED, processTypes, List.of(), null); - - List ids = applications.getContent().stream() - .map(ApplicationJpaEntity::getId) - .toList(); - assertThat(ids).contains(applicationJpaEntity.getId()); - } - } - - @DisplayName("종료된 전형 필터링을 선택하지 않을 경우") - @Nested - class Context_without_scheduled_filter { - - @DisplayName("전체 항목을 조회한다.") - @Test - void it_returns_all_applications() { - - } - } - - @DisplayName("종료된 전형 필터링을 선택할 경우") - @Nested - class Context_with_scheduled_filter { - - @DisplayName("선택된 전형 목록만 조회한다.") - @Test - void it_returns_selected_applications() { - - } - } - - @DisplayName("회사명을 검색할 경우") - @Nested - class Context_with_searching_company_name { - - @DisplayName("해당 회사명을 가지는 전형 목록만 조회한다.") - @Test - void it_returns_contained_applications_company_name() { - String companyName = naverApplicationEntity.getCompanyName(); - - Slice applications = applicationRepositoryCustom.findAllByUserId( - userId, pageRequest, ApplicationSortingType.CREATED, List.of(), List.of(), companyName); - - List ids = applications.getContent().stream() - .map(ApplicationJpaEntity::getId) - .toList(); - assertThat(ids).contains(naverApplicationEntity.getId()); - } - } - } - - public ApplicationJpaEntity saveApplicationAndProcesses(Long userId, Application application) { - ApplicationJpaEntity applicationEntity = applicationRepository.save( - convertToApplicationEntity(userId, application)); - - for (Process process : application.getProcesses()) { - ApplicationProcessJpaEntity applicationProcessJpaEntity = applicationProcessRepository.save( - convertToApplicationProcessEntity(applicationEntity, process, - application.getCurrentProcess() == process)); - - applicationEntity.addProcess(applicationProcessJpaEntity); - } - - return applicationEntity; - } + @Autowired + private ApplicationRepositoryCustomImpl applicationRepositoryCustom; + + @Autowired + private ApplicationRepository applicationRepository; + + @Autowired + private ApplicationProcessRepository applicationProcessRepository; + + @DisplayName("findAllByUserId 메소드는") + @Nested + class Describe_findAllByUserId { + + private final LocalDateTime today = LocalDateTime.now(); + private final LocalDateTime yesterday = today.minusDays(1); + private final LocalDateTime tomorrow = today.plusDays(1); + + private final Long userId = 0L; + private final PageRequest pageRequest = PageRequest.of(0, 10); + + private ApplicationJpaEntity naverApplicationEntity; + private ApplicationJpaEntity kakaoApplicationEntity; + private ApplicationJpaEntity coupangApplicationEntity; + + @BeforeEach + void setUp() { + Application naverApplication = NAVER_APPLICATION.toDomain(TEST.toDomainWithSchedule(yesterday)); + naverApplicationEntity = saveApplicationAndProcesses(userId, naverApplication); + + Application kakoaApplication = KAKAO_APPLICATION.toDomain(TEST.toDomainWithSchedule(tomorrow)); + kakaoApplicationEntity = saveApplicationAndProcesses(userId, kakoaApplication); + + Application coupangApplication = COUPANG_APPLICATION.toDomain(TEST.toDomainWithSchedule(today)); + coupangApplicationEntity = saveApplicationAndProcesses(userId, coupangApplication); + } + + @DisplayName("조회를 요청할 경우") + @Nested + class Context_request { + + @DisplayName("삭제되지 않은 현재 프로세스 전형을 조회한다.") + @Test + void it_returns_processes() { + Application deletedApplication = LINE_APPLICATION.toDomain(); + ApplicationJpaEntity deletedApplicationJpaEntity = saveApplicationAndProcesses(userId, + deletedApplication); + deletedApplicationJpaEntity.delete(); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, List.of(), List.of(), null); + + assertAll( + () -> assertThat(applications.getContent()).hasSizeGreaterThan(1), + () -> assertThat(applications.getContent().get(0).getProcesses()).hasSize(1), + () -> assertThat(applications.getContent()).doesNotContain(deletedApplicationJpaEntity) + ); + } + } + + @DisplayName("정렬 기준을 생략할 경우") + @Nested + class Context_without_scheduled { + + @DisplayName("지원서를 작성한 순서대로 조회한다.") + @Test + void it_returns_desc_id() { + ApplicationSortingType sortingType = ApplicationSortingType.CREATED; + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, sortingType, List.of(), List.of(), null); + + assertAll( + () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), + () -> assertThat(applications.getContent().get(0).getId()).isEqualTo( + coupangApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(1).getId()).isEqualTo( + kakaoApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(naverApplicationEntity.getId()) + ); + } + } + + @DisplayName("정렬 기준이 '전형순' 일 경우") + @Nested + class Context_with_scheduled { + + @DisplayName("전형일 오름차순으로 정렬되어 조회한다.") + @Test + void it_returns_asc_scheduled() { + ApplicationSortingType sortingType = ApplicationSortingType.PROCESS_TYPE; + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, sortingType, List.of(), List.of(), null); + + assertAll( + () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), + () -> assertThat(applications.getContent().get(0).getId()).isEqualTo( + naverApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(1).getId()).isEqualTo( + coupangApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(kakaoApplicationEntity.getId()) + ); + } + } + + @DisplayName("정렬 기준이 '전형역순' 일 경우") + @Nested + class Context_with_re_scheduled { + + @DisplayName("전형일 내림차순으로 정렬되어 조회한다.") + @Test + void it_returns_desc_scheduled() { + ApplicationSortingType sortingType = ApplicationSortingType.REVERSE_PROCESS_TYPE; + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, sortingType, List.of(), List.of(), null); + + assertAll( + () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), + () -> assertThat(applications.getContent().get(0).getId()).isEqualTo( + kakaoApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(1).getId()).isEqualTo( + coupangApplicationEntity.getId()), + () -> assertThat(applications.getContent().get(2).getId()).isEqualTo(naverApplicationEntity.getId()) + ); + } + } + + // @DisplayName("정렬 기준이 '마감임박순' 일 경우") + // @Nested + // class Context_with_closing { + // + // @DisplayName("마감일이 가까운 순으로 정렬되어 조회한다.") + // @Test + // void it_returns_asc_deadline() { + // ApplicationSortingType sortingType = ApplicationSortingType.CLOSING; + // + // Slice applications = applicationRepositoryCustom.findAllByUserId( + // userId, pageRequest, sortingType, null, null, null); + // + // assertAll( + // () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), + // () -> assertThat(applications.getContent().get(0).getCompanyName()).isEqualTo(kakaoApplicationEntity.getCompanyName()), + // () -> assertThat(applications.getContent().get(1).getCompanyName()).isEqualTo(coupangApplicationEntity.getCompanyName()), + // () -> assertThat(applications.getContent().get(2).getCompanyName()).isEqualTo(naverApplicationEntity.getCompanyName()) + // ); + // } + // } + + @DisplayName("전형별로 보기 필터링을 선택하지 않을 경우") + @Nested + class Context_without_process_filter { + + @DisplayName("전체 항목을 조회한다.") + @Test + void it_returns_all_applications() { + List processTypes = List.of(); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, processTypes, List.of(), null); + + List ids = applications.getContent().stream() + .map(ApplicationJpaEntity::getId) + .toList(); + assertAll( + () -> assertThat(applications.getNumberOfElements()).isEqualTo(3), + () -> assertThat(ids).contains(naverApplicationEntity.getId(), kakaoApplicationEntity.getId(), + coupangApplicationEntity.getId()) + ); + } + } + + @DisplayName("전형별로 보기 필터링을 선택할 경우") + @Nested + class Context_with_process_filter { + + @DisplayName("선택된 전형 목록만 조회한다.") + @Test + void it_returns_selected_applications() { + List processTypes = List.of(ProcessType.DOCUMENT); + Application naverApplication = NAVER_APPLICATION.toDomain(DOCUMENT.toDomain()); + ApplicationJpaEntity applicationJpaEntity = saveApplicationAndProcesses(userId, naverApplication); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, processTypes, List.of(), null); + + List ids = applications.getContent().stream() + .map(ApplicationJpaEntity::getId) + .toList(); + assertThat(ids).contains(applicationJpaEntity.getId()); + } + } + + @DisplayName("종료 여부를 선택하지 않을 경우") + @Nested + class Context_without_scheduled_filter { + + @DisplayName("전체 항목을 조회한다.") + @Test + void it_returns_all_applications() { + List completes = List.of(); + Application naverApplication = NAVER_APPLICATION.toDomain(DOCUMENT.toDomain()); + ApplicationJpaEntity applicationJpaEntity = saveApplicationAndProcesses(userId, naverApplication); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, List.of(), completes, null); + + List ids = applications.getContent().stream() + .map(ApplicationJpaEntity::getId) + .toList(); + assertThat(ids).contains(applicationJpaEntity.getId()); + } + } + + @DisplayName("종료된 전형 필터링을 선택할 경우") + @Nested + class Context_with_scheduled_filter { + + @DisplayName("선택된 전형 목록만 조회한다.") + @Test + void it_returns_selected_applications() { + List completes = List.of(true); + Application naverApplication = NAVER_APPLICATION.toDomain(DOCUMENT.toDomain()); + saveApplicationAndProcesses(userId, naverApplication); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, List.of(), completes, null); + + List ids = applications.getContent().stream() + .map(ApplicationJpaEntity::getId) + .toList(); + assertThat(ids).isEmpty(); + } + } + + @DisplayName("회사명을 검색할 경우") + @Nested + class Context_with_searching_company_name { + + @DisplayName("해당 회사명을 가지는 전형 목록만 조회한다.") + @Test + void it_returns_contained_applications_company_name() { + String companyName = naverApplicationEntity.getCompanyName(); + + Slice applications = applicationRepositoryCustom.findAllByUserId( + userId, pageRequest, ApplicationSortingType.CREATED, List.of(), List.of(), companyName); + + List ids = applications.getContent().stream() + .map(ApplicationJpaEntity::getId) + .toList(); + assertThat(ids).contains(naverApplicationEntity.getId()); + } + } + } + + public ApplicationJpaEntity saveApplicationAndProcesses(Long userId, Application application) { + ApplicationJpaEntity applicationEntity = applicationRepository.save( + convertToApplicationEntity(userId, application)); + + for (Process process : application.getProcesses()) { + ApplicationProcessJpaEntity applicationProcessJpaEntity = applicationProcessRepository.save( + convertToApplicationProcessEntity(applicationEntity, process, + application.getCurrentProcess() == process)); + + applicationEntity.addProcess(applicationProcessJpaEntity); + } + + return applicationEntity; + } }