diff --git a/src/features/user/constants/user.constants.ts b/src/features/user/constants/user.constants.ts index 5c64aa7..bbabab9 100644 --- a/src/features/user/constants/user.constants.ts +++ b/src/features/user/constants/user.constants.ts @@ -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'; // ── 생년월일 ── diff --git a/src/features/user/services/user-base.service.spec.ts b/src/features/user/services/user-base.service.spec.ts index 6590cd0..d5d639d 100644 --- a/src/features/user/services/user-base.service.spec.ts +++ b/src/features/user/services/user-base.service.spec.ts @@ -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', () => { diff --git a/src/features/user/services/user-base.service.ts b/src/features/user/services/user-base.service.ts index 920512b..dd8709b 100644 --- a/src/features/user/services/user-base.service.ts +++ b/src/features/user/services/user-base.service.ts @@ -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'; @@ -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; }