test: add coverage on helper function
This commit is contained in:
parent
69386778a7
commit
3c108e8d44
5 changed files with 188 additions and 1 deletions
81
src/client/hooks/__tests__/useDisclosure.test.ts
Normal file
81
src/client/hooks/__tests__/useDisclosure.test.ts
Normal file
|
@ -0,0 +1,81 @@
|
|||
import { renderHook } from '@testing-library/react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { useDisclosure } from '../useDisclosure';
|
||||
|
||||
describe('useDisclosure', () => {
|
||||
test('should set isOpen to false by default', () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useDisclosure());
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(false);
|
||||
});
|
||||
|
||||
test('should set isOpen to true when calling open', () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useDisclosure());
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.open();
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(true);
|
||||
});
|
||||
|
||||
test('should set isOpen to false when calling close', () => {
|
||||
// arrangarrange
|
||||
const { result } = renderHook(() => useDisclosure(true));
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.close();
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(false);
|
||||
});
|
||||
|
||||
test('should set isOpen to the opposite of the current value when calling toggle', () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useDisclosure(false));
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.toggle();
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(true);
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.toggle();
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(false);
|
||||
});
|
||||
|
||||
test('should set isOpen to the passed value when calling toggle with a boolean argument', () => {
|
||||
// arrange
|
||||
const { result } = renderHook(() => useDisclosure(false));
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.toggle(true);
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(true);
|
||||
|
||||
// act
|
||||
act(() => {
|
||||
result.current.toggle(false);
|
||||
});
|
||||
|
||||
// assert
|
||||
expect(result.current.isOpen).toBe(false);
|
||||
});
|
||||
});
|
|
@ -5,7 +5,7 @@ export const useDisclosure = (isOpenDefault = false) => {
|
|||
|
||||
const open = useCallback(() => setIsOpen(true), []);
|
||||
const close = useCallback(() => setIsOpen(false), []);
|
||||
const toggle = useCallback((toSet: boolean) => {
|
||||
const toggle = useCallback((toSet?: boolean) => {
|
||||
if (typeof toSet === 'undefined') {
|
||||
setIsOpen((state) => !state);
|
||||
} else {
|
||||
|
|
62
src/client/utils/__tests__/typescript.test.ts
Normal file
62
src/client/utils/__tests__/typescript.test.ts
Normal file
|
@ -0,0 +1,62 @@
|
|||
import { nonNullable, objectKeys } from '../typescript';
|
||||
|
||||
describe('objectKeys and nonNullable', () => {
|
||||
describe('objectKeys', () => {
|
||||
test('should return an array of keys from an object', () => {
|
||||
// arrange
|
||||
const input = { foo: 1, bar: 'baz' };
|
||||
|
||||
// act
|
||||
const result = objectKeys(input);
|
||||
|
||||
// assert
|
||||
expect(result).toStrictEqual(['foo', 'bar']);
|
||||
});
|
||||
|
||||
test('should return an empty array for an empty object', () => {
|
||||
// arrange
|
||||
const input = {};
|
||||
|
||||
// act
|
||||
const result = objectKeys(input);
|
||||
|
||||
// assert
|
||||
expect(result).toStrictEqual([]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('nonNullable', () => {
|
||||
test('should return true for a non-null, non-undefined value', () => {
|
||||
// arrange
|
||||
const input = 'foo';
|
||||
|
||||
// act
|
||||
const result = nonNullable(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(true);
|
||||
});
|
||||
|
||||
test('should return false for a null value', () => {
|
||||
// arrange
|
||||
const input = null;
|
||||
|
||||
// act
|
||||
const result = nonNullable(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
test('should return false for an undefined value', () => {
|
||||
// arrange
|
||||
const input = undefined;
|
||||
|
||||
// act
|
||||
const result = nonNullable(input);
|
||||
|
||||
// assert
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -25,6 +25,7 @@ beforeAll(async () => {
|
|||
beforeEach(async () => {
|
||||
jest.mock('fs-extra');
|
||||
jest.mock('redis');
|
||||
await setConfig('demoMode', false);
|
||||
await db.user.deleteMany();
|
||||
});
|
||||
|
||||
|
@ -238,6 +239,16 @@ describe('Test: getTotpUri', () => {
|
|||
// act & assert
|
||||
await expect(AuthService.getTotpUri({ userId, password: 'password' })).rejects.toThrowError('User not found');
|
||||
});
|
||||
|
||||
it('should throw an error if app is in demo mode', async () => {
|
||||
// arrange
|
||||
await setConfig('demoMode', true);
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser({ email }, db);
|
||||
|
||||
// act & assert
|
||||
await expect(AuthService.getTotpUri({ userId: user.id, password: 'password' })).rejects.toThrowError('2FA is not available in demo mode');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: setupTotp', () => {
|
||||
|
@ -291,6 +302,16 @@ describe('Test: setupTotp', () => {
|
|||
// act & assert
|
||||
await expect(AuthService.setupTotp({ userId: user.id, totpCode: '1234' })).rejects.toThrowError('Invalid TOTP code');
|
||||
});
|
||||
|
||||
it('should throw an error if app is in demo mode', async () => {
|
||||
// arrange
|
||||
await setConfig('demoMode', true);
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser({ email }, db);
|
||||
|
||||
// act & assert
|
||||
await expect(AuthService.setupTotp({ userId: user.id, totpCode: '1234' })).rejects.toThrowError('2FA is not available in demo mode');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: disableTotp', () => {
|
||||
|
@ -683,4 +704,15 @@ describe('Test: changePassword', () => {
|
|||
// act & assert
|
||||
await expect(AuthService.changePassword({ userId: user.id, newPassword, currentPassword: 'password' })).rejects.toThrowError('Password must be at least 8 characters');
|
||||
});
|
||||
|
||||
it('should throw if instance is in demo mode', async () => {
|
||||
// arrange
|
||||
await setConfig('demoMode', true);
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser({ email }, db);
|
||||
const newPassword = faker.internet.password();
|
||||
|
||||
// act & assert
|
||||
await expect(AuthService.changePassword({ userId: user.id, newPassword, currentPassword: 'password' })).rejects.toThrowError('Changing password is not allowed in demo mode');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -111,6 +111,10 @@ export class AuthServiceClass {
|
|||
* @returns {Promise<{uri: string, key: string}>} - A promise that resolves to an object containing the TOTP URI and the secret key
|
||||
*/
|
||||
public getTotpUri = async (params: { userId: number; password: string }) => {
|
||||
if (getConfig().demoMode) {
|
||||
throw new Error('2FA is not available in demo mode');
|
||||
}
|
||||
|
||||
const { userId, password } = params;
|
||||
const user = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||
|
||||
|
@ -150,6 +154,10 @@ export class AuthServiceClass {
|
|||
};
|
||||
|
||||
public setupTotp = async (params: { userId: number; totpCode: string }) => {
|
||||
if (getConfig().demoMode) {
|
||||
throw new Error('2FA is not available in demo mode');
|
||||
}
|
||||
|
||||
const { userId, totpCode } = params;
|
||||
const user = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||
|
||||
|
@ -370,6 +378,10 @@ export class AuthServiceClass {
|
|||
};
|
||||
|
||||
public changePassword = async (params: { currentPassword: string; newPassword: string; userId: number }) => {
|
||||
if (getConfig().demoMode) {
|
||||
throw new Error('Changing password is not allowed in demo mode');
|
||||
}
|
||||
|
||||
const { currentPassword, newPassword, userId } = params;
|
||||
|
||||
const user = await this.prisma.user.findUnique({ where: { id: userId } });
|
||||
|
|
Loading…
Reference in a new issue