From f433ee1bf6c52c8639b6448fa7e0c31c6ad955d1 Mon Sep 17 00:00:00 2001 From: Marton Horvath <17813215+horvathmarton@users.noreply.github.com> Date: Sat, 22 Jul 2023 08:46:42 +0200 Subject: [PATCH] Use precalculated hashes in auth testing instead of mocking --- packages/altair-api/custom-matchers.ts | 14 +++++++++ packages/altair-api/jest.d.ts | 1 + .../altair-api/src/auth/mocks/express.mock.ts | 4 +-- .../src/auth/mocks/password.mock.ts | 9 ++++++ .../auth/password/password.service.spec.ts | 30 ++++++------------- 5 files changed, 35 insertions(+), 23 deletions(-) create mode 100644 packages/altair-api/src/auth/mocks/password.mock.ts diff --git a/packages/altair-api/custom-matchers.ts b/packages/altair-api/custom-matchers.ts index 7f6da4623f..150b88766f 100644 --- a/packages/altair-api/custom-matchers.ts +++ b/packages/altair-api/custom-matchers.ts @@ -195,10 +195,24 @@ function toBeUserStats(stats: any) { }; } +function toBeBcryptHash(hash: string) { + const match = /^\$2b\$10\$.{53}$/.test(hash); + + return { + pass: match, + message: () => { + return match + ? `expected ${hash} not to match the bcrypt hash format` + : `expected ${hash} to match the bcrypt hash format`; + }, + }; +} + expect.extend({ toBeUser, toBePlanConfig, toBeSubscriptionItem, toBePlan, toBeUserStats, + toBeBcryptHash, }); diff --git a/packages/altair-api/jest.d.ts b/packages/altair-api/jest.d.ts index c5329d4928..4704dd9aa5 100644 --- a/packages/altair-api/jest.d.ts +++ b/packages/altair-api/jest.d.ts @@ -5,5 +5,6 @@ declare namespace jest { toBeSubscriptionItem(): R; toBePlan(): R; toBeUserStats(): R; + toBeBcryptHash(): R; } } diff --git a/packages/altair-api/src/auth/mocks/express.mock.ts b/packages/altair-api/src/auth/mocks/express.mock.ts index 2932191b2c..e25773b892 100644 --- a/packages/altair-api/src/auth/mocks/express.mock.ts +++ b/packages/altair-api/src/auth/mocks/express.mock.ts @@ -1,9 +1,9 @@ import { Request, Response } from 'express'; -export function mockRequest(props?: object): Request { +export function mockRequest(props?: Partial): Request { return { ...props } as Request; } -export function mockResponse(props?: object): Response { +export function mockResponse(props?: Partial): Response { return { ...props } as Response; } diff --git a/packages/altair-api/src/auth/mocks/password.mock.ts b/packages/altair-api/src/auth/mocks/password.mock.ts new file mode 100644 index 0000000000..a269259085 --- /dev/null +++ b/packages/altair-api/src/auth/mocks/password.mock.ts @@ -0,0 +1,9 @@ +export const passwordMock = '123456'; +export const otherPasswordMock = 'secret'; + +export const passwordHashMapping = { + [passwordMock]: + '$2b$10$i.6ZxLRuMEZ3UvfCAjLsDO5RpJHOAwBWw.K9EDHxdYmrqNFeJ0kG2', + [otherPasswordMock]: + '$2b$10$0En78yD5TJvSoYLhf1vFNO4TxBa2Eyco0blVScDhf.9uGZ92zGTH.', +}; diff --git a/packages/altair-api/src/auth/password/password.service.spec.ts b/packages/altair-api/src/auth/password/password.service.spec.ts index 03e576cdcd..2cfb743d73 100644 --- a/packages/altair-api/src/auth/password/password.service.spec.ts +++ b/packages/altair-api/src/auth/password/password.service.spec.ts @@ -2,15 +2,16 @@ import { ConfigService } from '@nestjs/config'; import { Test, TestingModule } from '@nestjs/testing'; import { PasswordService } from './password.service'; import * as bcrypt from 'bcrypt'; +import { + otherPasswordMock, + passwordHashMapping, + passwordMock, +} from '../mocks/password.mock'; describe('PasswordService', () => { let service: PasswordService; let configService: ConfigService; - const passwordMock = '123456'; - const hashMock = - '8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92'; - beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ providers: [PasswordService, ConfigService], @@ -41,15 +42,10 @@ describe('PasswordService', () => { describe('validatePassword', () => { it(`should return true if the password matches the provided hash`, async () => { - // GIVEN - jest - .spyOn(bcrypt, 'compare') - .mockImplementationOnce(() => Promise.resolve(true)); - // WHEN const validationResult = await service.validatePassword( passwordMock, - hashMock + passwordHashMapping[passwordMock] ); // THEN @@ -57,15 +53,10 @@ describe('PasswordService', () => { }); it(`should return false if the password doesn't match the provided hash`, async () => { - // GIVEN - jest - .spyOn(bcrypt, 'compare') - .mockImplementationOnce(() => Promise.resolve(false)); - // WHEN const validationResult = await service.validatePassword( passwordMock, - `${hashMock}-test` + passwordHashMapping[otherPasswordMock] ); // THEN @@ -75,14 +66,11 @@ describe('PasswordService', () => { describe('hashPassword', () => { it(`should returned the hash of the password`, async () => { - // GIVEN - jest.spyOn(bcrypt, 'hash').mockImplementationOnce(() => hashMock); - // WHEN - const hash = await service.hashPassword(passwordMock); + const hash = await service.hashPassword(otherPasswordMock); // THEN - expect(hash).toEqual(hashMock); + expect(hash).toBeBcryptHash(); }); }); });