Skip to content

Commit

Permalink
Feat(#520): 소셜 로그인 실패 테스트 케이스 추가 완료
Browse files Browse the repository at this point in the history
  • Loading branch information
Kimsoo0119 committed Jun 3, 2024
1 parent 778094c commit f2fb116
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 11 deletions.
28 changes: 25 additions & 3 deletions test/e2e/auth.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { randomInt } from 'crypto';
import { v4 } from 'uuid';
import { testCreateUser } from '@test/features/user/test-create-user';
import { OAuthProvider } from '@src/auth/constants/const';
import { IServerErrorResponse } from '@test/interface/interface';

jest.mock('axios');
const mockedAxios = axios as jest.Mocked<typeof axios>;
Expand All @@ -29,14 +30,14 @@ describe('AuthOAuthController (e2e)', () => {
await server.close();
});

describe('/auth/oauth/signin/kakao (GET)', () => {
describe('/auth/oauth/signin/:provider (GET)', () => {
//소셜 로그인 테스트
it('새로운 사용자일 경우 authEmail을 반환해야 한다', async () => {
const testEmail = v4() + '@example.com';
//OAuth Server 통신 모킹(카카오)
mockedAxios.post.mockResolvedValue({
data: { kakao_account: { email: testEmail } },
});

const response = await testUserSignin(PORT, OAuthProvider.KAKAO);

expect(response.authEmail).toEqual(testEmail);
Expand All @@ -45,12 +46,12 @@ describe('AuthOAuthController (e2e)', () => {
// 기존 사용자일 경우 액세스 토큰을 반환하는 테스트
it('기존 사용자일 경우 액세스 토큰을 반환해야 한다', async () => {
const testEmail = v4() + '@example.com';

await testCreateUser(PORT, {
provider: OAuthProvider.KAKAO,
email: testEmail,
});

//OAuth Server 통신 모킹(카카오)
mockedAxios.post.mockResolvedValue({
data: { kakao_account: { email: testEmail } },
});
Expand All @@ -59,5 +60,26 @@ describe('AuthOAuthController (e2e)', () => {
expect(response.userAccessToken).toBeDefined();
expect(typeof response.userAccessToken).toBe('string');
});

//비즈니스 로직 에러 테스트
it('이미 다른 방식으로 가입한 이메일일 경우 에러를 반환해야 한다', async () => {
const testEmail = v4() + '@example.com';
await testCreateUser(PORT, {
provider: OAuthProvider.KAKAO,
email: testEmail,
});

//OAuth Server 통신 모킹(구글)
mockedAxios.get.mockResolvedValue({
data: { email: testEmail },
});
const response = await testUserSignin<IServerErrorResponse>(
PORT,
OAuthProvider.GOOGLE,
);

expect(response.statusCode).toBe(400);
expect(response.error).toBe('differentSignUpMethod');
});
});
});
12 changes: 8 additions & 4 deletions test/features/auth/test-user-signin.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
import { OAuthProvider } from '@src/auth/constants/const';
import { AuthOAuthController } from '@src/auth/controllers/auth-oauth.controller';
import { ApiResponse } from '@test/types/api-response.type';
import { v4 } from 'uuid';

/**
* 유저 OAuth 로그인 테스트
* 테스트 환경에서는 OAuth 서버와 통신하지 않는다.
* Axios 요청을 모킹하여 OAuth 프로바이더에 맞게 반환값을 할당해야한다.
* OAuth Server는 성공한다는 가정하에 비즈니스 로직 성공 보장
* IServerErrorResponse을 제네릭 타입으로 사용하면 비즈니스 코드의 에러 response를 처리할 수 있다.
*
* @param PORT 포트번호
* @param provider 로그인 할 OAuth provider
* @returns 로그인에 성공하면 토큰을 발급받는다.
*/
export const testUserSignin = async (
export const testUserSignin = async <T = unknown>(
PORT: number,
provider: OAuthProvider,
): Promise<ReturnType<AuthOAuthController['signIn']>> => {
): Promise<ApiResponse<T, AuthOAuthController['signIn']>> => {
const accessToken = v4();
const url = `http://localhost:${PORT}/auth/oauth/signin/${
provider ?? 'kakao'
Expand All @@ -24,7 +26,9 @@ export const testUserSignin = async (
const response = await fetch(url, {
method: 'GET',
});
const responseBody = await response.json();

return responseBody as Awaited<ReturnType<AuthOAuthController['signIn']>>;
const responseBody: ApiResponse<T, AuthOAuthController['signIn']> =
await response.json();

return responseBody;
};
11 changes: 7 additions & 4 deletions test/features/user/test-create-user.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ import { v4 } from 'uuid';
import request from 'supertest';
import { CreateUserDto } from '@src/user/dtos/create-user.dto';
import { UserController } from '@src/user/controllers/user.controller';
import { ApiResponse } from '@test/types/api-response.type';

/**
* 유저 생성 테스트
* 프론트에서 호출한 것과 동일한 유저 생성과정을 수행한다.
* 이메일, 닉네임, PROVIDER만 선택적으로 받으며 대한 그외 정보는 전부 랜덤으로 생성된다.
* IServerErrorResponse을 제네릭 타입으로 사용하면 비즈니스 코드의 에러 response를 처리할 수 있다.
*
* @param PORT 포트번호
* @param options [이메일, 닉네임, PROVIDER] OPTIONAL
* @returns 유저 생성 결과
*/

export const testCreateUser = async (
export const testCreateUser = async <T = unknown>(
PORT: number,
options?: Partial<CreateUserDto>,
): Promise<ReturnType<UserController['createUser']>> => {
): Promise<ApiResponse<T, UserController['createUser']>> => {
const email = options?.email || v4() + '@example.com';
const url = `http://localhost:${PORT}/users`;

Expand All @@ -43,7 +45,8 @@ export const testCreateUser = async (
}),
});

const responseBody = await response.json();
const responseBody: ApiResponse<T, UserController['createUser']> =
await response.json();

return responseBody as Awaited<ReturnType<UserController['createUser']>>;
return responseBody;
};
5 changes: 5 additions & 0 deletions test/interface/interface.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export interface IServerErrorResponse {
statusCode: number;
message: string;
error: string;
}
9 changes: 9 additions & 0 deletions test/types/api-response.type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { IServerErrorResponse } from '@test/interface/interface';

// e2e 테스트의 성공, 비즈니스 로직 실패 response에 접근하기 위해 사용하는 타입
export type ApiResponse<
T,
SuccessType extends (...args: any) => any,
> = T extends IServerErrorResponse
? IServerErrorResponse
: Awaited<ReturnType<SuccessType>>;

0 comments on commit f2fb116

Please sign in to comment.