Skip to content

Commit

Permalink
refactor/backend testing for services (#159)
Browse files Browse the repository at this point in the history
* add more tests for securePassword service

* add more tests for transaction service

* refactor/format document

* refactor/refine some tests in userService

* refactor/fix typo

* delete unused imporrt
  • Loading branch information
joh748 authored Sep 24, 2024
1 parent 46f54cc commit f63e8d5
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 25 deletions.
21 changes: 14 additions & 7 deletions backend/src/services/userService.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ const checkEmailExists = async (email) => {
text: 'SELECT * FROM users WHERE email = $1',
values: [email],
};

try { const result = await pool.query(query);
return result.rows.length > 0;
return result.rows.length > 0;
} catch (error) {
console.error('An error occurred while checking email:', error);
return false;
Expand All @@ -48,13 +49,19 @@ const checkPasswordCorrect = async (email, password) => {
text: 'SELECT password FROM users WHERE email = $1',
values: [email],
};
try {const result = await pool.query(query);
if (result.rows.length === 0) {
return false;
}
const hashedPassword = result.rows[0].password;
const passwordsMatch = await securePassword.comparePasswords(password, hashedPassword);

try {
const result = await pool.query(query);

if (result.rows.length === 0) {
return false;
}

const hashedPassword = result.rows[0].password;
const passwordsMatch = await securePassword.comparePasswords(password, hashedPassword);

return passwordsMatch;

} catch (error) {

console.error('An error occurred while checking password:', error);
Expand Down
35 changes: 35 additions & 0 deletions backend/test/service/securePassword.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,18 @@ describe('securePassword', () => {
expect(error.message).to.equal('Error hashing password');
}
});

// Test if hashed password != plain password
it('should return a hashed password as a different string', async () => {
const plainPassword = 'MyPassword123';
const hashedPassword = await securePassword.hashPassword(plainPassword);

// The hashed password should be a string
expect(typeof(hashedPassword)).to.be.a('string')

// The hashed password should not match the plain text password
expect(hashedPassword).to.not.equal(plainPassword);
});
});

// Test suite for the comparePasswords function
Expand Down Expand Up @@ -114,5 +126,28 @@ describe('securePassword', () => {
expect(error.message).to.equal('Error comparing passwords');
}
});

// Test if comparing the same passwords gives true
it('should return true for matching passwords', async () => {
const plainPassword = 'MyPassword123';
const hashedPassword = await securePassword.hashPassword(plainPassword);

const result = await securePassword.comparePasswords(plainPassword, hashedPassword);

// Assert that the passwords match
expect(result).to.be.true;
});

// Test if comparing a different passwords gives false
it('should return false for non-matching passwords', async () => {
const plainPassword = 'MyPassword123';
const wrongPassword = 'WrongPassword123';
const hashedPassword = await securePassword.hashPassword(plainPassword);

const result = await securePassword.comparePasswords(wrongPassword, hashedPassword);

// Assert that the passwords don't match
expect(result).to.be.false;
});
});
});
21 changes: 21 additions & 0 deletions backend/test/service/transactionService.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,25 @@ describe('transactionService', () => {
expect(poolQueryStub.calledOnce).to.be.true; // Expect the pool query function to be called once
});

// Test if get user transaction by page calls the sql query
it('should return paginated transactions for a user', async () => {
const userID = 1;
const pageNumber = 2;
const mockTransactions = [
{ id: 1, amount: 100, title: 'Transaction 1' },
{ id: 2, amount: 200, title: 'Transaction 2' },
];

poolQueryStub.resolves({ rows: mockTransactions });

const result = await transactionService.getUserTransactionsByPage(userID, pageNumber);

expect(poolQueryStub.calledOnce).to.be.true;
expect(result).to.deep.equal(mockTransactions);
expect(poolQueryStub.firstCall.args[0].text).to.include('SELECT * FROM transactions');
expect(poolQueryStub.firstCall.args[0].values).to.deep.equal([userID, 10, 10]); // Check OFFSET is correct
});

