Skip to content

Commit 382f692

Browse files
authored
Merge pull request #33 from boostcampwm-2022/test/#33-C
test: ๋กœ๊ทธ์ธ ์„œ๋น„์Šค ๋กœ์ง
2 parents 91df7ba + 30aa849 commit 382f692

File tree

5 files changed

+115
-49
lines changed

5 files changed

+115
-49
lines changed

โ€Žserver/.eslintrcโ€Ž

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@typescript-eslint/explicit-module-boundary-types": "off",
1818
"@typescript-eslint/no-explicit-any": "off",
1919
"@typescript-eslint/ban-types": "off",
20+
"@typescript-eslint/no-var-requires": "off",
2021
"no-nested-ternary": "error",
2122
"eqeqeq": "error",
2223
"no-console": "warn"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import axios from 'axios';
2+
import env from '@config';
3+
import AuthorizationError from '@errors/authorization-error';
4+
5+
const ACCESS_TOKEN_REQUEST_URL = 'https://github.com/login/oauth/access_token';
6+
const USER_REQUEST_URL = 'https://api.github.com/user';
7+
8+
export const getAccessToken = async (code: string) => {
9+
const body = {
10+
client_id: env.GITHUB_CLIENT_ID,
11+
client_secret: env.GITHUB_CLIENT_SECRET,
12+
code,
13+
};
14+
const headers = {
15+
'Content-Type': 'application/json',
16+
Accept: 'application/json',
17+
};
18+
19+
const { data: accessTokenResponse } = await axios.post(
20+
ACCESS_TOKEN_REQUEST_URL,
21+
body,
22+
{
23+
headers,
24+
},
25+
);
26+
27+
if (accessTokenResponse.error) {
28+
throw new Error('access token ์ƒ์„ฑ ์š”์ฒญ ์‹คํŒจ');
29+
}
30+
31+
return accessTokenResponse;
32+
};
33+
34+
export const getGithubUser = async (accessToken: string, tokenType: string) => {
35+
const { data: user } = await axios.get(USER_REQUEST_URL, {
36+
headers: {
37+
Authorization: `${tokenType} ${accessToken}`,
38+
},
39+
});
40+
41+
if (user.error) {
42+
throw new AuthorizationError('OAuth ์œ ์ € ์ •๋ณด ์š”์ฒญ ์‹คํŒจ');
43+
}
44+
45+
return user;
46+
};
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
const { login } = require('./service');
2+
const { getAccessToken, getGithubUser } = require('./service.github');
3+
const userModel = require('@apis/user/model');
4+
const jwt = require('@utils/jwt');
5+
6+
jest.mock('./service.github', () => {
7+
return {
8+
getAccessToken: jest.fn(),
9+
getGithubUser: jest.fn(),
10+
};
11+
});
12+
13+
jest.mock('@apis/user/model', () => {
14+
return {
15+
exists: jest.fn(),
16+
create: jest.fn().mockImplementation(() => undefined),
17+
};
18+
});
19+
20+
jest.mock('@utils/jwt', () => {
21+
return {
22+
generateAccessToken: jest.fn(),
23+
generateRefreshToken: jest.fn(),
24+
};
25+
});
26+
27+
describe('login', () => {
28+
const successfulTokenResponse = {
29+
access_token: '',
30+
token_type: '',
31+
};
32+
const successfulUserResponse = {
33+
id: '',
34+
login: '',
35+
avatar_url: '',
36+
};
37+
38+
const ACCESS_TOKEN = 'ACCESS_TOKEN';
39+
const REFRESH_TOKEN = 'REFRESH_TOKEN';
40+
41+
jwt.generateAccessToken.mockReturnValue(ACCESS_TOKEN);
42+
jwt.generateRefreshToken.mockReturnValue(REFRESH_TOKEN);
43+
44+
it('์œ ํšจํ•œ ์ฝ”๋“œ๋ฅผ ๋ฐ›์œผ๋ฉด ํ† ํฐ์ด ์„ฑ๊ณต์ ์œผ๋กœ ์ƒ์„ฑ๋œ๋‹ค.', async () => {
45+
getAccessToken.mockResolvedValueOnce(successfulTokenResponse);
46+
getGithubUser.mockResolvedValueOnce(successfulUserResponse);
47+
userModel.exists.mockReturnValue(false);
48+
49+
const { loginToken, refreshToken } = await login('');
50+
51+
expect(loginToken).toBe(ACCESS_TOKEN);
52+
expect(refreshToken).toBe(REFRESH_TOKEN);
53+
});
54+
55+
it('์—‘์„ธ์Šค ํ† ํฐ ํš๋“ ์‹คํŒจ ์‹œ ์—๋Ÿฌ๋ฅผ ๋˜์ง„๋‹ค.', async () => {
56+
getAccessToken.mockRejectedValueOnce(new Error('fail'));
57+
58+
expect(() => login()).rejects.toThrow('fail');
59+
});
60+
61+
it('์œ ์ € ์ •๋ณด ํš๋“ ์‹คํŒจ ์‹œ ์—๋Ÿฌ๋ฅผ ๋˜์ง„๋‹ค.', async () => {
62+
getAccessToken.mockResolvedValueOnce(successfulTokenResponse);
63+
getGithubUser.mockRejectedValueOnce(new Error('fail'));
64+
65+
expect(() => login()).rejects.toThrow('fail');
66+
});
67+
});

โ€Žserver/apis/auth/service.tsโ€Ž

Lines changed: 1 addition & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,12 @@
1-
import axios from 'axios';
2-
import env from '@config';
31
import userModel from '@apis/user/model';
42
import * as jwt from '@utils/jwt';
5-
import AuthorizationError from '@errors/authorization-error';
3+
import { getAccessToken, getGithubUser } from './service.github';
64

75
interface TokenResponse {
86
access_token: string;
97
token_type: string;
108
}
119

12-
const ACCESS_TOKEN_REQUEST_URL = 'https://github.com/login/oauth/access_token';
13-
const USER_REQUEST_URL = 'https://api.github.com/user';
14-
15-
const getAccessToken = async (code: string) => {
16-
const body = {
17-
client_id: env.GITHUB_CLIENT_ID,
18-
client_secret: env.GITHUB_CLIENT_SECRET,
19-
code,
20-
};
21-
const headers = {
22-
'Content-Type': 'application/json',
23-
Accept: 'application/json',
24-
};
25-
26-
const { data: accessTokenResponse } = await axios.post(
27-
ACCESS_TOKEN_REQUEST_URL,
28-
body,
29-
{
30-
headers,
31-
},
32-
);
33-
34-
if (accessTokenResponse.error) {
35-
throw new AuthorizationError('access token ์ƒ์„ฑ ์š”์ฒญ ์‹คํŒจ');
36-
}
37-
38-
return accessTokenResponse;
39-
};
40-
41-
const getGithubUser = async (accessToken: string, tokenType: string) => {
42-
const { data: user } = await axios.get(USER_REQUEST_URL, {
43-
headers: {
44-
Authorization: `${tokenType} ${accessToken}`,
45-
},
46-
});
47-
48-
if (user.error) {
49-
throw new AuthorizationError('OAuth ์œ ์ € ์ •๋ณด ์š”์ฒญ ์‹คํŒจ');
50-
}
51-
52-
return user;
53-
};
54-
5510
export const login = async (code: string) => {
5611
const { access_token: accessToken, token_type: tokenType }: TokenResponse =
5712
await getAccessToken(code);

โ€Žserver/dummy.test.tsโ€Ž

Lines changed: 0 additions & 3 deletions
This file was deleted.

0 commit comments

Comments
ย (0)