Skip to content

Commit f214d9b

Browse files
committed
modify tests for the code refactor
1 parent d19068c commit f214d9b

File tree

9 files changed

+116
-83
lines changed

9 files changed

+116
-83
lines changed

src/auth/authentication.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import JWT from '../core/JWT';
66
import KeystoreRepo from '../database/repository/KeystoreRepo';
77
import { Types } from 'mongoose';
88
import { getAccessToken, validateTokenData } from './authUtils';
9-
import { tokenInfo } from '../config';
109
import validator, { ValidationSource } from '../helpers/validator';
1110
import schema from './schema';
1211
import asyncHandler from '../helpers/asyncHandler';
@@ -26,10 +25,7 @@ export default router.use(validator(schema.auth, ValidationSource.HEADER),
2625
req.user = user;
2726

2827
const keystore = await KeystoreRepo.findforKey(req.user._id, payload.prm);
29-
30-
if (!keystore || keystore.primaryKey !== payload.prm)
31-
throw new AuthFailureError('Invalid access token');
32-
28+
if (!keystore) throw new AuthFailureError('Invalid access token');
3329
req.keystore = keystore;
3430

3531
return next();

tests/auth/apikey/unit.test.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,13 +11,13 @@ describe('apikey validation', () => {
1111
mockFindApiKey.mockClear();
1212
});
1313

14-
it('Should response with 400 if api-key header is not passed', async () => {
14+
it('Should response with 400 if x-api-key header is not passed', async () => {
1515
const response = await request.get(endpoint);
1616
expect(response.status).toBe(400);
1717
expect(mockFindApiKey).not.toBeCalled();
1818
});
1919

20-
it('Should response with 403 if wrong api-key header is passed', async () => {
20+
it('Should response with 403 if wrong x-api-key header is passed', async () => {
2121
const wrongApiKey = '123';
2222
const response = await request
2323
.get(endpoint)
@@ -27,7 +27,7 @@ describe('apikey validation', () => {
2727
expect(mockFindApiKey).toBeCalledWith(wrongApiKey);
2828
});
2929

30-
it('Should response with 404 if correct api-key header is passed and when route is not handelled', async () => {
30+
it('Should response with 404 if correct x-api-key header is passed and when route is not handelled', async () => {
3131
const response = await request
3232
.get(endpoint)
3333
.set('x-api-key', API_KEY);

tests/auth/authUtils/unit.test.ts

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,59 +12,53 @@ describe('authUtils validateTokenData tests', () => {
1212
jest.resetAllMocks();
1313
});
1414

15-
it('Should throw error when user is different', async () => {
16-
17-
const userId = new Types.ObjectId(); // Random Key
15+
it('Should throw error when subject in not user id format', async () => {
1816

1917
const payload = new JwtPayload(
2018
tokenInfo.issuer,
2119
tokenInfo.audience,
22-
new Types.ObjectId().toHexString(), // Random Key
20+
'abc',
2321
ACCESS_TOKEN_KEY,
2422
tokenInfo.accessTokenValidityDays
2523
);
2624

2725
try {
28-
await validateTokenData(payload, userId);
26+
validateTokenData(payload);
2927
} catch (e) {
3028
expect(e).toBeInstanceOf(AuthFailureError);
3129
}
3230
});
3331

3432
it('Should throw error when access token key is different', async () => {
3533

36-
const userId = new Types.ObjectId(); // Random Key
37-
3834
const payload = new JwtPayload(
3935
tokenInfo.issuer,
4036
tokenInfo.audience,
41-
userId.toHexString(),
37+
new Types.ObjectId().toHexString(),
4238
'123',
4339
tokenInfo.accessTokenValidityDays
4440
);
4541

4642
try {
47-
await validateTokenData(payload, userId);
43+
validateTokenData(payload);
4844
} catch (e) {
4945
expect(e).toBeInstanceOf(AuthFailureError);
5046
}
5147
});
5248

53-
it('Should return same payload if all data is correct', async () => {
54-
55-
const userId = new Types.ObjectId('553f8a4286f5c759f36f8e5b'); // Random Key
49+
it('Should return true if all data is correct', async () => {
5650

5751
const payload = new JwtPayload(
5852
tokenInfo.issuer,
5953
tokenInfo.audience,
60-
userId.toHexString(),
54+
new Types.ObjectId().toHexString(), // Random Key
6155
ACCESS_TOKEN_KEY,
6256
tokenInfo.accessTokenValidityDays
6357
);
6458

65-
const validatedPayload = await validateTokenData(payload, userId);
59+
const validatedPayload = validateTokenData(payload);
6660

67-
expect(validatedPayload).toMatchObject(payload);
61+
expect(validatedPayload).toBeTruthy();
6862
});
6963
});
7064

@@ -77,7 +71,7 @@ describe('authUtils createTokens function', () => {
7771

7872
it('Should process and return accessToken and refreshToken', async () => {
7973

80-
const userId = new Types.ObjectId('553f8a4286f5c759f36f8e5b'); // Random Key
74+
const userId = new Types.ObjectId(); // Random Key
8175

8276
const tokens = await createTokens(<User>{ _id: userId }, ACCESS_TOKEN_KEY, REFRESH_TOKEN_KEY);
8377

tests/auth/authentication/mock.ts

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,33 @@ import { API_KEY } from '../apikey/mock';
33

44
import User from '../../../src/database/model/User';
55
import { Types } from 'mongoose';
6-
import JWT, { ValidationParams, JwtPayload } from '../../../src/core/JWT';
6+
import JWT, { JwtPayload } from '../../../src/core/JWT';
77
import { BadTokenError } from '../../../src/core/ApiError';
88
import Keystore from '../../../src/database/model/Keystore';
9+
import * as authUtils from '../../../src/auth/authUtils';
10+
import { tokenInfo } from '../../../src/config';
911

1012
export const ACCESS_TOKEN = 'xyz';
1113

1214
export const USER_ID = new Types.ObjectId(); // random id with object id format
1315

16+
export const getAccessTokenSpy = jest.spyOn(authUtils, 'getAccessToken');
17+
1418
export const mockUserFindById = jest.fn(async (id: Types.ObjectId) => {
1519
if (USER_ID.equals(id)) return <User>{ _id: new Types.ObjectId(id) };
1620
else return null;
1721
});
1822

19-
export const mockJwtDecode = jest.fn(async (token: string): Promise<JwtPayload> => {
20-
if (token == ACCESS_TOKEN) return <JwtPayload>{ sub: USER_ID.toHexString() };
21-
throw new BadTokenError();
22-
});
23-
2423
export const mockJwtValidate = jest.fn(
25-
async (token: string, validations: ValidationParams): Promise<JwtPayload> => {
26-
if (token == ACCESS_TOKEN) return <JwtPayload>{ prm: 'abcdef' };
24+
async (token: string): Promise<JwtPayload> => {
25+
if (token === ACCESS_TOKEN) return <JwtPayload>{
26+
iss: tokenInfo.issuer,
27+
aud: tokenInfo.audience,
28+
sub: USER_ID.toHexString(),
29+
iat: 1,
30+
exp: 2,
31+
prm: 'abcdef'
32+
};
2733
throw new BadTokenError();
2834
});
2935

@@ -39,13 +45,12 @@ jest.mock('../../../src/database/repository/KeystoreRepo', () => ({
3945
}));
4046

4147
JWT.validate = mockJwtValidate;
42-
JWT.decode = mockJwtDecode;
4348

4449
export const addHeaders = (request: any) => request
4550
.set('Content-Type', 'application/json')
4651
.set('x-api-key', API_KEY);
4752

48-
export const addAuthHeaders = (request: any) => request
53+
export const addAuthHeaders = (request: any, accessToken = ACCESS_TOKEN) => request
4954
.set('Content-Type', 'application/json')
50-
.set('Authorization', `Bearer ${ACCESS_TOKEN}`)
55+
.set('Authorization', `Bearer ${accessToken}`)
5156
.set('x-api-key', API_KEY);
Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
2-
USER_ID, ACCESS_TOKEN, addHeaders, addAuthHeaders,
3-
mockUserFindById, mockJwtValidate, mockJwtDecode, mockKeystoreFindForKey
2+
ACCESS_TOKEN, addHeaders, addAuthHeaders,
3+
mockUserFindById, mockJwtValidate, mockKeystoreFindForKey,
4+
getAccessTokenSpy
45
} from './mock';
56

67
import app from '../../../src/app';
@@ -12,18 +13,17 @@ describe('authentication validation', () => {
1213
const request = supertest(app);
1314

1415
beforeEach(() => {
15-
mockUserFindById.mockClear();
16+
getAccessTokenSpy.mockClear();
1617
mockJwtValidate.mockClear();
17-
mockJwtDecode.mockClear();
18+
mockUserFindById.mockClear();
1819
mockKeystoreFindForKey.mockClear();
1920
});
2021

2122
it('Should response with 400 if Authorization header is not passed', async () => {
2223
const response = await addHeaders(request.get(endpoint));
2324
expect(response.status).toBe(400);
2425
expect(response.body.message).toMatch(/authorization/);
25-
expect(mockJwtDecode).not.toBeCalled();
26-
expect(mockUserFindById).not.toBeCalled();
26+
expect(getAccessTokenSpy).not.toBeCalled();
2727
});
2828

2929

@@ -32,17 +32,19 @@ describe('authentication validation', () => {
3232
.set('Authorization', '123');
3333
expect(response.status).toBe(400);
3434
expect(response.body.message).toMatch(/authorization/);
35-
expect(mockJwtDecode).not.toBeCalled();
36-
expect(mockUserFindById).not.toBeCalled();
35+
expect(getAccessTokenSpy).not.toBeCalled();
3736
});
3837

3938
it('Should response with 401 if wrong Authorization header is provided', async () => {
4039
const response = await addHeaders(request.get(endpoint))
4140
.set('Authorization', 'Bearer 123');
4241
expect(response.status).toBe(401);
4342
expect(response.body.message).toMatch(/token/i);
44-
expect(mockJwtDecode).toBeCalledTimes(1);
45-
expect(mockJwtDecode).toBeCalledWith('123');
43+
expect(getAccessTokenSpy).toBeCalledTimes(1);
44+
expect(getAccessTokenSpy).toBeCalledWith('Bearer 123');
45+
expect(getAccessTokenSpy).toReturnWith('123');
46+
expect(mockJwtValidate).toBeCalledTimes(1);
47+
expect(mockJwtValidate).toBeCalledWith('123');
4648
expect(mockUserFindById).not.toBeCalled();
4749
});
4850

@@ -51,9 +53,12 @@ describe('authentication validation', () => {
5153
expect(response.body.message).not.toMatch(/not registered/);
5254
expect(response.body.message).not.toMatch(/token/i);
5355
expect(response.status).toBe(404);
54-
expect(mockJwtDecode).toBeCalledTimes(1);
55-
expect(mockJwtDecode).toBeCalledWith(ACCESS_TOKEN);
56-
expect(mockUserFindById).toBeCalledTimes(1);
56+
expect(getAccessTokenSpy).toBeCalledTimes(1);
57+
expect(getAccessTokenSpy).toBeCalledWith(`Bearer ${ACCESS_TOKEN}`);
58+
expect(getAccessTokenSpy).toReturnWith(ACCESS_TOKEN);
5759
expect(mockJwtValidate).toBeCalledTimes(1);
60+
expect(mockJwtValidate).toBeCalledWith(ACCESS_TOKEN);
61+
expect(mockUserFindById).toBeCalledTimes(1);
62+
expect(mockKeystoreFindForKey).toBeCalledTimes(1);
5863
});
5964
});

tests/auth/authorization/mock.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
// all dependent mock should be on the top
2-
import { USER_ID } from '../authentication/mock';
2+
import { USER_ID, ACCESS_TOKEN } from '../authentication/mock';
33

44
import { Types } from 'mongoose';
55
import User from '../../../src/database/model/User';
66
import Role, { RoleCode } from '../../../src/database/model/Role';
7+
import { BadTokenError } from '../../../src/core/ApiError';
8+
import JWT, { JwtPayload } from '../../../src/core/JWT';
9+
import { tokenInfo } from '../../../src/config';
710

811
export const LEARNER_ROLE_ID = new Types.ObjectId(); // random id
912
export const WRITER_ROLE_ID = new Types.ObjectId(); // random id
@@ -12,6 +15,9 @@ export const EDITOR_ROLE_ID = new Types.ObjectId(); // random id
1215
export const USER_ID_WRITER = new Types.ObjectId(); // random id
1316
export const USER_ID_EDITOR = new Types.ObjectId(); // random id
1417

18+
export const WRITER_ACCESS_TOKEN = 'def';
19+
export const EDITOR_ACCESS_TOKEN = 'ghi';
20+
1521
export const mockUserFindById = jest.fn(async (id: Types.ObjectId) => {
1622
if (USER_ID.equals(id)) return <User>{
1723
_id: USER_ID,
@@ -58,10 +64,37 @@ export const mockRoleRepoFindByCode = jest.fn(
5864
return null;
5965
});
6066

67+
export const mockJwtValidate = jest.fn(
68+
async (token: string): Promise<JwtPayload> => {
69+
let subject = null;
70+
switch (token) {
71+
case ACCESS_TOKEN:
72+
subject = USER_ID.toHexString();
73+
break;
74+
case WRITER_ACCESS_TOKEN:
75+
subject = USER_ID_WRITER.toHexString();
76+
break;
77+
case EDITOR_ACCESS_TOKEN:
78+
subject = USER_ID_EDITOR.toHexString();
79+
break;
80+
}
81+
if (subject) return <JwtPayload>{
82+
iss: tokenInfo.issuer,
83+
aud: tokenInfo.audience,
84+
sub: subject,
85+
iat: 1,
86+
exp: 2,
87+
prm: 'abcdef'
88+
};
89+
throw new BadTokenError();
90+
});
91+
6192
jest.mock('../../../src/database/repository/UserRepo', () => ({
6293
get findById() { return mockUserFindById; }
6394
}));
6495

6596
jest.mock('../../../src/database/repository/RoleRepo', () => ({
6697
get findByCode() { return mockRoleRepoFindByCode; }
67-
}));
98+
}));
99+
100+
JWT.validate = mockJwtValidate;

tests/auth/authorization/unit.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { addAuthHeaders } from '../authentication/mock';
22

33
// import the mock for the current test after all other mock imports
44
// this will prevent the different implementations by the other mock
5-
import { mockRoleRepoFindByCode, mockUserFindById } from './mock';
5+
import { mockRoleRepoFindByCode, mockUserFindById, EDITOR_ACCESS_TOKEN } from './mock';
66

77
import app from '../../../src/app';
88
import supertest from 'supertest';
@@ -39,7 +39,7 @@ describe('authentication validation for writer', () => {
3939
});
4040

4141
it('Should response with 404 if user have writer role', async () => {
42-
const response = await addAuthHeaders(request.get(endpoint));
42+
const response = await addAuthHeaders(request.get(endpoint), EDITOR_ACCESS_TOKEN);
4343
expect(response.status).toBe(404);
4444
expect(mockRoleRepoFindByCode).toBeCalledTimes(1);
4545
expect(mockUserFindById).toBeCalledTimes(1);

tests/core/jwt/unit.test.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { readFileSpy } from './mock';
2-
import JWT, { JwtPayload, ValidationParams } from '../../../src/core/JWT';
2+
import JWT, { JwtPayload } from '../../../src/core/JWT';
33
import { BadTokenError, TokenExpiredError } from '../../../src/core/ApiError';
44

55
describe('JWT class tests', () => {
@@ -17,7 +17,7 @@ describe('JWT class tests', () => {
1717
});
1818

1919
try {
20-
await JWT.decode('abc', new ValidationParams(issuer, audience, subject));
20+
await JWT.decode('abc');
2121
} catch (e) {
2222
expect(e).toBeInstanceOf(BadTokenError);
2323
}
@@ -46,7 +46,7 @@ describe('JWT class tests', () => {
4646

4747
const payload = new JwtPayload(issuer, audience, subject, param, validity);
4848
const token = await JWT.encode(payload);
49-
const decoded = await JWT.decode(token, new ValidationParams(issuer, audience, subject));
49+
const decoded = await JWT.decode(token);
5050

5151
expect(decoded).toMatchObject(payload);
5252
expect(readFileSpy).toBeCalledTimes(2);
@@ -69,7 +69,7 @@ describe('JWT class tests', () => {
6969
prm: param,
7070
};
7171
const token = await JWT.encode(payload);
72-
const decoded = await JWT.decode(token, new ValidationParams(issuer, audience, subject));
72+
const decoded = await JWT.decode(token);
7373

7474
expect(decoded).toMatchObject(payload);
7575
expect(readFileSpy).toBeCalledTimes(2);
@@ -82,7 +82,7 @@ describe('JWT class tests', () => {
8282
});
8383

8484
try {
85-
await JWT.validate('abc', new ValidationParams(issuer, audience, subject));
85+
await JWT.validate('abc');
8686
} catch (e) {
8787
expect(e).toBeInstanceOf(BadTokenError);
8888
}
@@ -98,7 +98,7 @@ describe('JWT class tests', () => {
9898

9999
const payload = new JwtPayload(issuer, audience, subject, param, validity);
100100
const token = await JWT.encode(payload);
101-
const decoded = await JWT.validate(token, new ValidationParams(issuer, audience, subject));
101+
const decoded = await JWT.validate(token);
102102

103103
expect(decoded).toMatchObject(payload);
104104
expect(readFileSpy).toBeCalledTimes(2);
@@ -122,7 +122,7 @@ describe('JWT class tests', () => {
122122
};
123123
const token = await JWT.encode(payload);
124124
try {
125-
await JWT.validate(token, new ValidationParams(issuer, audience, subject));
125+
await JWT.validate(token);
126126
} catch (e) {
127127
expect(e).toBeInstanceOf(TokenExpiredError);
128128
}

0 commit comments

Comments
 (0)