// Test case for an error during the query
it('should handle errors and throw the error', async () => {
// Stub the pool query function to reject with an error
Expand Down Expand Up @@ -87,7 +106,9 @@ describe('transactionService', () => {

expect(poolQueryStub.calledTwice).to.be.true; // Expect the pool query function to be called twice
expect(poolQueryStub.firstCall.args[0].text).to.include('INSERT INTO transactions'); // Expect the first query to be an insert query
expect(poolQueryStub.firstCall.args[0].values).to.deep.equal([userID, amount, title, description]);
expect(poolQueryStub.secondCall.args[0].text).to.include('UPDATE users SET balance'); // Expect the second query to be an update query
expect(poolQueryStub.secondCall.args[0].values).to.deep.equal([amount, userID]);
});

// Test case for an error during the transaction
Expand Down
41 changes: 23 additions & 18 deletions backend/test/service/userService.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ describe('userService', () => {
poolQueryStub.resolves(mockResult);

// Call the getUserID function with the stubbed pool query
const userId = await userService.getUserID('test');
const userId = await userService.getUserID('test@example.com');

expect(userId).to.equal(1); // Expect the user ID to be 1
expect(poolQueryStub.calledOnce).to.be.true; // Expect the pool query function to be called once
Expand All @@ -52,19 +52,22 @@ describe('userService', () => {
poolQueryStub.resolves(mockResult);

// Call the getUserID function with the stubbed pool query
const userId = await userService.getUserID('test');
const userId = await userService.getUserID('test@example.com');

expect(userId).to.be.null; // Expect the user ID to be null
expect(poolQueryStub.calledOnce).to.be.true; // Expect the pool query function to be called once
});

// Test case for an error during the query
it('should throw an error if the query fails', async () => {
// Stub the pool query function to reject with an error
poolQueryStub.rejects(new Error('Query failed'));

// Call the getUserID function with a test email and expect an error to be thrown
expect(userService.getUserID('test')).to.throw;
const mockError = new Error('Query failed');
poolQueryStub.rejects(mockError);

try {
await userService.getUserID('[email protected]');
} catch (error) {
expect(error).to.equal(mockError);
}
});
});

Expand All @@ -85,13 +88,13 @@ describe('userService', () => {
// Test case for an existing email
it('should return true if the email exists', async () => {
// Mock the query result to return an array with an email
const mockResult = { rows: [{ email: 'test' }] };
const mockResult = { rows: [{ email: 'test@example.com' }] };

// Stub the pool query function to resolve with the mock result
poolQueryStub.resolves(mockResult);

// Call the checkEmailExists function with the stubbed pool query
const exists = await userService.checkEmailExists('test');
const exists = await userService.checkEmailExists('test@example.com');

// Expect the result to be true, indicating email exists
expect(exists).to.be.true;
Expand All @@ -106,7 +109,7 @@ describe('userService', () => {
poolQueryStub.resolves(mockResult);

// Call the checkEmailExists function with the pool query stub
const exists = await userService.checkEmailExists('test');
const exists = await userService.checkEmailExists('test@example.com');

// Expect the result to be false, indicating email does not exist
expect(exists).to.be.false;
Expand Down Expand Up @@ -142,10 +145,11 @@ describe('userService', () => {
comparePasswordsStub.resolves(true);

// Call the checkPasswordCorrect function with stubbed methods
const isCorrect = await userService.checkPasswordCorrect('test', 'password');
const isCorrect = await userService.checkPasswordCorrect('test@example.com', 'password');

// Expect the result to be true, indicating the password is correct
expect(isCorrect).to.be.true;
expect(comparePasswordsStub.calledOnce).to.be.true;
});

// Test case for an incorrect password
Expand All @@ -160,10 +164,11 @@ describe('userService', () => {
comparePasswordsStub.resolves(false);

// Call the checkPasswordCorrect function with stubbed methods
const isCorrect = await userService.checkPasswordCorrect('test', 'wrongPassword');
const isCorrect = await userService.checkPasswordCorrect('test@example.com', 'wrongPassword');

// Expect the result to be false, indicating the password is incorrect
expect(isCorrect).to.be.false;
expect(comparePasswordsStub.calledOnce).to.be.true;
});

// Test case for a non-existent user
Expand All @@ -175,7 +180,7 @@ describe('userService', () => {
poolQueryStub.resolves(mockResult);

// Call the checkPasswordCorrect function with stubbed methods
const isCorrect = await userService.checkPasswordCorrect('test', 'password');
const isCorrect = await userService.checkPasswordCorrect('test@example.com', 'password');

// Expect the result to be false, indicating the user does not exist
expect(isCorrect).to.be.false;
Expand All @@ -187,7 +192,7 @@ describe('userService', () => {
poolQueryStub.rejects(new Error('Query failed'));

// Call the checkPasswordCorrect function with pool query error stub
const isCorrect = await userService.checkPasswordCorrect('test', 'password');
const isCorrect = await userService.checkPasswordCorrect('test@example.com', 'password');

// Expect the result to be false, indicating an error occurred
expect(isCorrect).to.be.false;
Expand Down Expand Up @@ -227,7 +232,7 @@ describe('userService', () => {
poolQueryStub.resolves(mockResult);

// Call the createUser function with stubbed methods
await userService.createUser('test', 'password');
await userService.createUser('test@example.com', 'password');

expect(checkEmailExistsStub.notCalled).to.be.true; // Expect the checkEmailExists function to be called once
expect(hashPasswordStub.calledOnce).to.be.true; // Expect the pool query function to be called once
Expand All @@ -236,7 +241,7 @@ describe('userService', () => {
// Test case for an existing user
it('should throw an error if the user already exists', async () => {
// Mock the query result to return an array with an email
const mockResult = { rows: [{ email: 'test' }] };
const mockResult = { rows: [{ email: 'test@example.com' }] };

// Stub the checkEmailExists function to resolve true, mocking email exists
checkEmailExistsStub.resolves(true);
Expand All @@ -246,7 +251,7 @@ describe('userService', () => {

try {
// Call the createUser function with stubbed methods
await userService.createUser('test', 'password');
await userService.createUser('test@example.com', 'password');
} catch (error) {
// Expect an error to be thrown with the message 'User already exists'
expect(error.message).to.equal('User already exists');
Expand All @@ -266,7 +271,7 @@ describe('userService', () => {

try {
// Call the createUser function with stubbed methods and expect an error to be thrown
await userService.createUser('test', 'password');
await userService.createUser('test@example.com', 'password');
} catch (error) {
// Expect an error to be thrown with the message 'Query failed'
expect(error.message).to.equal('Query failed');
Expand Down

0 comments on commit f63e8d5

Please sign in to comment.