Skip to content

Commit 7f6dfda

Browse files
committed
[Test] #29 프로필 및 온보딩 API 테스트 추가
1 parent f8e3d06 commit 7f6dfda

1 file changed

Lines changed: 219 additions & 0 deletions

File tree

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
package com.leets7th.job_is_be.domain.user.controller;
2+
3+
import com.leets7th.job_is_be.domain.job.entity.JobCategory;
4+
import com.leets7th.job_is_be.domain.job.entity.Region;
5+
import com.leets7th.job_is_be.domain.job.repository.JobCategoryRepository;
6+
import com.leets7th.job_is_be.domain.job.repository.RegionRepository;
7+
import com.leets7th.job_is_be.domain.user.entity.User;
8+
import com.leets7th.job_is_be.domain.user.enums.SocialType;
9+
import com.leets7th.job_is_be.domain.user.repository.UserRepository;
10+
import org.junit.jupiter.api.BeforeEach;
11+
import org.junit.jupiter.api.Test;
12+
import org.springframework.beans.factory.annotation.Autowired;
13+
import org.springframework.boot.test.context.SpringBootTest;
14+
import org.springframework.boot.webmvc.test.autoconfigure.AutoConfigureMockMvc;
15+
import org.springframework.http.MediaType;
16+
import org.springframework.test.context.ActiveProfiles;
17+
import org.springframework.test.web.servlet.MockMvc;
18+
import org.springframework.transaction.annotation.Transactional;
19+
20+
import java.util.ArrayList;
21+
import java.util.List;
22+
23+
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.jwt;
24+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
25+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
26+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
27+
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
28+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
29+
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
30+
31+
@SpringBootTest
32+
@AutoConfigureMockMvc
33+
@ActiveProfiles("test")
34+
@Transactional
35+
class ProfileControllerIntegrationTest {
36+
37+
@Autowired
38+
private MockMvc mockMvc;
39+
@Autowired
40+
private UserRepository userRepository;
41+
@Autowired
42+
private JobCategoryRepository jobCategoryRepository;
43+
@Autowired
44+
private RegionRepository regionRepository;
45+
46+
private Long userId;
47+
private List<Long> jobCategoryIds;
48+
private Long regionId;
49+
50+
@BeforeEach
51+
void setUp() {
52+
User user = userRepository.save(User.builder()
53+
.socialId("profile-test-social-id")
54+
.socialType(SocialType.KAKAO)
55+
.email("profile-test@example.com")
56+
.build());
57+
userId = user.getId();
58+
59+
jobCategoryIds = new ArrayList<>();
60+
for (int index = 1; index <= 4; index++) {
61+
JobCategory category = jobCategoryRepository.save(JobCategory.builder()
62+
.name("직무 " + index)
63+
.sortOrder(index)
64+
.build());
65+
jobCategoryIds.add(category.getId());
66+
}
67+
Region region = regionRepository.save(Region.builder()
68+
.name("서울 전체")
69+
.sortOrder(1)
70+
.build());
71+
regionId = region.getId();
72+
}
73+
74+
@Test
75+
void supportsDraftCompletionQueryAndUpdateFlow() throws Exception {
76+
mockMvc.perform(get("/api/profile/draft").with(userJwt()))
77+
.andExpect(status().isOk())
78+
.andExpect(jsonPath("$.code").value("PROFILE_200_3"))
79+
.andExpect(jsonPath("$.data").doesNotExist());
80+
81+
mockMvc.perform(put("/api/profile/draft")
82+
.with(userJwt())
83+
.contentType(MediaType.APPLICATION_JSON)
84+
.content("""
85+
{
86+
"onboardingStep": "PROFILE",
87+
"jobCategoryIds": [%d],
88+
"primaryJobCategoryId": %d,
89+
"regionId": null,
90+
"careerLevel": null,
91+
"preferenceNotes": ["원격 가능"],
92+
"excludeKeywords": [],
93+
"techStacks": ["Java"]
94+
}
95+
""".formatted(jobCategoryIds.get(0), jobCategoryIds.get(0))))
96+
.andExpect(status().isOk())
97+
.andExpect(jsonPath("$.data.onboardingStep").value("PROFILE"))
98+
.andExpect(jsonPath("$.data.region").doesNotExist())
99+
.andExpect(jsonPath("$.data.careerLevel").doesNotExist());
100+
101+
mockMvc.perform(put("/api/profile/draft")
102+
.with(userJwt())
103+
.contentType(MediaType.APPLICATION_JSON)
104+
.content("""
105+
{
106+
"onboardingStep": "REVIEW",
107+
"jobCategoryIds": [%d, %d],
108+
"primaryJobCategoryId": %d,
109+
"regionId": %d,
110+
"careerLevel": "ENTRY",
111+
"preferenceNotes": ["원격 가능", "정규직 우선"],
112+
"excludeKeywords": ["야간 근무"],
113+
"techStacks": ["Java", "Spring"]
114+
}
115+
""".formatted(
116+
jobCategoryIds.get(0),
117+
jobCategoryIds.get(1),
118+
jobCategoryIds.get(0),
119+
regionId
120+
)))
121+
.andExpect(status().isOk())
122+
.andExpect(jsonPath("$.data.onboardingStep").value("REVIEW"))
123+
.andExpect(jsonPath("$.data.jobCategories.length()").value(2))
124+
.andExpect(jsonPath("$.data.jobCategories[0].primary").value(true))
125+
.andExpect(jsonPath("$.data.region.name").value("서울 전체"));
126+
127+
mockMvc.perform(post("/api/profile/onboarding/complete").with(userJwt()))
128+
.andExpect(status().isOk())
129+
.andExpect(jsonPath("$.code").value("PROFILE_200_5"));
130+
131+
mockMvc.perform(get("/api/profile").with(userJwt()))
132+
.andExpect(status().isOk())
133+
.andExpect(jsonPath("$.data.userId").value(userId))
134+
.andExpect(jsonPath("$.data.onboardingCompleted").value(true))
135+
.andExpect(jsonPath("$.data.preferenceNotes[0]").value("원격 가능"));
136+
137+
mockMvc.perform(patch("/api/profile")
138+
.with(userJwt())
139+
.contentType(MediaType.APPLICATION_JSON)
140+
.content("""
141+
{
142+
"preferenceNotes": [],
143+
"excludeKeywords": ["주말 근무"],
144+
"techStacks": ["Kotlin"]
145+
}
146+
"""))
147+
.andExpect(status().isOk())
148+
.andExpect(jsonPath("$.code").value("PROFILE_200_2"))
149+
.andExpect(jsonPath("$.data.preferenceNotes").isEmpty())
150+
.andExpect(jsonPath("$.data.excludeKeywords[0]").value("주말 근무"))
151+
.andExpect(jsonPath("$.data.techStacks[0]").value("Kotlin"));
152+
}
153+
154+
@Test
155+
void rejectsCompletionWhenRequiredValuesAreMissing() throws Exception {
156+
mockMvc.perform(put("/api/profile/draft")
157+
.with(userJwt())
158+
.contentType(MediaType.APPLICATION_JSON)
159+
.content("""
160+
{
161+
"onboardingStep": "REVIEW",
162+
"jobCategoryIds": [],
163+
"primaryJobCategoryId": null,
164+
"regionId": null,
165+
"careerLevel": null
166+
}
167+
"""))
168+
.andExpect(status().isOk());
169+
170+
mockMvc.perform(post("/api/profile/onboarding/complete").with(userJwt()))
171+
.andExpect(status().isBadRequest())
172+
.andExpect(jsonPath("$.code").value("PROFILE_400_5"));
173+
}
174+
175+
@Test
176+
void rejectsMoreThanThreeJobCategories() throws Exception {
177+
mockMvc.perform(put("/api/profile/draft")
178+
.with(userJwt())
179+
.contentType(MediaType.APPLICATION_JSON)
180+
.content("""
181+
{
182+
"onboardingStep": "PROFILE",
183+
"jobCategoryIds": [%d, %d, %d, %d],
184+
"primaryJobCategoryId": %d
185+
}
186+
""".formatted(
187+
jobCategoryIds.get(0),
188+
jobCategoryIds.get(1),
189+
jobCategoryIds.get(2),
190+
jobCategoryIds.get(3),
191+
jobCategoryIds.get(0)
192+
)))
193+
.andExpect(status().isBadRequest())
194+
.andExpect(jsonPath("$.code").value("PROFILE_400_2"));
195+
}
196+
197+
@Test
198+
void profileEndpointRejectsIncompleteDraft() throws Exception {
199+
mockMvc.perform(put("/api/profile/draft")
200+
.with(userJwt())
201+
.contentType(MediaType.APPLICATION_JSON)
202+
.content("""
203+
{
204+
"onboardingStep": "PROFILE",
205+
"jobCategoryIds": [],
206+
"primaryJobCategoryId": null
207+
}
208+
"""))
209+
.andExpect(status().isOk());
210+
211+
mockMvc.perform(get("/api/profile").with(userJwt()))
212+
.andExpect(status().isNotFound())
213+
.andExpect(jsonPath("$.code").value("PROFILE_404_1"));
214+
}
215+
216+
private org.springframework.test.web.servlet.request.RequestPostProcessor userJwt() {
217+
return jwt().jwt(token -> token.subject(userId.toString()));
218+
}
219+
}

0 commit comments

Comments
 (0)