tests: improve coverage on newly created code
This commit is contained in:
parent
a2e03bf384
commit
1eab6ef2d9
7 changed files with 247 additions and 19 deletions
109
src/client/hooks/__tests__/useLocale.test.ts
Normal file
109
src/client/hooks/__tests__/useLocale.test.ts
Normal file
|
@ -0,0 +1,109 @@
|
|||
import nookies from 'nookies';
|
||||
import { getTRPCMock } from '@/client/mocks/getTrpcMock';
|
||||
import { server } from '@/client/mocks/server';
|
||||
import { renderHook, waitFor } from '../../../../tests/test-utils';
|
||||
import { useLocale } from '../useLocale';
|
||||
|
||||
beforeEach(() => {
|
||||
nookies.destroy(null, 'locale');
|
||||
});
|
||||
|
||||
describe('test: useLocale()', () => {
|
||||
describe('test: locale', () => {
|
||||
it('should return users locale if logged in', async () => {
|
||||
// arrange
|
||||
const locale = 'fr-FR';
|
||||
// @ts-expect-error - we're mocking the trpc context
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: { locale } }));
|
||||
|
||||
// act
|
||||
const { result } = renderHook(() => useLocale());
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.locale).toEqual(locale);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return cookie locale if not logged in', async () => {
|
||||
// arrange
|
||||
const locale = 'fr-FR';
|
||||
nookies.set(null, 'locale', locale);
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: null }));
|
||||
|
||||
// act
|
||||
const { result } = renderHook(() => useLocale());
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.locale).toEqual(locale);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return browser locale if not logged in and no cookie', async () => {
|
||||
// arrange
|
||||
const locale = 'fr-FR';
|
||||
jest.spyOn(window.navigator, 'language', 'get').mockReturnValueOnce(locale);
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: null }));
|
||||
|
||||
// act
|
||||
const { result } = renderHook(() => useLocale());
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.locale).toEqual(locale);
|
||||
});
|
||||
});
|
||||
|
||||
it('should default to english if no locale is found', async () => {
|
||||
// arrange
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: null }));
|
||||
// @ts-expect-error - we're mocking window.navigator
|
||||
jest.spyOn(window.navigator, 'language', 'get').mockReturnValueOnce(undefined);
|
||||
|
||||
// act
|
||||
const { result } = renderHook(() => useLocale());
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(result.current.locale).toEqual('en');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('test: changeLocale()', () => {
|
||||
it('should set the locale in the cookie', async () => {
|
||||
// arrange
|
||||
const locale = 'fr-FR';
|
||||
const { result } = renderHook(() => useLocale());
|
||||
|
||||
// act
|
||||
result.current.changeLocale(locale);
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(nookies.get(null)).toEqual({ locale: 'fr-FR' });
|
||||
});
|
||||
});
|
||||
|
||||
it('should update the locale in the user profile when logged in', async () => {
|
||||
// arrange
|
||||
const locale = 'en';
|
||||
// @ts-expect-error - we're mocking the trpc context
|
||||
server.use(getTRPCMock({ path: ['auth', 'me'], response: { locale: 'fr-FR' } }));
|
||||
server.use(getTRPCMock({ path: ['auth', 'changeLocale'], type: 'mutation', response: true }));
|
||||
const { result } = renderHook(() => useLocale());
|
||||
await waitFor(() => {
|
||||
expect(result.current.locale).toEqual('fr-FR');
|
||||
});
|
||||
|
||||
// act
|
||||
result.current.changeLocale(locale);
|
||||
|
||||
// assert
|
||||
await waitFor(() => {
|
||||
expect(nookies.get(null)).toEqual({ locale });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -2,6 +2,7 @@ import React, { useState } from 'react';
|
|||
import { toast } from 'react-hot-toast';
|
||||
import { useRouter } from 'next/router';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
import { LoginForm } from '../../components/LoginForm';
|
||||
|
@ -16,10 +17,7 @@ export const LoginContainer: React.FC = () => {
|
|||
const utils = trpc.useContext();
|
||||
const login = trpc.auth.login.useMutation({
|
||||
onError: (e) => {
|
||||
let toastMessage = e.message;
|
||||
if (e.data?.translatedError) {
|
||||
toastMessage = t(e.data.translatedError);
|
||||
}
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onSuccess: (data) => {
|
||||
|
@ -34,10 +32,7 @@ export const LoginContainer: React.FC = () => {
|
|||
|
||||
const verifyTotp = trpc.auth.verifyTotp.useMutation({
|
||||
onError: (e) => {
|
||||
let toastMessage = e.message;
|
||||
if (e.data?.translatedError) {
|
||||
toastMessage = t(e.data.translatedError);
|
||||
}
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onSuccess: () => {
|
||||
|
|
|
@ -3,6 +3,7 @@ import React from 'react';
|
|||
import { toast } from 'react-hot-toast';
|
||||
import { useLocale } from '@/client/hooks/useLocale';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
import { RegisterForm } from '../../components/RegisterForm';
|
||||
|
@ -16,10 +17,7 @@ export const RegisterContainer: React.FC = () => {
|
|||
const utils = trpc.useContext();
|
||||
const register = trpc.auth.register.useMutation({
|
||||
onError: (e) => {
|
||||
let toastMessage = e.message;
|
||||
if (e.data?.translatedError) {
|
||||
toastMessage = t(e.data.translatedError);
|
||||
}
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
onSuccess: () => {
|
||||
|
|
|
@ -2,6 +2,7 @@ import { useRouter } from 'next/router';
|
|||
import React from 'react';
|
||||
import { toast } from 'react-hot-toast';
|
||||
import { useTranslations } from 'next-intl';
|
||||
import type { MessageKey } from '@/server/utils/errors';
|
||||
import { Button } from '../../../../components/ui/Button';
|
||||
import { trpc } from '../../../../utils/trpc';
|
||||
import { AuthFormLayout } from '../../components/AuthFormLayout';
|
||||
|
@ -22,10 +23,7 @@ export const ResetPasswordContainer: React.FC<Props> = ({ isRequested }) => {
|
|||
utils.auth.checkPasswordChangeRequest.invalidate();
|
||||
},
|
||||
onError: (e) => {
|
||||
let toastMessage = e.message;
|
||||
if (e.data?.translatedError) {
|
||||
toastMessage = t(e.data.translatedError);
|
||||
}
|
||||
const toastMessage = t(e.data?.translatedError || (e.message as MessageKey));
|
||||
toast.error(toastMessage);
|
||||
},
|
||||
});
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
import { getAuthedPageProps } from '../page-helpers';
|
||||
import nookies from 'nookies';
|
||||
import merge from 'lodash.merge';
|
||||
import { getAuthedPageProps, getMessagesPageProps } from '../page-helpers';
|
||||
import englishMessages from '../../messages/en.json';
|
||||
import frenchMessages from '../../messages/fr-FR.json';
|
||||
|
||||
describe('getAuthedPageProps', () => {
|
||||
describe('test: getAuthedPageProps()', () => {
|
||||
it('should redirect to /login if there is no user id in session', async () => {
|
||||
// arrange
|
||||
const ctx = { req: { session: {} } };
|
||||
|
@ -26,3 +30,58 @@ describe('getAuthedPageProps', () => {
|
|||
expect(props).toEqual({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('test: getMessagesPageProps()', () => {
|
||||
beforeEach(() => {
|
||||
nookies.destroy(null, 'locale');
|
||||
});
|
||||
|
||||
it('should return correct messages if the locale is in the session', async () => {
|
||||
// arrange
|
||||
const ctx = { req: { session: { locale: 'fr' }, headers: {} } };
|
||||
|
||||
// act
|
||||
// @ts-expect-error - we're passing in a partial context
|
||||
const { props } = await getMessagesPageProps(ctx);
|
||||
|
||||
// assert
|
||||
expect(props.messages).toEqual(merge(frenchMessages, englishMessages));
|
||||
});
|
||||
|
||||
it('should return correct messages if the locale in the cookie', async () => {
|
||||
// arrange
|
||||
const ctx = { req: { session: {}, headers: {} } };
|
||||
nookies.set(null, 'locale', 'fr-FR');
|
||||
|
||||
// act
|
||||
// @ts-expect-error - we're passing in a partial context
|
||||
const { props } = await getMessagesPageProps(ctx);
|
||||
|
||||
// assert
|
||||
expect(props.messages).toEqual(merge(frenchMessages, englishMessages));
|
||||
});
|
||||
|
||||
it('should return correct messages if the locale is detected from the browser', async () => {
|
||||
// arrange
|
||||
const ctx = { req: { session: {}, headers: { 'accept-language': 'fr-FR' } } };
|
||||
|
||||
// act
|
||||
// @ts-expect-error - we're passing in a partial context
|
||||
const { props } = await getMessagesPageProps(ctx);
|
||||
|
||||
// assert
|
||||
expect(props.messages).toEqual(merge(frenchMessages, englishMessages));
|
||||
});
|
||||
|
||||
it('should default to english messages if the locale is not found', async () => {
|
||||
// arrange
|
||||
const ctx = { req: { session: {}, headers: {} } };
|
||||
|
||||
// act
|
||||
// @ts-expect-error - we're passing in a partial context
|
||||
const { props } = await getMessagesPageProps(ctx);
|
||||
|
||||
// assert
|
||||
expect(props.messages).toEqual(englishMessages);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -84,7 +84,7 @@ describe('Test: register', () => {
|
|||
|
||||
// act
|
||||
try {
|
||||
await caller.register({ username: 'test@test.com', password: '123' });
|
||||
await caller.register({ username: 'test@test.com', password: '123', locale: 'en' });
|
||||
} catch (e) {
|
||||
error = e as { code: string };
|
||||
}
|
||||
|
@ -327,3 +327,38 @@ describe('Test: resetPassword', () => {
|
|||
expect(error?.code).not.toBe('UNAUTHORIZED');
|
||||
});
|
||||
});
|
||||
|
||||
describe('Test: changeLocale', () => {
|
||||
it('should not be accessible without an account', async () => {
|
||||
// arrange
|
||||
const caller = authRouter.createCaller(fromPartial({ req: { session: {} } }));
|
||||
let error;
|
||||
|
||||
// act
|
||||
try {
|
||||
await caller.changeLocale({ locale: 'en' });
|
||||
} catch (e) {
|
||||
error = e as { code: string };
|
||||
}
|
||||
|
||||
// assert
|
||||
expect(error?.code).toBe('UNAUTHORIZED');
|
||||
});
|
||||
|
||||
it('should be accessible with an account', async () => {
|
||||
// arrange
|
||||
await createUser({ id: 122, locale: 'en' }, db);
|
||||
const caller = authRouter.createCaller(fromPartial({ req: { session: { userId: 122 } } }));
|
||||
let error;
|
||||
|
||||
// act
|
||||
try {
|
||||
await caller.changeLocale({ locale: 'fr-FR' });
|
||||
} catch (e) {
|
||||
error = e as { code: string };
|
||||
}
|
||||
|
||||
// assert
|
||||
expect(error?.code).not.toBe('UNAUTHORIZED');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -687,3 +687,37 @@ describe('Test: changePassword', () => {
|
|||
expect(sessions).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe('test: changeLocale()', () => {
|
||||
it('should change the locale of the user', async () => {
|
||||
// arrange
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser({ email }, database);
|
||||
const locale = 'fr-FR';
|
||||
|
||||
// act
|
||||
await AuthService.changeLocale({ userId: user.id, locale });
|
||||
|
||||
// assert
|
||||
const updatedUser = await getUserById(user.id, database);
|
||||
expect(updatedUser?.locale).toBe(locale);
|
||||
});
|
||||
|
||||
it('should throw if the user does not exist', async () => {
|
||||
// arrange
|
||||
const locale = 'fr-FR';
|
||||
|
||||
// act & assert
|
||||
await expect(AuthService.changeLocale({ userId: 1, locale })).rejects.toThrowError('server-messages.errors.user-not-found');
|
||||
});
|
||||
|
||||
it('should throw if the locale is invalid', async () => {
|
||||
// arrange
|
||||
const email = faker.internet.email();
|
||||
const user = await createUser({ email }, database);
|
||||
const locale = 'invalid';
|
||||
|
||||
// act & assert
|
||||
await expect(AuthService.changeLocale({ userId: user.id, locale })).rejects.toThrowError('server-messages.errors.invalid-locale');
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue