diff --git a/src/app/mocks/browser.ts b/src/app/mocks/browser.ts index 15e01d3..e4a9dcb 100644 --- a/src/app/mocks/browser.ts +++ b/src/app/mocks/browser.ts @@ -3,12 +3,16 @@ import { setupWorker } from 'msw/browser'; import { commentHandlers } from './handler/comment'; import { feedHandlers } from './handler/feed'; import { likeHandlers } from './handler/like'; -import { userHandlers } from './handler/user'; +import { followHandler } from './handler/follow'; +import { searchHandler } from './handler/search'; +import { userHandler } from './handler/user'; // 브라우저에서 실행하기 위한 mocking worker 초기화 export const worker = setupWorker( ...commentHandlers, ...feedHandlers, ...likeHandlers, - ...userHandlers, + ...followHandler, + ...searchHandler, + ...userHandler, ); diff --git a/src/app/mocks/consts/likeUser.ts b/src/app/mocks/consts/likeUser.ts new file mode 100644 index 0000000..686e2a1 --- /dev/null +++ b/src/app/mocks/consts/likeUser.ts @@ -0,0 +1,58 @@ +import { User } from '@/shared/consts'; + +interface Users { + [userId: number]: User; +} + +export const likeUsers: Users = { + 1: { + id: 2, + profileImage: 'https://picsum.photos/200/200', + name: '이의찬', + content: 'Legitgoons', + locked: false, + feedCount: 124, + followingCount: 2, + followerCount: 5341, + }, + 2: { + id: 3, + profileImage: 'https://picsum.photos/200/200', + name: '양재서', + content: 'psychology50', + locked: true, + feedCount: 6, + followingCount: 35, + followerCount: 423, + }, + 3: { + id: 5, + profileImage: 'https://picsum.photos/200/200', + name: '신얀', + content: 'yanni13', + locked: true, + feedCount: 51, + followingCount: 7897, + followerCount: 7890, + }, + 4: { + id: 4, + profileImage: 'https://picsum.photos/200/200', + name: '이수민', + content: 'SSXXMM22', + locked: true, + feedCount: 24, + followingCount: 42, + followerCount: 53251, + }, + 5: { + id: 7, + profileImage: 'https://picsum.photos/200/200', + name: '안성윤', + content: 'asn6878', + locked: true, + feedCount: 87, + followingCount: 67, + followerCount: 4556, + }, +}; diff --git a/src/app/mocks/consts/profileFeed.ts b/src/app/mocks/consts/profileFeed.ts index 58fa834..d965049 100644 --- a/src/app/mocks/consts/profileFeed.ts +++ b/src/app/mocks/consts/profileFeed.ts @@ -9,8 +9,7 @@ interface ProfileFeeds { export const profileFeeds: ProfileFeeds = { 1: { id: 1, - title: 'Feed Title 1', - content: 'Feed Content 1', + content: 'Profile Feed Content 1', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[1].totalCount, @@ -18,8 +17,7 @@ export const profileFeeds: ProfileFeeds = { }, 2: { id: 2, - title: 'Feed Title 2', - content: 'Feed Content 2', + content: 'Profile Feed Content 2', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[2].totalCount, @@ -27,7 +25,6 @@ export const profileFeeds: ProfileFeeds = { }, 3: { id: 3, - title: 'Feed Title 3', content: 'Feed Content 3', thubnailImage: 'https://picsum.photos/200/200', @@ -36,8 +33,7 @@ export const profileFeeds: ProfileFeeds = { }, 4: { id: 4, - title: 'Feed Title 4', - content: 'Feed Content 4', + content: 'Profile Feed Content 4', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[4].totalCount, @@ -45,8 +41,7 @@ export const profileFeeds: ProfileFeeds = { }, 5: { id: 5, - title: 'Feed Title 5', - content: 'Feed Content 5', + content: 'Profile Feed Content 5', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[5].totalCount, @@ -54,8 +49,7 @@ export const profileFeeds: ProfileFeeds = { }, 6: { id: 6, - title: 'Feed Title 5', - content: 'Feed Content 5', + content: 'Profile Feed Content 5', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[6].totalCount, @@ -63,8 +57,7 @@ export const profileFeeds: ProfileFeeds = { }, 7: { id: 7, - title: 'Feed Title 7', - content: 'Feed Content 7', + content: 'Profile Feed Content 7', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[7].totalCount, @@ -72,8 +65,7 @@ export const profileFeeds: ProfileFeeds = { }, 8: { id: 8, - title: 'Feed Title 8', - content: 'Feed Content 8', + content: 'Profile Feed Content 8', thubnailImage: 'https://picsum.photos/200/200', likeCount: likes[8].totalCount, @@ -81,8 +73,7 @@ export const profileFeeds: ProfileFeeds = { }, 9: { id: 9, - title: 'Feed Title 9', - content: 'Feed Content 9', + content: 'Profile Feed Content 9', thubnailImage: '', likeCount: likes[9].totalCount, diff --git a/src/app/mocks/consts/relationshipStatus.ts b/src/app/mocks/consts/relationshipStatus.ts index e208f7f..0a0751c 100644 --- a/src/app/mocks/consts/relationshipStatus.ts +++ b/src/app/mocks/consts/relationshipStatus.ts @@ -14,5 +14,5 @@ export const relationshipStatus: Relationship = { 6: 'pending', 7: 'following', 8: 'none', - 9: 'pending', + 9: 'none', }; diff --git a/src/app/mocks/consts/user.ts b/src/app/mocks/consts/user.ts index b209313..1df37a4 100644 --- a/src/app/mocks/consts/user.ts +++ b/src/app/mocks/consts/user.ts @@ -10,6 +10,7 @@ export const users: Users = { profileImage: '', name: '강병준', content: 'bangdori', + locked: false, feedCount: 100, followingCount: 347, followerCount: 25, @@ -19,6 +20,7 @@ export const users: Users = { profileImage: '', name: '이의찬', content: 'Legitgoons', + locked: false, feedCount: 124, followingCount: 2, followerCount: 5341, @@ -28,6 +30,7 @@ export const users: Users = { profileImage: '', name: '양재서', content: 'psychology50', + locked: true, feedCount: 6, followingCount: 35, followerCount: 423, @@ -37,6 +40,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '이수민', content: 'SSXXMM22', + locked: true, feedCount: 24, followingCount: 42, followerCount: 53251, @@ -46,6 +50,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '신얀', content: 'yanni13', + locked: true, feedCount: 51, followingCount: 7897, followerCount: 7890, @@ -55,6 +60,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '이주원', content: '2weeksone', + locked: false, feedCount: 97, followingCount: 98, followerCount: 8975, @@ -64,6 +70,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '안성윤', content: 'asn6878', + locked: true, feedCount: 87, followingCount: 67, followerCount: 4556, @@ -73,6 +80,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '이진우', content: 'jinlee1703', + locked: false, feedCount: 32, followingCount: 24, followerCount: 543, @@ -82,6 +90,7 @@ export const users: Users = { profileImage: 'https://picsum.photos/32/32', name: '최희진', content: 'heejinnn', + locked: false, feedCount: 66, followingCount: 1, followerCount: 1, diff --git a/src/app/mocks/handler/follow.ts b/src/app/mocks/handler/follow.ts new file mode 100644 index 0000000..5bed3db --- /dev/null +++ b/src/app/mocks/handler/follow.ts @@ -0,0 +1,87 @@ +import { http } from 'msw'; + +import { + createHttpSuccessResponse, + createHttpErrorResponse, +} from '../dir/response'; + +import { relationshipStatus } from '../consts/relationshipStatus'; +import { users } from '../consts/user'; + +export const followHandler = [ + // 1️⃣ 팔로우 요청 + http.post('/users/:user_id/follow', ({ params }) => { + const { user_id } = params; + + if (isNaN(Number(user_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedUserId = Number(user_id); + const followInfo = relationshipStatus[formattedUserId]; + + switch (followInfo) { + case 'self': + return createHttpErrorResponse('4220'); + case 'none': + if (users[formattedUserId].locked) { + relationshipStatus[formattedUserId] = 'pending'; + } else relationshipStatus[formattedUserId] = 'following'; + break; + case 'following': + return createHttpErrorResponse('4220'); + case 'pending': + return createHttpErrorResponse('4220'); + default: + return createHttpErrorResponse('4040'); + } + + return createHttpSuccessResponse({}); + }), + // 2️⃣ 언팔로우 & 팔로우 요청 취소 + http.delete('/users/:user_id/follow', ({ params }) => { + const { user_id } = params; + + if (isNaN(Number(user_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedUserId = Number(user_id); + const followInfo = relationshipStatus[formattedUserId]; + + switch (followInfo) { + case 'self': + return createHttpErrorResponse('4220'); + case 'none': + return createHttpErrorResponse('4220'); + case 'following': + relationshipStatus[formattedUserId] = 'none'; + break; + case 'pending': + relationshipStatus[formattedUserId] = 'none'; + break; + + default: + return createHttpErrorResponse('4040'); + } + + return createHttpSuccessResponse({}); + }), + // 3️⃣ 팔로우 확인 + http.get('/users/:user_id/follow', ({ params }) => { + const { user_id } = params; + + if (isNaN(Number(user_id))) { + return createHttpErrorResponse('4220'); + } + + const formattedUserId = Number(user_id); + const followInfo = relationshipStatus[formattedUserId]; + + if (!followInfo) { + return createHttpErrorResponse('4040'); + } + + return createHttpSuccessResponse({ relationshipStatus: followInfo }); + }), +]; diff --git a/src/app/mocks/handler/search.ts b/src/app/mocks/handler/search.ts new file mode 100644 index 0000000..badf040 --- /dev/null +++ b/src/app/mocks/handler/search.ts @@ -0,0 +1,42 @@ +import { http } from 'msw'; +import { User } from '@/shared/consts'; + +import { + createHttpSuccessResponse, + createHttpErrorResponse, +} from '../dir/response'; + +import { users } from '../consts/user'; +import { likeUsers } from '../consts/likeUser'; + +export const searchHandler = [ + // 1️⃣ 사용자 검색 + http.get('/users', ({ request }) => { + const url = new URL(request.url); + const query = url.searchParams.get('q'); + + if (!query) { + return createHttpErrorResponse('4220'); + } + + const filteredUsers: User[] = Object.values(users).filter((user) => + user.name.includes(query), + ); + return createHttpSuccessResponse({ users: filteredUsers }); + }), + // 2️⃣ 좋아요 사용자 검색 + http.get('/like', ({ request }) => { + const url = new URL(request.url); + const query = url.searchParams.get('q'); + + if (!query) { + return createHttpErrorResponse('4220'); + } + + const filteredUsers: User[] = Object.values(likeUsers).filter((user) => + user.name.includes(query), + ); + + return createHttpSuccessResponse({ likeUsers: filteredUsers }); + }), +]; diff --git a/src/app/mocks/handler/user.ts b/src/app/mocks/handler/user.ts index 08e00ee..744d2e8 100644 --- a/src/app/mocks/handler/user.ts +++ b/src/app/mocks/handler/user.ts @@ -1,51 +1,17 @@ import { http } from 'msw'; -import { users } from '../consts/user'; -import { profileFeeds } from '../consts/profileFeed'; import { createHttpSuccessResponse, createHttpErrorResponse, } from '../dir/response'; -import { reports } from '../consts/report'; -import { relationshipStatus } from '../consts/relationshipStatus'; - -export const userHandlers = [ - // 1️⃣ 팔로우 요청 - http.post('/users/:user_id/follow', async ({ params }) => { - const { user_id } = params; - - if (isNaN(Number(user_id))) { - return createHttpErrorResponse('4220'); - } - - const formattedUserId = Number(user_id); - const followInfo = relationshipStatus[formattedUserId]; - - if (followInfo !== 'none') { - return createHttpErrorResponse('4220'); - } - - return createHttpSuccessResponse({}); - }), - // 2️⃣ 언팔로우 & 팔로우 요청 취소 - http.delete('/users/:user_id/follow', ({ params }) => { - const { user_id } = params; - - if (isNaN(Number(user_id))) { - return createHttpErrorResponse('4220'); - } - - const formattedUserId = Number(user_id); - const followInfo = relationshipStatus[formattedUserId]; - if (followInfo === 'self' || followInfo === 'none') { - return createHttpErrorResponse('4220'); - } +import { users } from '../consts/user'; +import { profileFeeds } from '../consts/profileFeed'; +import { reports } from '../consts/report'; - return createHttpSuccessResponse({}); - }), - // 3️⃣ 팔로우 확인 - http.get('/users/:user_id/follow', ({ params }) => { +export const userHandler = [ + // 1️⃣ 사용자 조회 + http.get('/users/:user_id', ({ params }) => { const { user_id } = params; if (isNaN(Number(user_id))) { @@ -53,47 +19,20 @@ export const userHandlers = [ } const formattedUserId = Number(user_id); - const followInfo = relationshipStatus[formattedUserId]; + const user = users[formattedUserId]; - if (!followInfo) { + if (!user) { return createHttpErrorResponse('4040'); } - return createHttpSuccessResponse({ relationshipStatus: followInfo }); + return createHttpSuccessResponse({ user: user }); }), - // 4️⃣ 사용자 검색 - http.get('/users', ({ request }) => { - const url = new URL(request.url); - const query = url.searchParams.get('q'); - - if (!query) { - return createHttpErrorResponse('4220'); - } - - const filteredUsers = Object.values(users).filter((user) => - user.name.includes(query), - ); + // 2️⃣ 사용자 프로필 피드 조회 + http.get('/profile/:user_id', ({ request, params }) => { + const { user_id } = params; - return createHttpSuccessResponse({ users: filteredUsers }); - }), - // 5️⃣ 좋아요 사용자 검색 - http.get('/like', ({ request }) => { const url = new URL(request.url); - const query = url.searchParams.get('q'); - - if (!query) { - return createHttpErrorResponse('4220'); - } - - const filteredUsers = Object.values(users).filter((user) => - user.name.includes(query), - ); - - return createHttpSuccessResponse({ users: filteredUsers }); - }), - // 6️⃣ 사용자 프로필 조회 - http.get('/users/:user_id', ({ params }) => { - const { user_id } = params; + const page = url.searchParams.get('page') || 1; if (isNaN(Number(user_id))) { return createHttpErrorResponse('4220'); @@ -106,19 +45,6 @@ export const userHandlers = [ return createHttpErrorResponse('4040'); } - return createHttpSuccessResponse({ user: user }); - }), - // 7️⃣ 사용자 프로필 피드 - http.get('/users/:user_id', ({ request, params }) => { - const { user_id } = params; - - const url = new URL(request.url); - const page = url.searchParams.get('page') || 1; - - if (isNaN(Number(user_id))) { - return createHttpErrorResponse('4220'); - } - if (isNaN(Number(page)) || page === '0') { return createHttpErrorResponse('4220'); } @@ -135,7 +61,7 @@ export const userHandlers = [ const hasNextPage = endOfPageRange < totalFeeds; return createHttpSuccessResponse({ - feeds: profileFeeds, + feeds: profileFeedsData, currentPageNumber: pageCount, pageSize: formattedPage, numberOfElements: profileFeedsData.length, diff --git a/src/app/mocks/test/follow/follow.error.test.ts b/src/app/mocks/test/follow/follow.error.test.ts new file mode 100644 index 0000000..e6bfcf8 --- /dev/null +++ b/src/app/mocks/test/follow/follow.error.test.ts @@ -0,0 +1,36 @@ +import axios from 'axios'; +import { describe, expect, it } from 'vitest'; + +const testCases = [ + ['GET', '팔로우 조회 API'], + ['POST', '팔로우 신청 API'], + ['DELETE', '언팔로우 & 팔로우 요청 취소 API'], +]; + +describe.each(testCases)('[%s] %s', (method) => { + it('유저 아이디가 정수 타입이 아니라면 에러가 발생한다.', async () => { + const userIds = ['hello', undefined, '[]', '{}']; + + for (const userId of userIds) { + const response = await axios({ + method, + url: `/users/${userId}/follow`, + }); + const { code } = response.data; + + expect(code).toBe('4220'); + } + }); + + it('유저 아이디에 해당하는 유저가 존재하지 않는다면 에러가 발생한다.', async () => { + const userId = 5389532104234901; + + const response = await axios({ + method, + url: `/users/${userId}/follow`, + }); + const { code } = response.data; + + expect(code).toBe('4040'); + }); +}); diff --git a/src/app/mocks/test/follow/follow.test.ts b/src/app/mocks/test/follow/follow.test.ts new file mode 100644 index 0000000..acb19af --- /dev/null +++ b/src/app/mocks/test/follow/follow.test.ts @@ -0,0 +1,135 @@ +import axios from 'axios'; +import { describe, expect, it } from 'vitest'; +import { RelationshipStatus } from '@/shared/consts'; + +async function getUserById(userId: number) { + const followInfo = await axios.get(`/users/${userId}/follow`); + const relationshipStatus: RelationshipStatus = + followInfo.data.data.relationshipStatus; + return { relationshipStatus }; +} + +describe('팔로우가 되어있지 않은 상태에서', () => { + it('공개 계정에 팔로우 신청을 클릭하면, 팔로잉으로 상태가 변경된다.', async () => { + const userId = 8; + + // 팔로우 신청 + await axios.post(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: relationshipStatus } = + await getUserById(userId); + + expect(relationshipStatus).toBe('following'); + }); + + it('비공개 계정에 팔로우 신청을 클릭하면, 요청됨으로 상태가 변경된다.', async () => { + const userId = 4; + + // 팔로우 신청 + await axios.post(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: relationshipStatus } = + await getUserById(userId); + + expect(relationshipStatus).toBe('pending'); + }); + + it('언팔로우를 클릭하면, 팔로우 상태가 변경되지 않는다.', async () => { + const userId = 9; + const { relationshipStatus: prevStatus } = await getUserById(userId); + + // 팔로우 취소 클릭 + await axios.delete(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: newStatus } = await getUserById(userId); + + expect(newStatus).toBe(prevStatus); + }); +}); + +describe('팔로우 된 상태에서', () => { + it('팔로우 신청을 클릭하면, 팔로우 상태가 변동되지 않는다.', async () => { + const userId = 2; + const { relationshipStatus: prevStatus } = await getUserById(userId); + + // 팔로우 신청 + await axios.post(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: newStatus } = await getUserById(userId); + + expect(newStatus).toBe(prevStatus); + }); + + it('언팔로우를 클릭하면, 상태가 none으로 변경된다.', async () => { + const userId = 2; + + // 팔로우 취소 클릭 + await axios.delete(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: relationshipStatus } = + await getUserById(userId); + + expect(relationshipStatus).toBe('none'); + }); +}); + +describe('팔로우 요청 중 상태에서', () => { + it('팔로우 신청을 클릭하면, 팔로우 상태가 변동되지 않는다.', async () => { + const userId = 3; + const { relationshipStatus: prevStatus } = await getUserById(userId); + + // 팔로우 신청 + await axios.post(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: newStatus } = await getUserById(userId); + + expect(newStatus).toBe(prevStatus); + }); + + it('팔로우 요청 취소를 클릭하면, 상태가 none으로 변경된다.', async () => { + const userId = 3; + + // 팔로우 취소 + await axios.delete(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: relationshipStatus } = + await getUserById(userId); + + expect(relationshipStatus).toBe('none'); + }); +}); + +describe('목표 유저가 본인이라면', () => { + it('팔로우 신청을 클릭하면, 상태가 변동되지 않는다.', async () => { + const userId = 1; + const { relationshipStatus: prevStatus } = await getUserById(userId); + + // 팔로우 신청 + await axios.post(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: newStatus } = await getUserById(userId); + + expect(newStatus).toBe(prevStatus); + }); + + it('언팔로우를 클릭하면, 상태가 변동되지 않는다.', async () => { + const userId = 1; + const { relationshipStatus: prevStatus } = await getUserById(userId); + + // 팔로우 취소 + await axios.delete(`/users/${userId}/follow`); + + // 업데이트 된 팔로우 상태 + const { relationshipStatus: newStatus } = await getUserById(userId); + + expect(newStatus).toBe(prevStatus); + }); +}); diff --git a/src/app/mocks/test/search/search.test.ts b/src/app/mocks/test/search/search.test.ts new file mode 100644 index 0000000..553c16b --- /dev/null +++ b/src/app/mocks/test/search/search.test.ts @@ -0,0 +1,70 @@ +import axios from 'axios'; +import { describe, expect, it } from 'vitest'; + +async function getUsersByName(userName: string) { + const users = await axios.get(`/users?q=${userName}`); + const searchedUsers = users.data.data.users; + return { searchedUsers }; +} + +async function getLikeUsersByName(userName: string) { + const likeusers = await axios.get(`/like?q=${userName}`); + const searchedLikeUsers = likeusers.data.data.likeUsers; + return { searchedLikeUsers }; +} + +describe('유저 검색 시, ', () => { + it('이름이 일치하는 유저가 있다면 해당 사용자들을 반환한다.', async () => { + const userName = '강병'; + + // 검색 + await axios.get(`/users?q=${userName}`); + + // 검색 결과 + const { searchedUsers: searchedUsers } = await getUsersByName(userName); + + expect(searchedUsers).toHaveLength(1); + expect(searchedUsers[0].name).toBe('강병준'); + }); + + it('이름이 일치하는 유저가 없다면 빈 배열을 반환한다.', async () => { + const userName = '김가상의유저이름'; + + // 검색 + await axios.get(`/users?q=${userName}`); + + // 검색 결과 + const { searchedUsers: searchedUsers } = await getUsersByName(userName); + + expect(searchedUsers).toHaveLength(0); + }); +}); + +describe('좋아요 유저 검색 시, ', () => { + it('이름이 일치하는 유저가 있다면 해당 사용자들을 반환한다.', async () => { + const userName = '이'; + + // 검색 + await axios.get(`/like?q=${userName}`); + + // 검색 결과 + const { searchedLikeUsers: searchedLikeUsers } = + await getLikeUsersByName(userName); + + expect(searchedLikeUsers).toHaveLength(2); + expect(searchedLikeUsers[1].name).toBe('이수민'); + }); + + it('이름이 일치하는 유저가 없다면 빈 배열을 반환한다.', async () => { + const userName = '김가상의유저이름'; + + // 검색 + await axios.get(`/like?q=${userName}`); + + // 검색 결과 + const { searchedLikeUsers: searchedLikeUsers } = + await getLikeUsersByName(userName); + + expect(searchedLikeUsers).toHaveLength(0); + }); +}); diff --git a/src/app/mocks/test/user/user.error.test.ts b/src/app/mocks/test/user/user.error.test.ts new file mode 100644 index 0000000..4b0b3b7 --- /dev/null +++ b/src/app/mocks/test/user/user.error.test.ts @@ -0,0 +1,72 @@ +import axios from 'axios'; +import { describe, expect, it } from 'vitest'; + +describe('[GET] 유저 조회 API', () => { + it('유저 아이디가 정수 타입이 아니라면 에러가 발생한다.', async () => { + const userIds = ['hello', undefined, '[]', '{}']; + + for (const userId of userIds) { + const response = await axios({ + method: 'GET', + url: `/users/${userId}`, + }); + const { code } = response.data; + + expect(code).toBe('4220'); + } + }); + + it('유저 아이디에 해당하는 유저가 존재하지 않는다면 에러가 발생한다.', async () => { + const userId = 5389532104234901; + + const response = await axios({ + method: 'GET', + url: `/users/${userId}`, + }); + const { code } = response.data; + + expect(code).toBe('4040'); + }); +}); + +describe('[GET] 프로필 피드 조회 API', () => { + it('유저 아이디가 정수 타입이 아니라면 에러가 발생한다.', async () => { + const userIds = ['hello', undefined, '[]', '{}']; + + for (const userId of userIds) { + const response = await axios({ + method: 'GET', + url: `/profile/${userId}`, + }); + const { code } = response.data; + + expect(code).toBe('4220'); + } + }); + + it('유저 아이디에 해당하는 유저가 존재하지 않는다면 에러가 발생한다.', async () => { + const userId = 5389532104234901; + + const response = await axios({ + method: 'GET', + url: `/profile/${userId}`, + }); + const { code } = response.data; + + expect(code).toBe('4040'); + }); + + it('page가 정수 타입이 아니라면 에러가 발생한다.', async () => { + const pages = ['hello', undefined, '[]', '{}']; + const userId = 1; + for (const page of pages) { + const response = await axios({ + method: 'GET', + url: `/profile/${userId}&p=${page}`, + }); + const { code } = response.data; + + expect(code).toBe('4220'); + } + }); +}); diff --git a/src/app/mocks/test/user/user.test.ts b/src/app/mocks/test/user/user.test.ts new file mode 100644 index 0000000..0ee1b38 --- /dev/null +++ b/src/app/mocks/test/user/user.test.ts @@ -0,0 +1,37 @@ +import axios from 'axios'; +import { expect, it } from 'vitest'; +import { User } from '@/shared/consts'; + +async function getUserById(userId: number) { + const user = await axios.get(`/users/${userId}`); + const userData: User = user.data.data.user; + return { userData }; +} + +async function getProfileFeedById(userId: number, page: number) { + const profileFeed = await axios.get(`/profile/${userId}?page=${page}`); + const profileFeedData = profileFeed.data.data; + return { profileFeedData }; +} + +it('유저 정보 조회 시, id에 일치하는 유저 정보를 반환한다.', async () => { + const userId = 8; + + // 유저 정보 가져오기 + const { userData: user } = await getUserById(userId); + + expect(user.name).toBe('이진우'); +}); + +it('유저의 ProfileFeed 조회 시, 해당 유저의 ProfileFeed를 반환한다.', async () => { + const userId = 4; + let page = 1; + + // ProfileFeed 가져오기 + const { profileFeedData: profileFeedData } = await getProfileFeedById( + userId, + page, + ); + + expect(profileFeedData.currentPageNumber).toBe(5); +}); diff --git a/src/setupTest.ts b/src/setupTest.ts index 47b587b..0aaa4f0 100644 --- a/src/setupTest.ts +++ b/src/setupTest.ts @@ -4,12 +4,20 @@ import * as matchers from '@testing-library/jest-dom/matchers'; import { setupServer } from 'msw/node'; import { beforeAll, afterAll, afterEach, expect } from 'vitest'; +import { followHandler } from './app/mocks/handler/follow'; import { likeHandlers } from './app/mocks/handler/like'; +import { searchHandler } from './app/mocks/handler/search'; +import { userHandler } from './app/mocks/handler/user'; expect.extend(matchers); -export const server = setupServer(...likeHandlers); +export const server = setupServer( + ...likeHandlers, + ...followHandler, + ...searchHandler, + ...userHandler, +); beforeAll(() => server.listen({ onUnhandledRequest: 'error' })); afterAll(() => server.close()); -afterEach(() => server.resetHandlers()); \ No newline at end of file +afterEach(() => server.resetHandlers()); diff --git a/src/shared/consts/types/profileFeed.ts b/src/shared/consts/types/profileFeed.ts index 2d873b4..4fbd2f9 100644 --- a/src/shared/consts/types/profileFeed.ts +++ b/src/shared/consts/types/profileFeed.ts @@ -1,6 +1,5 @@ export interface ProfileFeed { id: number; - title: string; content: string; thubnailImage: string; diff --git a/src/shared/consts/types/user.ts b/src/shared/consts/types/user.ts index d582c3a..62c8962 100644 --- a/src/shared/consts/types/user.ts +++ b/src/shared/consts/types/user.ts @@ -3,6 +3,7 @@ export interface User { profileImage: string; name: string; content: string; + locked: boolean; feedCount: number; followingCount: number;