Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/controllers/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
}
Expand Down Expand Up @@ -108,14 +107,16 @@ export class UserController {
};

fetchCurrentUser: RequestHandler = async (req: Request, res: Response<LoginResponseDto>) => {
// 외부 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,
);

Expand Down
9 changes: 1 addition & 8 deletions src/middlewares/__test__/auth.middleware.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => ({
Expand Down Expand Up @@ -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]
Expand Down
57 changes: 0 additions & 57 deletions src/repositories/__test__/fixtures.ts

This file was deleted.

4 changes: 2 additions & 2 deletions src/repositories/__test__/leaderboard.repo.test.ts
Original file line number Diff line number Diff line change
@@ -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');

Expand Down
2 changes: 1 addition & 1 deletion src/repositories/__test__/post.repo.test.ts
Original file line number Diff line number Diff line change
@@ -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');

Expand Down
2 changes: 1 addition & 1 deletion src/repositories/__test__/qr.repo.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down
6 changes: 3 additions & 3 deletions src/repositories/__test__/totalStats.repo.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => ({
Expand Down
2 changes: 1 addition & 1 deletion src/routes/user.router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ router.post('/logout', authMiddleware.verify, userController.logout);
* get:
* tags:
* - User
* summary: 사용자 정보 조회
* summary: 사용자 정보 조회, auth 미들웨어 객체 그대로 사용
* responses:
* '200':
* description: 성공
Expand Down
18 changes: 3 additions & 15 deletions src/services/__test__/qr.service.test.ts
Original file line number Diff line number Diff line change
@@ -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', () => {
Expand Down Expand Up @@ -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',
Expand Down
3 changes: 3 additions & 0 deletions src/types/models/User.type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ export interface User {
is_active: boolean;
created_at: Date;
updated_at: Date;
// 250607 추가
username: string | null;
thumbnail: string | null;
}


Expand Down
77 changes: 77 additions & 0 deletions src/utils/fixtures.ts
Original file line number Diff line number Diff line change
@@ -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<Promise<QueryResult<Record<string, unknown>>>, 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<string, unknown>를 확장해야 함)
* @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<T extends Record<string, unknown>>(rows: T[]): QueryResult<T> {
return {
rows,
rowCount: rows.length,
command: '',
oid: 0,
fields: [],
} satisfies QueryResult<T>;
}
Loading