Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ryan/feat(ux: create input loading spinner) #399

Merged
merged 49 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
49 commits
Select commit Hold shift + click to select a range
fe61aee
feat(LoadingSpinner.tsx): created first iteration of a loading spinner
ryandotfurrer Jul 5, 2024
5d7fb40
feat(LoadingSpinner.tsx): added optional height and width props to co…
ryandotfurrer Jul 13, 2024
86c9e36
feat(LoadingSpinner.tsx): add accessibility features
ryandotfurrer Jul 13, 2024
f69924e
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 13, 2024
ba83fee
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 16, 2024
879e45d
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 16, 2024
0642af5
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 16, 2024
9fe6c06
Merge remote-tracking branch 'origin/develop' into ryan/create-input-…
ryandotfurrer Jul 17, 2024
cfbb118
Merge branch 'ryan/create-input-loading-spinner' of https://github.co…
ryandotfurrer Jul 17, 2024
91a1cad
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 19, 2024
3ae4268
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 19, 2024
8555c8c
feat(page.tsx): remove loading spinner component from league/all page
ryandotfurrer Jul 19, 2024
d1ea90e
feat(LoadingSpinner.tsx): made loadingspinner respect min and max hei…
ryandotfurrer Jul 19, 2024
0a97191
fix(LeagueCard.tsx): remove hard height on leaguecard component
ryandotfurrer Jul 19, 2024
0a17029
test(LoadingSpinner.test.tsx): create test for loadingspinner component
ryandotfurrer Jul 19, 2024
ddf61e9
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 23, 2024
b13771f
fix(LeagueCard.tsx): added hover styles that were unintentionally rem…
ryandotfurrer Jul 23, 2024
7405e32
fix(league/all/page.tsx): revereted loading text value back so the te…
ryandotfurrer Jul 23, 2024
f951b9f
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 25, 2024
896684d
fix(/login/page.tsx): added router import
ryandotfurrer Jul 26, 2024
ada9f2a
test(LoadingSpinner.test.tsx): test only the loadingspinner component…
ryandotfurrer Jul 27, 2024
f4f6297
fix(register/page.tsx-and-login/page.tsx): updated userouter import t…
ryandotfurrer Jul 27, 2024
10d8372
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 30, 2024
6750360
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Jul 31, 2024
6e05eee
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Aug 8, 2024
a5ff75e
feat(loadingspinner.tsx): move data-testid to loadingspinner containi…
ryandotfurrer Aug 9, 2024
c57250a
test(LoadingSpinner.test.tsx): remove line checking for classes as I …
ryandotfurrer Aug 9, 2024
a09b347
Merge branch 'develop' of https://github.com/LetsGetTechnical/gridiro…
ryandotfurrer Aug 13, 2024
3691ac6
change buttonprops label type and remove react from loadingspinner fo…
ryandotfurrer Aug 13, 2024
2fcd56a
(button.tsx): change previous change on buttonprops label to a string…
ryandotfurrer Aug 13, 2024
f8159f1
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Aug 14, 2024
5bbb240
sort imports in login page.tsx
ryandotfurrer Aug 15, 2024
045fea2
attempt at adding test to login page for loading spinner
ryandotfurrer Aug 16, 2024
6a45440
feat(login/page.tsx): add try and catch statements to onSubmit function
ryandotfurrer Aug 16, 2024
efbf890
attempt to make loadingspinner test work
ryandotfurrer Aug 16, 2024
4b7be56
implemented shashi's testing logic for the loadingspinner on the logi…
ryandotfurrer Aug 21, 2024
dd0f185
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Aug 21, 2024
bbce891
Clue355/feat(#449): Use input spinner for submission buttons (#453)
Clue355 Aug 26, 2024
42f4023
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Aug 29, 2024
0803b5a
address comments in latest PR review including updating the login pag…
ryandotfurrer Aug 29, 2024
1a86fce
fix build error pertaining to the new throw in login page.tsx
ryandotfurrer Aug 29, 2024
68f5ac5
remove redundant setIsLoading(false) from try statement
ryandotfurrer Aug 30, 2024
edf7ccb
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Sep 5, 2024
585c807
add `finally` statement to register page `onSubmit` function
ryandotfurrer Sep 5, 2024
564e8c4
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Sep 5, 2024
cd6711d
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Sep 19, 2024
6beef05
update login/page.test.tsx tests
ryandotfurrer Sep 19, 2024
a81040b
fix register page tests
ryandotfurrer Sep 20, 2024
f910e60
Merge branch 'develop' into ryan/create-input-loading-spinner
ryandotfurrer Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 64 additions & 21 deletions app/(main)/login/page.test.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { act } from 'react-dom/test-utils';
import { fireEvent, render, screen, waitFor } from '@testing-library/react';
vmaineng marked this conversation as resolved.
Show resolved Hide resolved
import Login from './page';
import React, { useState as useStateMock } from 'react';

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

jest.mock('react', () => ({
...jest.requireActual('react'),
useState: jest.fn(),
}));

let continueButton: HTMLElement,
emailInput: HTMLInputElement,
Expand Down Expand Up @@ -33,44 +40,47 @@ jest.mock('../../../context/AuthContextProvider', () => ({
}));

describe('Login', () => {
const setIsLoading = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
jest
.spyOn(React, 'useState')
.mockImplementation(() => [false, setIsLoading]);

render(<Login />);

continueButton = screen.getByTestId('continue-button');
emailInput = screen.getByTestId('email');
passwordInput = screen.getByTestId('password');
continueButton = screen.getByTestId('continue-button');
});
test('should render the login page', () => {
it('should render the login page', () => {
expect(continueButton).toBeInTheDocument();
expect(emailInput).toBeInTheDocument();
expect(passwordInput).toBeInTheDocument();
expect(continueButton).toBeInTheDocument();
});

test('should update email state when input value changes', () => {
fireEvent.change(emailInput, { target: { value: '[email protected]' } });
expect(emailInput).toHaveValue('[email protected]');
});
it('should update email and password fields and submit form', async () => {
const form = screen.getByTestId('login-form');

test('should update password state when input value changes', () => {
fireEvent.change(passwordInput, { target: { value: 'password123' } });
expect(passwordInput).toHaveValue('password123');
});
await act(async () => {
fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'password123' } });
});

test('should call loginAccount function with email and password when continue button is clicked', async () => {
fireEvent.change(emailInput, { target: { value: '[email protected]' } });
fireEvent.change(passwordInput, { target: { value: 'password123' } });
fireEvent.click(continueButton);
await act(async () => {
fireEvent.submit(form);
});

await waitFor(() => {
expect(mockLogin).toHaveBeenCalledTimes(1);
expect(mockLogin).toHaveBeenCalledWith({
vmaineng marked this conversation as resolved.
Show resolved Hide resolved
email: '[email protected]',
password: 'password123',
});
});
});

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

render(<Login />);
Expand All @@ -79,11 +89,44 @@ describe('Login', () => {
mockUseAuthContext.isSignedIn = false;
});

test('redirects to /league/all when user navigates to /login', async () => {
it('redirects to /league/all when user navigates to /login', async () => {
mockUseAuthContext.isSignedIn = true;

act(() => {
render(<Login />);
});

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

mockUseAuthContext.isSignedIn = false;
});
});

describe('Login loading spinner', () => {
it('should show the loading spinner', async () => {
(useStateMock as jest.Mock).mockImplementation((init: boolean) => [
true,
setIsLoading,
]);
Comment on lines +108 to +112
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Your tests seem to be failing, please look into this and make sure it's changing the loading state properly

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@choir27 I was aware :P Just been busy working on other things and unable to get back to this. TY!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@choir27 fixed


render(<Login />);

expect(mockPush).toHaveBeenCalledWith('/league/all');
await waitFor(() => {
expect(screen.queryByTestId('loading-spinner')).toBeInTheDocument();
});
});
it('should not show the loading spinner', async () => {
(useStateMock as jest.Mock).mockImplementation((init: boolean) => [
false,
setIsLoading,
]);

render(<Login />);

await waitFor(() => {
expect(screen.queryByTestId('loading-spinner')).not.toBeInTheDocument();
});
});
});
35 changes: 25 additions & 10 deletions app/(main)/login/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ import {
Form,
FormControl,
FormField,
FormItem,
FormItem,
FormMessage,
} from '../../../components/Form/Form';
import { Input } from '@/components/Input/Input';
import { useAuthContext } from '@/context/AuthContextProvider';
import { useRouter } from 'next/navigation';
import { z } from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import LinkCustom from '@/components/LinkCustom/LinkCustom';
import LoadingSpinner from '@/components/LoadingSpinner/LoadingSpinner';
import Logo from '@/components/Logo/Logo';
import logo from '@/public/assets/logo-colored-outline.svg';
import React, { useEffect, useState } from 'react';
import { useRouter } from 'next/navigation';

/**
* The schema for the login form.
Expand Down Expand Up @@ -82,10 +82,18 @@ const Login = (): React.JSX.Element => {
* Handles the form submission.
* @param {LoginUserSchemaType} data - The data from the form.
*/
const onSubmit: SubmitHandler<LoginUserSchemaType> = async (data) => {
setIsLoading(true);
await login(data);
setIsLoading(false);
const onSubmit: SubmitHandler<LoginUserSchemaType> = async (
data: LoginUserSchemaType,
): Promise<void> => {
try {
setIsLoading(true);
await login(data);
} catch (error) {
console.error('Login error:', error);
throw new Error('An error occurred while logging in');
} finally {
setIsLoading(false);
}
vmaineng marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of setting setIsLoading(false) after the API or error, use finally. Then you'd only have to set it once.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh so smart, thank you! This will be updated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in latest commit.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@shashilo pinging you for a reminder, please advise.

};

return (
Expand Down Expand Up @@ -115,6 +123,7 @@ const Login = (): React.JSX.Element => {
<form
id="input-container"
className="grid gap-3"
data-testid="login-form"
onSubmit={form.handleSubmit(onSubmit)}
>
<FormField
Expand All @@ -130,7 +139,7 @@ const Login = (): React.JSX.Element => {
{...field}
/>
</FormControl>
{form.formState.errors.email && (
{form.formState.errors?.email && (
<FormMessage>
{form.formState.errors.email.message}
</FormMessage>
Expand All @@ -151,17 +160,23 @@ const Login = (): React.JSX.Element => {
{...field}
/>
</FormControl>
{form.formState.errors.password && (
{form.formState.errors?.password && (
<FormMessage>
{form.formState.errors.password.message}
{form.formState.errors?.password.message}
</FormMessage>
)}
</FormItem>
)}
/>
<Button
data-testid="continue-button"
label={isLoading ? <LoadingSpinner /> : 'Continue'}
label={
isLoading ? (
<LoadingSpinner data-testid="loading-spinner" />
) : (
'Continue'
)
}
type="submit"
disabled={!email || !password || isLoading}
/>
Expand Down
Loading