Skip to content

Commit

Permalink
Merge branch 'develop' into 339-bug-scroll-bar-issue
Browse files Browse the repository at this point in the history
  • Loading branch information
vazquezea96 authored Jul 15, 2024
2 parents c3034cd + af844dd commit 76d7dab
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 33 deletions.
14 changes: 7 additions & 7 deletions app/login/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,18 @@ import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Login from './page';

const mockLoginAccount = jest.fn();
const mockLogin = jest.fn();
const mockPush = jest.fn();
const getUser = jest.fn();

let emailInput: HTMLInputElement,
passwordInput: HTMLInputElement,
continueButton: HTMLElement;
let continueButton: HTMLElement,
emailInput: HTMLInputElement,
passwordInput: HTMLInputElement;

const mockUseAuthContext = {
loginAccount: mockLoginAccount,
isSignedIn: false,
getUser,
isSignedIn: false,
login: mockLogin,
};

jest.mock('next/navigation', () => ({
Expand Down Expand Up @@ -63,7 +63,7 @@ describe('Login', () => {
fireEvent.click(continueButton);

await waitFor(() => {
expect(mockLoginAccount).toHaveBeenCalledWith({
expect(mockLogin).toHaveBeenCalledWith({
email: '[email protected]',
password: 'password123',
});
Expand Down
6 changes: 3 additions & 3 deletions app/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ type LoginUserSchemaType = z.infer<typeof LoginUserSchema>;
* @returns {JSX.Element} The rendered login page.
*/
const Login = (): JSX.Element => {
const { loginAccount, isSignedIn, getUser } = useAuthContext();
const { login, isSignedIn, getUser } = useAuthContext();

useEffect(() => {
if (isSignedIn) {
Expand All @@ -65,10 +65,10 @@ const Login = (): JSX.Element => {
/**
* A function that handles form submission.
* @param {LoginUserSchemaType} data - The data submitted in the form.
* @returns {Promise<void>} A promise that resolves when the `loginAccount` function completes.
* @returns {Promise<void>} A promise that resolves when the `login` function completes.
*/
const onSubmit: SubmitHandler<LoginUserSchemaType> = async (data) => {
await loginAccount(data);
await login(data);
};

return (
Expand Down
77 changes: 70 additions & 7 deletions app/register/page.test.tsx
Original file line number Diff line number Diff line change
@@ -1,22 +1,31 @@
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import Register from './page';
import { registerAccount } from '@/api/apiFunctions';
import Alert from '@/components/AlertNotification/AlertNotification';
import { AlertVariants } from '@/components/AlertNotification/Alerts.enum';
import { toast } from 'react-hot-toast';

const mockLoginAccount = jest.fn();
const mockLogin = jest.fn();
const mockPush = jest.fn();

jest.mock('../../api/apiFunctions', () => ({
registerAccount: jest.fn(),
}));

let emailInput: HTMLElement;
let passwordInput: HTMLElement;
jest.mock('react-hot-toast', () => ({
toast: {
custom: jest.fn(),
},
}));

let confirmPasswordInput: HTMLElement;
let continueButton: HTMLElement;
let emailInput: HTMLElement;
let passwordInput: HTMLElement;

const mockUseAuthContext = {
loginAccount: mockLoginAccount,
isSignedIn: false,
login: mockLogin,
};

// Mock the useRouter and useAuthContext hooks
Expand Down Expand Up @@ -83,23 +92,77 @@ describe('Register', () => {
password: 'rawr123',
confirmPassword: 'rawr123',
});
expect(mockLoginAccount).toHaveBeenCalledWith({
expect(mockLogin).toHaveBeenCalledWith({
email: '[email protected]',
password: 'rawr123',
confirmPassword: 'rawr123',
});
});
});

test('redirects to /weeklyPicks when the button is clicked', async () => {
test('redirects to /league/all when the button is clicked', async () => {
mockUseAuthContext.isSignedIn = true;

render(<Register />);

await waitFor(() => {
expect(mockPush).toHaveBeenCalledWith('/weeklyPicks');
expect(mockPush).toHaveBeenCalledWith('/league/all');
});

mockUseAuthContext.isSignedIn = false;
});

test('should show success notification upon successful submission', async () => {
fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'pw1234' } });
fireEvent.change(confirmPasswordInput, { target: { value: 'pw1234' } });
fireEvent.click(continueButton);

await waitFor(() => {
expect(registerAccount).toHaveBeenCalledWith({
email: '[email protected]',
password: 'pw1234',
confirmPassword: 'pw1234',
});
expect(mockLogin).toHaveBeenCalledWith({
email: '[email protected]',
password: 'pw1234',
confirmPassword: 'pw1234',
});
expect(mockPush).toHaveBeenCalledWith('/league/all');
expect(toast.custom).toHaveBeenCalledWith(
<Alert
variant={AlertVariants.Success}
message="You have successfully registered your account."
/>,
);
});
});

test('should show error notification upon submission failing', async () => {
mockLogin.mockImplementationOnce(() =>
Promise.reject(new Error('Mock error')),
);

fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'pw1234' } });
fireEvent.change(confirmPasswordInput, { target: { value: 'pw1234' } });
fireEvent.click(continueButton);

await waitFor(() => {
expect(registerAccount).toHaveBeenCalledWith({
email: '[email protected]',
password: 'pw1234',
confirmPassword: 'pw1234',
});
expect(mockLogin).toHaveBeenCalledWith({
email: '[email protected]',
password: 'pw1234',
confirmPassword: 'pw1234',
});
expect(toast.custom).toHaveBeenCalledWith(
<Alert variant={AlertVariants.Error} message="Something went wrong!" />,
);
});
});
});
21 changes: 16 additions & 5 deletions app/register/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ import {
FormItem,
FormMessage,
} from '../../components/Form/Form';
import { toast } from 'react-hot-toast';
import Alert from '@/components/AlertNotification/AlertNotification';
import { AlertVariants } from '@/components/AlertNotification/Alerts.enum';

const RegisterUserSchema = z
.object({
Expand Down Expand Up @@ -50,11 +53,11 @@ type RegisterUserSchemaType = z.infer<typeof RegisterUserSchema>;
*/
const Register = (): JSX.Element => {
const router = useRouter();
const { loginAccount, isSignedIn } = useAuthContext();
const { login, isSignedIn } = useAuthContext();

useEffect(() => {
if (isSignedIn) {
router.push('/weeklyPicks');
router.push('/league/all');
}
}, [isSignedIn]);

Expand All @@ -64,7 +67,6 @@ const Register = (): JSX.Element => {

/**
* The current value of the 'email' field in the form.
*
* @type {string}
*/
const email: string = useWatch({
Expand Down Expand Up @@ -103,10 +105,19 @@ const Register = (): JSX.Element => {
): Promise<void> => {
try {
await registerAccount(data);
await loginAccount(data);
router.push('/weeklyPicks');
await login(data);
router.push('/league/all');
toast.custom(
<Alert
variant={AlertVariants.Success}
message="You have successfully registered your account."
/>,
);
} catch (error) {
console.error('Registration Failed', error);
toast.custom(
<Alert variant={AlertVariants.Error} message="Something went wrong!" />,
);
}
};

Expand Down
70 changes: 70 additions & 0 deletions context/AuthContextProvider.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React from 'react';
import { account } from '../api/config';
import Alert from '../components/AlertNotification/AlertNotification';
import { AlertVariants } from '../components/AlertNotification/Alerts.enum';
import { toast } from 'react-hot-toast';
import { loginAccount } from './AuthHelper';
import { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';

const mockCreateEmailPasswordSession = jest.fn();
account.createEmailPasswordSession = mockCreateEmailPasswordSession;

jest.mock('../api/config');
jest.mock('next/router');
jest.mock('react-hot-toast', () => ({
toast: {
custom: jest.fn(),
},
}));

describe('AuthContextProvider', () => {
const user = {
email: '[email protected]',
password: 'password1234',
};

const router = {
push: jest.fn(),
} as unknown as AppRouterInstance;

const getUser = jest.fn().mockResolvedValue({
email: '[email protected]',
password: 'password1234',
});

beforeEach(() => {
jest.clearAllMocks();
});

test('should show success notification after a successful login', async () => {
mockCreateEmailPasswordSession.mockResolvedValue({});

await loginAccount({ user, router, getUser });

expect(mockCreateEmailPasswordSession).toHaveBeenCalledWith(
user.email,
user.password,
);
expect(getUser).toHaveBeenCalled();
expect(router.push).toHaveBeenCalledWith('/league/all');
expect(toast.custom).toHaveBeenCalledWith(
<Alert
variant={AlertVariants.Success}
message="You've successfully logged in!"
/>,
);
});

test('should show error notification after a login attempt fails', async () => {
const mockError = new Error('Test error');

mockCreateEmailPasswordSession.mockRejectedValue(mockError);

const error = await loginAccount({ user, router, getUser });

expect(error).toEqual(mockError);
expect(toast.custom).toHaveBeenCalledWith(
<Alert variant={AlertVariants.Error} message="Something went wrong!" />,
);
});
});
21 changes: 10 additions & 11 deletions context/AuthContextProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,19 @@ import { useDataStore } from '@/store/dataStore';
import type { DataStore } from '@/store/dataStore';
import { IUser } from '@/api/apiFunctions.interface';
import { getCurrentUser } from '@/api/apiFunctions';
import { loginAccount } from './AuthHelper';

type UserCredentials = {
email: string;
password: string;
};

type AuthContextType = {
getUser: () => Promise<IUser | undefined>;
isSignedIn: boolean;
setIsSignedIn: React.Dispatch<React.SetStateAction<boolean>>;
loginAccount: (user: UserCredentials) => Promise<void | Error>; // eslint-disable-line no-unused-vars
login: (user: UserCredentials) => Promise<void | Error>; // eslint-disable-line no-unused-vars
logoutAccount: () => Promise<void>;
getUser: () => Promise<IUser | undefined>;
setIsSignedIn: React.Dispatch<React.SetStateAction<boolean>>;
};

export const AuthContext = createContext<AuthContextType | null>(null);
Expand Down Expand Up @@ -54,16 +55,14 @@ export const AuthContextProvider = ({
/**
* Authenticate and set session state
* @param user - The user credentials.
* @param router - Module for routing
* @returns The error if there is one.
*/
const loginAccount = async (user: UserCredentials): Promise<void | Error> => {
const login = async (user: UserCredentials): Promise<void | Error> => {
try {
await account.createEmailPasswordSession(user.email, user.password);
await getUser(); // Fetch user data and update state
router.push('/league/all');
await loginAccount({ user, router, getUser });
} catch (error) {
console.error('Login error:', error);
return error as Error;
}
};

Expand Down Expand Up @@ -121,11 +120,11 @@ export const AuthContextProvider = ({
// Memoize context values to avoid unnecessary re-renders
const contextValue = useMemo(
() => ({
getUser,
isSignedIn,
setIsSignedIn,
loginAccount,
login,
logoutAccount,
getUser,
setIsSignedIn,
}),
[isSignedIn],
);
Expand Down
Loading

0 comments on commit 76d7dab

Please sign in to comment.