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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/features/user/constants/user.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ export const MAX_NICKNAME_LENGTH = 20;

// ── 전화번호 ──

export const MIN_PHONE_LENGTH = 7;
export const MAX_PHONE_LENGTH = 20;
// 정책: 010-XXXX-XXXX 고정 (13자). figma 명세 기준.
export const PHONE_REGEX = /^010-\d{4}-\d{4}$/;
export const PHONE_FORMAT_EXAMPLE = '010-XXXX-XXXX';

// ── 생년월일 ──

Expand Down
34 changes: 23 additions & 11 deletions src/features/user/services/user-base.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,23 +183,35 @@ describe('UserBaseService (real DB)', () => {
expect(service.testNormalizePhoneNumber(' ')).toBeNull();
});

it('길이가 하한 미만이면 BadRequestException을 던진다', () => {
expect(() => service.testNormalizePhoneNumber('12345')).toThrow(
BadRequestException,
it.each([['010-0000-0000'], ['010-1234-5678'], ['010-9999-9999']])(
'정상 형식 %s 은 그대로 반환한다',
(raw) => {
expect(service.testNormalizePhoneNumber(raw)).toBe(raw);
},
);

it('앞뒤 공백을 trim하여 검증한다', () => {
expect(service.testNormalizePhoneNumber(' 010-1234-5678 ')).toBe(
'010-1234-5678',
);
});

it('숫자와 하이픈 외 문자가 포함되면 BadRequestException을 던진다', () => {
expect(() => service.testNormalizePhoneNumber('010-abc-1234')).toThrow(
it.each([
['011-1234-5678'], // 010 prefix 외
['019-1234-5678'], // 010 prefix 외
['010-123-4567'], // 자릿수 부족
['010-12345-6789'], // 자릿수 초과
['01012345678'], // 하이픈 없음
['010 1234 5678'], // 공백 구분자
['+82-10-1234-5678'], // 국가코드 포함
['010-abc-1234'], // 문자 포함
['010--1234-5678'], // 하이픈 위치 잘못
['12345'], // 짧은 임의 문자열
])('비정상 형식 %s 은 BadRequestException을 던진다', (raw) => {
expect(() => service.testNormalizePhoneNumber(raw)).toThrow(
BadRequestException,
);
});

it('유효한 전화번호를 반환한다', () => {
expect(service.testNormalizePhoneNumber('010-1234-5678')).toBe(
'010-1234-5678',
);
});
});

describe('normalizeBirthDate', () => {
Expand Down
16 changes: 6 additions & 10 deletions src/features/user/services/user-base.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ import {
DEFAULT_PAGINATION_LIMIT,
MAX_NICKNAME_LENGTH,
MAX_PAGINATION_LIMIT,
MAX_PHONE_LENGTH,
MIN_BIRTH_DATE,
MIN_NICKNAME_LENGTH,
MIN_PHONE_LENGTH,
PHONE_FORMAT_EXAMPLE,
PHONE_REGEX,
} from '@/features/user/constants/user.constants';
import type { UserAccountWithProfile } from '@/features/user/repositories/user.repository';
import { UserRepository } from '@/features/user/repositories/user.repository';
Expand Down Expand Up @@ -90,14 +90,10 @@ export abstract class UserBaseService {
if (raw === undefined || raw === null) return null;
const trimmed = raw.trim();
if (trimmed.length === 0) return null;
if (
trimmed.length < MIN_PHONE_LENGTH ||
trimmed.length > MAX_PHONE_LENGTH
) {
throw new BadRequestException('Invalid phone number length.');
}
if (!/^[0-9-]+$/.test(trimmed)) {
throw new BadRequestException('Invalid phone number format.');
if (!PHONE_REGEX.test(trimmed)) {
throw new BadRequestException(
`Invalid phone number format. Expected ${PHONE_FORMAT_EXAMPLE}.`,
);
}
return trimmed;
}
Expand Down
Loading