diff --git a/src/controllers/user.controller.ts b/src/controllers/user.controller.ts index 5d02751..4ee2dd9 100644 --- a/src/controllers/user.controller.ts +++ b/src/controllers/user.controller.ts @@ -24,9 +24,8 @@ export class UserController { if (isProd) { baseOptions.sameSite = 'lax'; - baseOptions.domain = "velog-dashboard.kro.kr"; + baseOptions.domain = 'velog-dashboard.kro.kr'; baseOptions.maxAge = THREE_WEEKS_IN_MS; // 3주 - } else { baseOptions.domain = 'localhost'; } @@ -108,14 +107,16 @@ export class UserController { }; fetchCurrentUser: RequestHandler = async (req: Request, res: Response) => { - // 외부 API (velog) 호출로 username 을 가져와야 함, 게시글 바로가기 때문에 (username) - const { accessToken, refreshToken } = req.tokens; - const velogUser = await fetchVelogApi(accessToken, refreshToken); + const currentUser = req.user; + + // 인가 middle 에서 만든 객체 그대로 재활용 + const username = currentUser.username || ''; + const profile = { thumbnail: currentUser.thumbnail || '' }; const response = new LoginResponseDto( true, '유저 정보 조회에 성공하였습니다.', - { id: req.user.id, username: velogUser.username, profile: velogUser.profile }, + { id: currentUser.id, username: username, profile: profile }, null, ); diff --git a/src/middlewares/__test__/auth.middleware.test.ts b/src/middlewares/__test__/auth.middleware.test.ts index 98f7556..6447854 100644 --- a/src/middlewares/__test__/auth.middleware.test.ts +++ b/src/middlewares/__test__/auth.middleware.test.ts @@ -1,6 +1,7 @@ import { Request, Response } from 'express'; import { authMiddleware } from '@/middlewares/auth.middleware'; import pool from '@/configs/db.config'; +import { mockUser } from '@/utils/fixtures'; // pool.query 모킹 jest.mock('@/configs/db.config', () => ({ @@ -184,14 +185,6 @@ describe('인증 미들웨어', () => { refreshToken: 'refresh-token' }; - // 사용자 정보 mock - const mockUser = { - id: 1, - username: 'testuser', - email: 'test@example.com', - velog_uuid: 'c7507240-093b-11ea-9aae-a58a86bb0520' - }; - // DB 쿼리 결과 모킹 (pool.query as jest.Mock).mockResolvedValueOnce({ rows: [mockUser] diff --git a/src/repositories/__test__/fixtures.ts b/src/repositories/__test__/fixtures.ts deleted file mode 100644 index ddc3dd6..0000000 --- a/src/repositories/__test__/fixtures.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { QueryResult } from "pg"; - -/** -* PostgreSQL 쿼리를 모킹하기 위한 mock Pool 객체 -* -* @description Jest 테스트에서 pg.Pool의 query 메서드를 모킹하는 데 사용됩니다. -* @example -* ```typescript -* // 성공적인 쿼리 결과 모킹 -* mockPool.query.mockResolvedValue(createMockQueryResult([{ id: 1, name: 'test' }])); -* -* // 에러 발생 모킹 -* mockPool.query.mockRejectedValue(new Error('Database error')); -* ``` -*/ -export const mockPool: { - query: jest.Mock>>, unknown[]>; -} = { - query: jest.fn(), -}; - -/** -* pg의 QueryResult 타입을 만족하는 mock 객체를 생성하기 위한 헬퍼 함수 -* -* @template T - 쿼리 결과 row의 타입 (Record를 확장해야 함) -* @param rows - 모킹할 데이터베이스 행들의 배열 -* @returns PostgreSQL QueryResult 형태의 mock 객체 -* -* @description -* PostgreSQL의 실제 쿼리 결과와 동일한 구조를 가진 mock 객체를 생성합니다. -* Jest 테스트에서 데이터베이스 쿼리 결과를 모킹할 때 사용됩니다. -* -* @example -* ```typescript -* // 사용자 데이터 모킹 -* const mockUsers = [ -* { id: 1, name: 'John', email: 'john@example.com' }, -* { id: 2, name: 'Jane', email: 'jane@example.com' } -* ]; -* const result = createMockQueryResult(mockUsers); -* -* // 빈 결과 모킹 -* const emptyResult = createMockQueryResult([]); -* -* // Jest mock에서 사용 -* mockPool.query.mockResolvedValue(createMockQueryResult(mockUsers)); -* ``` -*/ -export function createMockQueryResult>(rows: T[]): QueryResult { - return { - rows, - rowCount: rows.length, - command: '', - oid: 0, - fields: [], - } satisfies QueryResult; -} \ No newline at end of file diff --git a/src/repositories/__test__/leaderboard.repo.test.ts b/src/repositories/__test__/leaderboard.repo.test.ts index cda0cbb..be3f111 100644 --- a/src/repositories/__test__/leaderboard.repo.test.ts +++ b/src/repositories/__test__/leaderboard.repo.test.ts @@ -1,8 +1,8 @@ import { Pool } from 'pg'; import { DBError } from '@/exception'; -import { LeaderboardRepository } from '@/repositories/leaderboard.repository'; import { UserLeaderboardSortType, PostLeaderboardSortType } from '@/types'; -import { mockPool, createMockQueryResult } from './fixtures'; +import { LeaderboardRepository } from '@/repositories/leaderboard.repository'; +import { mockPool, createMockQueryResult } from '@/utils/fixtures'; jest.mock('pg'); diff --git a/src/repositories/__test__/post.repo.test.ts b/src/repositories/__test__/post.repo.test.ts index ba8df20..789da80 100644 --- a/src/repositories/__test__/post.repo.test.ts +++ b/src/repositories/__test__/post.repo.test.ts @@ -1,7 +1,7 @@ import { Pool } from 'pg'; import { PostRepository } from '@/repositories/post.repository'; import { DBError } from '@/exception'; -import { mockPool, createMockQueryResult } from './fixtures'; +import { mockPool, createMockQueryResult } from '@/utils/fixtures'; jest.mock('pg'); diff --git a/src/repositories/__test__/qr.repo.test.ts b/src/repositories/__test__/qr.repo.test.ts index a628955..e3e5c70 100644 --- a/src/repositories/__test__/qr.repo.test.ts +++ b/src/repositories/__test__/qr.repo.test.ts @@ -2,7 +2,7 @@ import { UserRepository } from '@/repositories/user.repository'; import { DBError } from '@/exception'; import { Pool } from 'pg'; import { QRLoginToken } from "@/types/models/QRLoginToken.type"; -import { mockPool } from './fixtures'; +import { mockPool } from '@/utils/fixtures'; jest.mock('pg'); diff --git a/src/repositories/__test__/totalStats.repo.test.ts b/src/repositories/__test__/totalStats.repo.test.ts index ba9f5a1..c9467a6 100644 --- a/src/repositories/__test__/totalStats.repo.test.ts +++ b/src/repositories/__test__/totalStats.repo.test.ts @@ -1,9 +1,9 @@ import { Pool } from 'pg'; -import { TotalStatsRepository } from '@/repositories/totalStats.repository'; import { DBError } from '@/exception'; -import { getKSTDateStringWithOffset } from '@/utils/date.util'; -import { mockPool, createMockQueryResult } from './fixtures'; import { TotalStatsType } from '@/types'; +import { TotalStatsRepository } from '@/repositories/totalStats.repository'; +import { getKSTDateStringWithOffset } from '@/utils/date.util'; +import { mockPool, createMockQueryResult } from '@/utils/fixtures'; // Mock dependencies jest.mock('@/configs/logger.config', () => ({ diff --git a/src/routes/user.router.ts b/src/routes/user.router.ts index 8850f66..5559fea 100644 --- a/src/routes/user.router.ts +++ b/src/routes/user.router.ts @@ -103,7 +103,7 @@ router.post('/logout', authMiddleware.verify, userController.logout); * get: * tags: * - User - * summary: 사용자 정보 조회 + * summary: 사용자 정보 조회, auth 미들웨어 객체 그대로 사용 * responses: * '200': * description: 성공 diff --git a/src/services/__test__/qr.service.test.ts b/src/services/__test__/qr.service.test.ts index ac2a81b..2490b65 100644 --- a/src/services/__test__/qr.service.test.ts +++ b/src/services/__test__/qr.service.test.ts @@ -1,9 +1,9 @@ +import { Pool } from 'pg'; +import { DBError } from '@/exception'; import { UserService } from '@/services/user.service'; import { UserRepository } from '@/repositories/user.repository'; -import { DBError } from '@/exception'; import { QRLoginToken } from '@/types/models/QRLoginToken.type'; -import { User } from '@/types'; -import { Pool } from 'pg'; +import { mockUser } from '@/utils/fixtures'; // AESEncryption 클래스 모킹 jest.mock('@/modules/token_encryption/aes_encryption', () => { @@ -68,18 +68,6 @@ describe('UserService의 QR 로그인 기능', () => { }); describe('useToken', () => { - const mockUser: User = { - id: 1, - velog_uuid: 'uuid-1', - access_token: 'encrypted-access-token', - refresh_token: 'encrypted-refresh-token', - email: 'test@example.com', - group_id: 1, - is_active: true, - created_at: new Date(), - updated_at: new Date() - }; - const mockQRToken: QRLoginToken = { id: 1, token: 'token', diff --git a/src/types/models/User.type.ts b/src/types/models/User.type.ts index 2b173fd..7a3640c 100644 --- a/src/types/models/User.type.ts +++ b/src/types/models/User.type.ts @@ -8,6 +8,9 @@ export interface User { is_active: boolean; created_at: Date; updated_at: Date; + // 250607 추가 + username: string | null; + thumbnail: string | null; } diff --git a/src/utils/fixtures.ts b/src/utils/fixtures.ts new file mode 100644 index 0000000..6a03cfb --- /dev/null +++ b/src/utils/fixtures.ts @@ -0,0 +1,77 @@ +import { QueryResult } from 'pg'; +import { User } from '@/types'; + +/** + * PostgreSQL 쿼리를 모킹하기 위한 mock Pool 객체 + * + * @description Jest 테스트에서 pg.Pool의 query 메서드를 모킹하는 데 사용됩니다. + * @example + * ```typescript + * // 성공적인 쿼리 결과 모킹 + * mockPool.query.mockResolvedValue(createMockQueryResult([{ id: 1, name: 'test' }])); + * + * // 에러 발생 모킹 + * mockPool.query.mockRejectedValue(new Error('Database error')); + * ``` + */ +export const mockPool: { + query: jest.Mock>>, unknown[]>; +} = { + query: jest.fn(), +}; + +/** + * 테스트용 모의 사용자 데이터, User 객체 + * + * @description 인증 관련 (미들웨어, QR 로그인 등) 유닛 테스트에서 공통적으로 사용되는 mock User 객체입니다. + */ +export const mockUser: User = { + id: 1, + velog_uuid: 'uuid-1', + access_token: 'encrypted-access-token', + refresh_token: 'encrypted-refresh-token', + email: 'test@example.com', + username: 'nuung', + thumbnail: 'https://nuung.com/test.jpg', + group_id: 1, + is_active: true, + created_at: new Date('2024-01-01T00:00:00Z'), + updated_at: new Date('2024-01-01T00:00:00Z'), +}; + +/** + * pg의 QueryResult 타입을 만족하는 mock 객체를 생성하기 위한 헬퍼 함수 + * + * @template T - 쿼리 결과 row의 타입 (Record를 확장해야 함) + * @param rows - 모킹할 데이터베이스 행들의 배열 + * @returns PostgreSQL QueryResult 형태의 mock 객체 + * + * @description + * PostgreSQL의 실제 쿼리 결과와 동일한 구조를 가진 mock 객체를 생성합니다. + * Jest 테스트에서 데이터베이스 쿼리 결과를 모킹할 때 사용됩니다. + * + * @example + * ```typescript + * // 사용자 데이터 모킹 + * const mockUsers = [ + * { id: 1, name: 'John', email: 'john@example.com' }, + * { id: 2, name: 'Jane', email: 'jane@example.com' } + * ]; + * const result = createMockQueryResult(mockUsers); + * + * // 빈 결과 모킹 + * const emptyResult = createMockQueryResult([]); + * + * // Jest mock에서 사용 + * mockPool.query.mockResolvedValue(createMockQueryResult(mockUsers)); + * ``` + */ +export function createMockQueryResult>(rows: T[]): QueryResult { + return { + rows, + rowCount: rows.length, + command: '', + oid: 0, + fields: [], + } satisfies QueryResult; +}