diff --git a/.vscode/settings.json b/.vscode/settings.json index 1a1f5ce..2612aca 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "typescript.preferences.importModuleSpecifier": "project-relative" + "typescript.preferences.importModuleSpecifier": "relative" } diff --git a/src/auth/oauth.controller.ts b/src/auth/oauth.controller.ts index 9d2ec1b..c76b8ef 100644 --- a/src/auth/oauth.controller.ts +++ b/src/auth/oauth.controller.ts @@ -54,7 +54,6 @@ export class OAuthController { }) @Get('kakao-login') async kakaoOauth(@Query('code') code: string): Promise { - console.log(code); return this.oauthService.kakaoOauth({ code }); } diff --git a/test/auth/get-kakao-auth.spec.ts b/test/auth/get-kakao-auth.spec.ts index 011d281..3894481 100644 --- a/test/auth/get-kakao-auth.spec.ts +++ b/test/auth/get-kakao-auth.spec.ts @@ -2,18 +2,28 @@ import { getBuilder } from '../common/application-builder'; import { HttpStatus, INestApplication } from '@nestjs/common'; import { StartedPostgreSqlContainer } from '@testcontainers/postgresql'; import * as request from 'supertest'; +import { DataSource } from 'typeorm'; jest.setTimeout(30_000); describe('[GET] /api/oauth/kakao-auth', () => { // Application let app: INestApplication; let container: StartedPostgreSqlContainer; // TODO 결합도 낮추기 + let dataSource: DataSource; beforeAll(async () => { - const { builder, container: _container } = await getBuilder(); + const { + builder, + container: _container, + dataSource: _dataSource, + } = await getBuilder(); container = _container; + dataSource = _dataSource; - const module = await builder.compile(); + const module = await builder + .overrideProvider(DataSource) + .useValue(dataSource) + .compile(); app = module.createNestApplication(); await app.init(); diff --git a/test/auth/get-kakao-login.spec.ts b/test/auth/get-kakao-login.spec.ts new file mode 100644 index 0000000..f6de45f --- /dev/null +++ b/test/auth/get-kakao-login.spec.ts @@ -0,0 +1,161 @@ +import { getBuilder } from '../common/application-builder'; +import { + BadRequestException, + CACHE_MANAGER, + HttpStatus, + INestApplication, + UnauthorizedException, +} from '@nestjs/common'; +import { StartedPostgreSqlContainer } from '@testcontainers/postgresql'; +import { OAuthUtil } from '../../src/auth/util/oauth.util'; +import { User } from '../../src/users/entities/user.entity'; +import * as request from 'supertest'; +import { cacheManagerMock } from '../mock/cache-manager.mock'; +import { oAuthUtilMock } from '../mock/oauth-util.mock'; +import { Seeder } from '../seeder/seeder.interface'; +import { UserSeeder } from '../seeder/user.seeder'; +import { DataSource, Repository } from 'typeorm'; + +jest.setTimeout(30_000); +describe('[GET] /api/oauth/kakao-login', () => { + // Application + let app: INestApplication; + let container: StartedPostgreSqlContainer; // TODO 결합도 낮추기 + let dataSource: DataSource; + + // Service + let oauthUtil: OAuthUtil; + + // Database + let userRepository: Repository; + + // Seeder + const userSeeder: Seeder = new UserSeeder(); + + // Stub + let userStub: User; + + beforeAll(async () => { + const { + builder, + container: _container, + dataSource: _dataSource, + } = await getBuilder(); + container = _container; + dataSource = _dataSource; + + const module = await builder + .overrideProvider(DataSource) + .useValue(dataSource) + .overrideProvider(OAuthUtil) + .useValue(oAuthUtilMock) + .overrideProvider(CACHE_MANAGER) + .useValue(cacheManagerMock) + .compile(); + + app = module.createNestApplication(); + await app.init(); + + oauthUtil = app.get(OAuthUtil); + userRepository = dataSource.getRepository(User); + }); + + beforeEach(async () => { + await dataSource.synchronize(true); + }); + + afterAll(async () => { + await app.close(); + await container.stop(); + }); + + /** + * 1. 카카오 로그인에 성공한다. + * 2. 카카오 인증을 받지 못해 실패한다. + * 3. 이메일 수집에 동의하지 않아 실패한다. + */ + + describe('카카오 로그인에 성공한다.', () => { + it('200을 반환한다.', async () => { + const emailStub = 'test@email.com'; + const nicknameStub = 'test'; + oauthUtil.getKakaoAccessToken = jest + .fn() + .mockImplementationOnce(async () => ({ access_token: '' })); + oauthUtil.getKakaoUserInfo = jest + .fn() + .mockImplementationOnce(async () => ({ + userInfo: { + kakao_account: { + email: emailStub, + profile: { nickname: nicknameStub }, + }, + }, + })); + + const { status, body } = await request(app.getHttpServer()) + .get('/oauth/kakao-login') + .query({ code: '' }); + + expect(status).toBe(HttpStatus.OK); + expect(typeof body.access_token).toBe('string'); + expect(typeof body.refresh_token).toBe('string'); + }); + }); + + describe('카카오 인증을 받지 못해 실패한다.', () => { + it('401 예외를 던진다.', async () => { + oauthUtil.getKakaoAccessToken = jest + .fn() + .mockImplementationOnce(async () => { + throw new UnauthorizedException(); + }); + + const { status } = await request(app.getHttpServer()) + .get('/oauth/kakao-login') + .query({ code: '' }); + + expect(status).toBe(HttpStatus.UNAUTHORIZED); + }); + + it('400 예외를 던진다.', async () => { + oauthUtil.getKakaoAccessToken = jest + .fn() + .mockImplementationOnce(async () => { + throw new BadRequestException(); + }); + + const { status } = await request(app.getHttpServer()) + .get('/oauth/kakao-login') + .query({ code: '' }); + + expect(status).toBe(HttpStatus.BAD_REQUEST); + }); + }); + + describe('이메일 동의를 하지 않아 실패한다.', () => { + it('400 예외를 던진다.', async () => { + const nicknameStub = 'test'; + oauthUtil.getKakaoAccessToken = jest + .fn() + .mockImplementationOnce(async () => ({ access_token: '' })); + oauthUtil.getKakaoUserInfo = jest + .fn() + .mockImplementationOnce(async () => ({ + userInfo: { + kakao_account: { + email: null, + profile: { nickname: nicknameStub }, + }, + }, + })); + + const { status, body } = await request(app.getHttpServer()) + .get('/oauth/kakao-login') + .query({ code: '' }); + + expect(status).toBe(HttpStatus.BAD_REQUEST); + expect(body.message).toBe('Please Agree to share your email'); + }); + }); +}); diff --git a/test/mock/oauth-util.mock.ts b/test/mock/oauth-util.mock.ts new file mode 100644 index 0000000..a59b2de --- /dev/null +++ b/test/mock/oauth-util.mock.ts @@ -0,0 +1,4 @@ +export const oAuthUtilMock = { + getKakaoAccessToken: jest.fn(), + getKakaoUserInfo: jest.fn(), +};