Skip to content

Commit a4cacfe

Browse files
committed
Add backend auth tests and rewrite the module to be a fit for tests.
1 parent 7dd9cc6 commit a4cacfe

File tree

4 files changed

+121
-21
lines changed

4 files changed

+121
-21
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
import {mock, expect, describe, it, afterEach} from "bun:test"
2+
import {InvalidCredentials} from "./login.ts";
3+
import {login} from "./login.ts";
4+
5+
const mockFindUserEmail = mock()
6+
const mockVerifyPassword = mock()
7+
const mockSignToken = mock()
8+
9+
mock.module("../repo/user.repo.js", () => {
10+
return {
11+
findUserByEmail: mockFindUserEmail,
12+
}
13+
})
14+
15+
mock.module("../impl/password.js", () => {
16+
return {
17+
verifyPassword: mockVerifyPassword,
18+
}
19+
})
20+
21+
mock.module("../impl/jwt.js", () => {
22+
return {
23+
signToken: mockSignToken,
24+
}
25+
})
26+
27+
28+
afterEach(() => {
29+
mockFindUserEmail.mockReset()
30+
mockVerifyPassword.mockReset()
31+
mockSignToken.mockReset()
32+
})
33+
34+
describe("Login function", () => {
35+
const email = 'test@mail.com'
36+
const password = '123456'
37+
const userId = '123'
38+
const token = 'fake.token'
39+
const passwordHash = 'hashedpassword'
40+
it("Throws if email does not exists", async () => {
41+
mockFindUserEmail.mockResolvedValue({id: userId, password_hash: passwordHash})
42+
mockVerifyPassword.mockResolvedValue(false)
43+
mockSignToken.mockResolvedValue({sub: userId})
44+
return expect(login({
45+
email,
46+
password
47+
})).rejects.toBeInstanceOf(InvalidCredentials)
48+
})
49+
50+
it("Throws if password is incorrect", async () => {
51+
mockFindUserEmail.mockResolvedValue({id: userId, password_hash: passwordHash})
52+
mockVerifyPassword.mockResolvedValue(false, )
53+
mockSignToken.mockResolvedValue({sub: userId})
54+
return expect(login({
55+
email,
56+
password
57+
})).rejects.toBeInstanceOf(InvalidCredentials)
58+
})
59+
60+
it("Resolves when email exists and password is correct", async () => {
61+
mockFindUserEmail.mockResolvedValue({id: userId, password_hash: passwordHash})
62+
mockVerifyPassword.mockResolvedValue(true)
63+
mockSignToken.mockResolvedValue(token)
64+
const user = await login({
65+
email,
66+
password
67+
})
68+
expect(mockFindUserEmail).toHaveBeenCalledTimes(1)
69+
expect(mockFindUserEmail).toHaveBeenCalledWith(email)
70+
71+
expect(mockVerifyPassword).toHaveBeenCalledTimes(1)
72+
expect(mockVerifyPassword).toHaveBeenCalledWith(password, passwordHash)
73+
74+
expect(mockSignToken).toHaveBeenCalledTimes(1)
75+
expect(mockSignToken).toHaveBeenCalledWith({sub: userId})
76+
77+
expect(user).toBe(token)
78+
})
79+
})

backend/src/modules/auth/logic/login.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export class InvalidCredentials extends Error {}
66

77
export async function login({email, password}: {email: string, password: string}) {
88
const user = await findUserByEmail(email)
9+
if (!user) throw new InvalidCredentials("Email does not exist")
910

1011
const validPassword = await verifyPassword(password, user.password_hash)
1112
if (!validPassword) throw new InvalidCredentials('Invalid password')

backend/src/modules/auth/logic/signup.test.ts

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import {mock, expect, describe, it} from "bun:test"
1+
import {mock, expect, describe, it, afterEach} from "bun:test"
22
import {signup} from "./signup.ts";
33
import {InvalidCredentials} from "./signup.ts";
44

@@ -19,13 +19,45 @@ mock.module("../impl/password.js", () => {
1919
}
2020
})
2121

22-
describe("signup function", () => {
22+
afterEach(() => {
23+
mockFindUserEmail.mockReset()
24+
mockCreateUser.mockReset()
25+
mockHashPassword.mockReset()
26+
})
27+
28+
describe("Signup function", () => {
29+
const email = 'test@mail.com'
30+
const username = 'test'
31+
const password = '123456'
32+
const passwordHash = 'hashedpassword'
33+
const userId = '123'
2334
it("Throws if email already exists", async () => {
2435
mockFindUserEmail.mockResolvedValue({id: '123'})
25-
expect(signup({
26-
email: "test@mail.com",
27-
username: "test",
28-
password: "123456"
36+
return expect(signup({
37+
email,
38+
username,
39+
password
2940
})).rejects.toBeInstanceOf(InvalidCredentials)
3041
})
42+
43+
it("Resolves when the email does not exist", async () => {
44+
mockFindUserEmail.mockResolvedValue(null)
45+
mockHashPassword.mockResolvedValue(passwordHash)
46+
mockCreateUser.mockResolvedValue( userId)
47+
const user = await signup({
48+
email,
49+
username,
50+
password
51+
})
52+
expect(mockFindUserEmail).toHaveBeenCalledTimes(1)
53+
expect(mockFindUserEmail).toHaveBeenCalledWith(email)
54+
55+
expect(mockHashPassword).toHaveBeenCalledTimes(1)
56+
expect(mockHashPassword).toHaveBeenCalledWith(password)
57+
58+
expect(mockCreateUser).toHaveBeenCalledTimes(1)
59+
expect(mockCreateUser).toHaveBeenCalledWith({email, username, passwordHash})
60+
61+
expect(user).toBe(userId)
62+
})
3163
})

backend/src/modules/auth/repo/user.repo.ts

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,27 +16,15 @@ export async function createUser({email, username, passwordHash}: {email: string
1616

1717
export async function findUserByEmail(email: string) {
1818
const rows = await findUserByEmailRaw.run({email}, db)
19-
const row = rows[0]
20-
if (!row) {
21-
throw new Error('FindUserByEmail returned no rows.');
22-
}
23-
return row
19+
return rows[0]
2420
}
2521

2622
export async function findUserByUsername(username: string) {
2723
const rows = await findUserByUsernameRaw.run({username}, db)
28-
const row = rows[0]
29-
if (!row) {
30-
throw new Error('FindUserByUsername returned no rows.');
31-
}
32-
return row
24+
return rows[0]
3325
}
3426

3527
export async function findUserById(id: string) {
3628
const rows = await findUserByIdRaw.run({id}, db)
37-
const row = rows[0]
38-
if (!row) {
39-
throw new Error('FindUserById returned no rows.');
40-
}
41-
return row
29+
return rows[0]
4230
}

0 commit comments

Comments
 (0)