Skip to content

Commit 6c37c1d

Browse files
chore: Add test (#47)
* chore: Add test * Fix comments * Update with main * Fix comments
1 parent 3821bd0 commit 6c37c1d

File tree

6 files changed

+267
-36
lines changed

6 files changed

+267
-36
lines changed

src/services/auth.test.ts

Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
import * as bcrypt from 'bcryptjs';
2+
import { faker } from '@faker-js/faker';
3+
4+
import { AuthService } from 'services/auth';
5+
import prisma from 'root/prisma/client';
6+
import {
7+
generateSessionData,
8+
generateUserData,
9+
} from 'tests/utils/generateData';
10+
import { ApiError } from 'utils/apiError';
11+
import { errors } from 'config/errors';
12+
13+
const userData = generateUserData();
14+
const hashedPassword = bcrypt.hashSync(userData.password, 8);
15+
const { id, createdAt, updatedAt, ...registerBody } = userData;
16+
const loginParams = {
17+
email: userData.email,
18+
password: userData.password,
19+
};
20+
21+
const jwtRegex = /^(\w|\d|\.)+/;
22+
23+
const mockAccessToken = faker.string.alphanumeric({
24+
length: 50,
25+
});
26+
const mockRefreshToken = faker.string.alphanumeric({
27+
length: 50,
28+
});
29+
const sessionData = generateSessionData({
30+
accessToken: mockAccessToken,
31+
refreshToken: mockRefreshToken,
32+
userId: userData.id,
33+
});
34+
35+
jest.mock('queue/queue');
36+
37+
describe('Auth service: ', () => {
38+
beforeEach(() => {
39+
jest.clearAllMocks();
40+
});
41+
42+
describe('register functionality', () => {
43+
test('should create new user', async () => {
44+
await expect(AuthService.register(registerBody)).resolves.toEqual({
45+
accessToken: expect.stringMatching(jwtRegex),
46+
refreshToken: expect.stringMatching(jwtRegex),
47+
});
48+
49+
await expect(
50+
prisma.user.findUnique({
51+
where: {
52+
email: registerBody.email,
53+
},
54+
}),
55+
).resolves.not.toBeNull();
56+
57+
const testSession = async () => {
58+
const user = await prisma.user.findUnique({
59+
where: {
60+
email: registerBody.email,
61+
},
62+
});
63+
64+
return prisma.session.findUnique({
65+
where: {
66+
userId: user?.id,
67+
},
68+
});
69+
};
70+
71+
await expect(testSession()).resolves.not.toBeNull();
72+
});
73+
74+
describe('User already exist', () => {
75+
test('should throw an error', async () => {
76+
await prisma.user.create({
77+
data: registerBody,
78+
});
79+
80+
await expect(AuthService.register(registerBody)).rejects.toThrowError(
81+
new ApiError(errors.USER_ALREADY_EXISTS),
82+
);
83+
});
84+
});
85+
});
86+
87+
describe('login functionality', () => {
88+
describe('User exists', () => {
89+
beforeEach(async () => {
90+
await prisma.user.create({
91+
data: {
92+
...userData,
93+
password: hashedPassword,
94+
},
95+
});
96+
});
97+
98+
test('should login successfully', async () => {
99+
await expect(AuthService.login(loginParams)).resolves.toEqual({
100+
accessToken: expect.stringMatching(jwtRegex),
101+
refreshToken: expect.stringMatching(jwtRegex),
102+
});
103+
});
104+
105+
test('wrong password', async () => {
106+
await expect(
107+
AuthService.login({
108+
...loginParams,
109+
password: `${loginParams.password} wrong`,
110+
}),
111+
).rejects.toThrow(new ApiError(errors.INVALID_CREDENTIALS));
112+
});
113+
});
114+
115+
test('wrong email', async () => {
116+
await expect(AuthService.login(loginParams)).rejects.toThrow(
117+
new ApiError(errors.INVALID_CREDENTIALS),
118+
);
119+
});
120+
});
121+
122+
describe('refresh functionality', () => {
123+
test('should refresh access token successfully', async () => {
124+
await prisma.user.create({
125+
data: userData,
126+
});
127+
await prisma.session.create({
128+
data: sessionData,
129+
});
130+
131+
await expect(
132+
AuthService.refresh({
133+
refreshToken: mockRefreshToken,
134+
}),
135+
).resolves.toEqual({
136+
accessToken: expect.stringMatching(jwtRegex),
137+
refreshToken: expect.stringMatching(jwtRegex),
138+
});
139+
});
140+
141+
test('session does not exist', async () => {
142+
await expect(
143+
AuthService.refresh({
144+
refreshToken: mockRefreshToken,
145+
}),
146+
).rejects.toThrow(new ApiError(errors.UNAUTHENTICATED));
147+
});
148+
149+
test('user does not exist', async () => {
150+
await prisma.session.create({
151+
data: sessionData,
152+
});
153+
154+
await expect(
155+
AuthService.refresh({
156+
refreshToken: mockRefreshToken,
157+
}),
158+
).rejects.toThrow(new ApiError(errors.NOT_FOUND_USER));
159+
});
160+
});
161+
});

src/services/auth.ts

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,21 @@
1-
import jwt from 'jsonwebtoken';
21
import * as bcrypt from 'bcryptjs';
3-
import { config } from 'config/config';
42
import {
53
ReturnAuth,
64
CreateUserParams,
7-
ReturnUser,
85
LoginParams,
96
RefreshTokenParams,
107
} from 'types';
118
import prisma from 'root/prisma/client';
129
import { ApiError } from 'utils/apiError';
1310
import { errors } from 'config/errors';
11+
import { generateAccessToken, generateRefreshToken } from 'utils/token';
1412
import { UserService } from '.';
1513

1614
export class AuthService {
1715
static register = async (userBody: CreateUserParams): Promise<ReturnAuth> => {
1816
const user = await UserService.create(userBody);
19-
const accessToken = await this.generateAccessToken(user);
20-
const refreshToken = await this.generateRefreshToken(user);
17+
const accessToken = await generateAccessToken(user);
18+
const refreshToken = await generateRefreshToken(user);
2119
const sessionData = {
2220
userId: user.id,
2321
accessToken,
@@ -44,7 +42,7 @@ export class AuthService {
4442
const session = await prisma.session.findUnique({
4543
where: { userId: user.id },
4644
});
47-
const accessToken = await this.generateAccessToken(user);
45+
const accessToken = await generateAccessToken(user);
4846
if (session) {
4947
await prisma.session.update({
5048
where: { id: session.id },
@@ -56,7 +54,7 @@ export class AuthService {
5654
};
5755
}
5856

59-
const refreshToken = await this.generateRefreshToken(user);
57+
const refreshToken = await generateRefreshToken(user);
6058
const sessionData = {
6159
userId: user.id,
6260
accessToken,
@@ -90,7 +88,7 @@ export class AuthService {
9088
throw new ApiError(errors.NOT_FOUND_USER);
9189
}
9290

93-
const accessToken = await this.generateAccessToken(user);
91+
const accessToken = await generateAccessToken(user);
9492
await prisma.session.update({
9593
where: { userId: user.id },
9694
data: { accessToken },
@@ -100,14 +98,4 @@ export class AuthService {
10098
refreshToken,
10199
};
102100
};
103-
104-
static generateAccessToken = async (user: ReturnUser): Promise<string> =>
105-
jwt.sign({ user }, config.accessTokenSecret, {
106-
expiresIn: config.accessTokenExpiresIn,
107-
});
108-
109-
static generateRefreshToken = async (user: ReturnUser): Promise<string> =>
110-
jwt.sign({ user }, config.refreshTokenSecret, {
111-
expiresIn: config.refreshTokenExpiresIn,
112-
});
113101
}

src/services/user.test.ts

Lines changed: 75 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,14 @@ import { faker } from '@faker-js/faker';
55
import prisma from 'root/prisma/client';
66
import { generateTokenData, generateUserData } from 'tests/utils/generateData';
77
import { UserService } from 'services/user';
8-
import { sendUserWithoutPassword } from 'utils/user';
98
import * as queues from 'queue/queue';
109
import { EmailTypes } from 'types';
1110
import { ApiError } from 'utils/apiError';
1211
import { errors } from 'config/errors';
1312

14-
jest.mock('utils/user');
13+
jest.mock('emails/index');
1514
jest.mock('queue/queue');
1615

17-
const mockSendUserWithoutPassword = sendUserWithoutPassword as jest.Mock;
18-
1916
const mockCode = String(Math.floor(100000 + Math.random() * 900000));
2017

2118
const userData = generateUserData();
@@ -28,15 +25,17 @@ const tokenData = generateTokenData({
2825
describe('User service: ', () => {
2926
afterEach(jest.clearAllMocks);
3027

31-
describe('create function', () => {
28+
describe('create functionality', () => {
3229
test('should create a new user with email', async () => {
3330
const spyAddToMailQueue = jest.spyOn(queues, 'addToMailQueue');
34-
const { password, ...userWithoutPassword } = userData;
35-
mockSendUserWithoutPassword.mockResolvedValue(userWithoutPassword);
3631

37-
await expect(UserService.create(userData)).resolves.toEqual(
38-
userWithoutPassword,
39-
);
32+
await expect(UserService.create(userData)).resolves.toEqual({
33+
createdAt: expect.anything(),
34+
email: userData.email,
35+
id: expect.stringMatching(/^(\d|\w|-)+/),
36+
name: userData.name,
37+
updatedAt: expect.anything(),
38+
});
4039

4140
expect(spyAddToMailQueue).toHaveBeenCalledWith('Sign up Email', {
4241
emailType: EmailTypes.SIGN_UP,
@@ -169,5 +168,71 @@ describe('User service: ', () => {
169168
).rejects.toThrow(new ApiError(errors.CODE_EXPIRED));
170169
});
171170
});
171+
172+
describe('find functionality', () => {
173+
test('should return user', async () => {
174+
await prisma.user.create({
175+
data: userData,
176+
});
177+
const { password, ...userWithoutPassword } = userData;
178+
179+
await expect(UserService.find(userData.id)).resolves.toEqual(
180+
userWithoutPassword,
181+
);
182+
});
183+
184+
test('user does not exist', async () => {
185+
await expect(UserService.find(faker.string.uuid())).rejects.toThrow(
186+
new ApiError(errors.NOT_FOUND_USER),
187+
);
188+
});
189+
});
190+
191+
describe('update functionality', () => {
192+
test('should update user', async () => {
193+
const updatedUser = {
194+
...userData,
195+
name: 'New name',
196+
};
197+
198+
await prisma.user.create({
199+
data: userData,
200+
});
201+
202+
const { password, ...userWithoutPassword } = updatedUser;
203+
204+
await expect(
205+
UserService.update(userData.id, updatedUser),
206+
).resolves.toEqual(userWithoutPassword);
207+
});
208+
209+
describe('invalid data', () => {
210+
test('user does not exist', async () => {
211+
await expect(
212+
UserService.update(userData.id, userData),
213+
).rejects.toThrow(new ApiError(errors.NOT_FOUND_USER));
214+
});
215+
});
216+
});
217+
218+
describe('delete functionality', () => {
219+
test('should delete user', async () => {
220+
await prisma.user.create({
221+
data: userData,
222+
});
223+
224+
await expect(UserService.destroy(userData.id)).resolves.toEqual(
225+
undefined,
226+
);
227+
});
228+
229+
describe('invalid data', () => {
230+
test('user does not exist', async () => {
231+
await expect(UserService.destroy(userData.id)).rejects.toThrow(
232+
new ApiError(errors.NOT_FOUND_USER),
233+
);
234+
});
235+
});
236+
});
172237
});
173238
});

src/services/usersMocked.test.ts

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@ import { prismaMock } from 'tests/prismaSetup';
22
import { generateUserData } from 'tests/utils/generateData';
33
import { UserService } from 'services/user';
44
import { sendUserWithoutPassword } from 'utils/user';
5-
import { addToMailQueue } from 'queue/queue';
65

76
jest.mock('emails/index');
87
jest.mock('utils/user');
98
jest.mock('queue/queue');
109

11-
const mockMailQueueAdd = addToMailQueue as jest.Mock;
1210
const userData = generateUserData();
1311

1412
/*
@@ -18,10 +16,6 @@ since we might have a test with prisma mocked in there.
1816
*/
1917

2018
describe('User service: ', () => {
21-
beforeEach(() => {
22-
mockMailQueueAdd.mockResolvedValue(undefined);
23-
});
24-
2519
afterEach(() => {
2620
jest.clearAllMocks();
2721
});

src/tests/utils/generateData.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { faker } from '@faker-js/faker';
2-
3-
import { User, Tokens, TypeToken } from '@prisma/client';
2+
import { Session, User, Tokens, TypeToken } from '@prisma/client';
43
import { endOfTomorrow } from 'date-fns';
54

65
export const generateUserData = (opts?: Partial<User>) => ({
@@ -23,3 +22,13 @@ export const generateTokenData = (opts?: Partial<Tokens>) => ({
2322
token: faker.string.alphanumeric(),
2423
...opts,
2524
});
25+
26+
export const generateSessionData = (opts?: Partial<Session>) => ({
27+
id: faker.string.uuid(),
28+
createdAt: faker.date.anytime(),
29+
updatedAt: faker.date.anytime(),
30+
accessToken: faker.string.alphanumeric(50),
31+
refreshToken: faker.string.alphanumeric(50),
32+
userId: faker.string.uuid(),
33+
...opts,
34+
});

0 commit comments

Comments
 (0)