Skip to content

Commit

Permalink
Merge branch 'develop' into walter/246-add-content-to-welcome-page-an…
Browse files Browse the repository at this point in the history
…d-make
  • Loading branch information
FurrerW authored Oct 11, 2024
2 parents dfaad28 + b4d6f29 commit 9d6f2d5
Show file tree
Hide file tree
Showing 4 changed files with 547 additions and 86 deletions.
277 changes: 215 additions & 62 deletions app/(main)/league/all/page.test.tsx
Original file line number Diff line number Diff line change
@@ -1,124 +1,277 @@
import { render, screen, waitFor, fireEvent } from '@testing-library/react';
import {
render,
screen,
waitFor,
waitForElementToBeRemoved,
fireEvent,
} from '@testing-library/react';
import Leagues from './page';
import { useDataStore } from '@/store/dataStore';
import { getUserLeagues } from '@/utils/utils';
import {
getGameWeek,
getAllLeagues,
getUserDocumentId,
} from '@/api/apiFunctions';
import { AuthContext } from '@/context/AuthContextProvider';
import { getAllLeagues, addUserToLeague } from '@/api/apiFunctions';
import { toast } from 'react-hot-toast';
import Alert from '@/components/AlertNotification/AlertNotification';
import { AlertVariants } from '@/components/AlertNotification/Alerts.enum';

jest.mock('@/store/dataStore', () => ({
useDataStore: jest.fn(() => ({ user: { id: '123', leagues: [] } })),
}));
const mockUseAuthContext = {
isSignedIn: false,
};

jest.mock('@/utils/utils', () => ({
getUserLeagues: jest.fn(() => Promise.resolve([])),
jest.mock('@/context/AuthContextProvider', () => ({
useAuthContext() {
return {
...mockUseAuthContext,
};
},
}));

jest.mock('@/api/apiFunctions', () => ({
getGameWeek: jest.fn(() =>
Promise.resolve({
week: 1,
}),
),
getAllLeagues: jest.fn(() =>
Promise.resolve([
jest.mock('@/store/dataStore', () => ({
useDataStore: jest.fn(() => ({
user: {
documentId: '123',
id: '1234',
email: '[email protected]',
leagues: ['league1'],
},
allLeagues: [
{
leagueId: '123',
leagueName: 'Test League',
logo: 'https://example.com/logo.png',
participants: ['123456', '78', '9'],
logo: 'logo.png',
participants: ['123456', '78'],
survivors: ['123456', '78'],
},
]),
),
],
updateUser: jest.fn(),
})),
}));

jest.mock('@/context/AuthContextProvider', () => ({
useAuthContext: jest.fn(() => ({ user: { id: '123' } })),
jest.mock('@/utils/utils', () => ({
getUserLeagues: jest.fn(() => Promise.resolve([])),
cn: jest.fn(),
}));

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

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

describe('Leagues Component', () => {
const mockUseDataStore = useDataStore as unknown as jest.Mock;
const mockGetUserLeagues = getUserLeagues as jest.Mock;
const mockGetGameWeek = getGameWeek as jest.Mock;
const mockGetAllLeagues = getAllLeagues as jest.Mock;
const mockAddUserToLeague = addUserToLeague as jest.Mock;

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

xtest('should render "You are not enrolled in any leagues" message when no leagues are found', async () => {
mockUseDataStore.mockReturnValueOnce({ user: { id: '123', leagues: [] } });
mockGetUserLeagues.mockResolvedValueOnce([]);
mockGetGameWeek.mockResolvedValueOnce({ week: 1 });
it('should render "You are not enrolled in any leagues" message when no leagues are found', async () => {
mockUseAuthContext.isSignedIn = true;
mockUseDataStore.mockReturnValue({
user: {
documentId: '123',
email: '[email protected]',
id: '123',
leagues: [],
},
allLeagues: [],
});

render(<Leagues />);

await waitForElementToBeRemoved(() => screen.getByTestId('global-spinner'));

await waitFor(() => {
expect(
screen.getByText('You are not enrolled in any leagues'),
).toBeInTheDocument();
const messageElement = screen.getByTestId('no-leagues-message');
expect(messageElement).toBeInTheDocument();
});
});

xtest('should display GlobalSpinner while loading data', async () => {
mockUseDataStore.mockReturnValueOnce({ user: { id: '123', leagues: [] } });
mockGetUserLeagues.mockResolvedValueOnce([]);
mockGetGameWeek.mockResolvedValueOnce({ week: 1 });
render(<Leagues />);
it('should display GlobalSpinner while loading data', async () => {
mockUseAuthContext.isSignedIn = true;

await waitFor(() => {
expect(screen.getByTestId('global-spinner')).toBeInTheDocument();
mockUseDataStore.mockReturnValueOnce({
user: {
documentId: '123',
email: '[email protected]',
id: '123',
leagues: [],
},
allLeagues: [],
});
});
xtest('should not display GlobalSpinner after loading data', async () => {
mockUseDataStore.mockReturnValueOnce({ user: { id: '123', leagues: [] } });
mockGetUserLeagues.mockResolvedValueOnce([]);
mockGetGameWeek.mockResolvedValueOnce({ week: 1 });

render(<Leagues />);

expect(screen.getByTestId('global-spinner')).toBeInTheDocument();

await waitFor(() => {
expect(screen.queryByTestId('global-spinner')).not.toBeInTheDocument();
});
});

xtest('should handle form submission to join a league', async () => {
mockUseDataStore.mockReturnValueOnce({
user: { id: '123', leagues: [] },
it('should not display GlobalSpinner after loading data', async () => {
mockUseAuthContext.isSignedIn = true;

mockUseDataStore.mockReturnValue({
user: {
documentId: '123',
email: '[email protected]',
id: '123',
leagues: [],
},
allLeagues: [
{
leagueId: '123',
leagueName: 'Test League',
logo: 'https://findmylogo.com/logo.png',
logo: 'logo.png',
participants: ['123456', '78'],
survivors: ['123456', '78', '9'],
survivors: ['123456', '78'],
},
],
});

mockGetUserLeagues.mockResolvedValueOnce([]);
mockGetGameWeek.mockResolvedValueOnce({ week: 1 });

render(<Leagues />);

await waitForElementToBeRemoved(() => screen.getByTestId('global-spinner'));

expect(screen.queryByTestId('global-spinner')).not.toBeInTheDocument();
});

it('should handle form submission to join a league', async () => {
mockUseAuthContext.isSignedIn = true;

const user = {
documentId: '123',
email: '[email protected]',
id: '123',
leagues: [],
};

const league = {
leagueId: '123',
leagueName: 'Test League',
logo: 'logo.png',
participants: [],
survivors: [],
};

const updateUser = jest.fn();

mockUseDataStore.mockReturnValue({
user,
allLeagues: [league],
updateUser,
});

mockGetAllLeagues.mockResolvedValueOnce([league]);
mockAddUserToLeague.mockResolvedValue(
Promise.resolve({
userDocumentId: user.documentId,
selectedLeague: league.leagueId,
selectedLeagues: [league.leagueId],
participants: [user.id],
survivors: [user.id],
}),
);

render(<Leagues />);

await waitFor(() => {
expect(screen.queryByTestId('global-spinner')).not.toBeInTheDocument();
});

const selectElement = screen.getByLabelText(/Select league to join/i);
expect(selectElement).toBeInTheDocument();
const selectElement = screen.getByTestId('select-available-leagues');
fireEvent.change(selectElement, { target: { value: '123' } });
fireEvent.click(screen.getByTestId('join-league-button'));

await waitFor(() => {
expect(mockAddUserToLeague).toHaveBeenCalledWith({
userDocumentId: user.documentId,
selectedLeague: league.leagueId,
selectedLeagues: [league.leagueId],
participants: [user.id],
survivors: [user.id],
});
expect(updateUser).toHaveBeenCalledWith(
user.documentId,
user.id,
user.email,
[...user.leagues, league.leagueId],
);
expect(toast.custom).toHaveBeenCalledWith(
<Alert
variant={AlertVariants.Success}
message={`Added ${league.leagueName} to your leagues!`}
/>,
);
});
});

it('should show error if adding to league fails', async () => {
mockUseAuthContext.isSignedIn = true;

const user = {
documentId: '123',
email: '[email protected]',
id: '123',
leagues: [],
};

const league = {
leagueId: '123',
leagueName: 'Test League',
logo: 'logo.png',
participants: [],
survivors: [],
};

mockUseDataStore.mockReturnValue({
user,
allLeagues: [league],
});

mockGetUserLeagues.mockResolvedValueOnce([]);
mockGetAllLeagues.mockResolvedValueOnce([league]);
mockAddUserToLeague.mockResolvedValue(
Promise.resolve({
userDocumentId: user.documentId,
selectedLeague: league.leagueId,
selectedLeagues: [league.leagueId],
participants: [user.id],
survivors: [user.id],
}),
);

render(<Leagues />);

await waitFor(() => {
expect(screen.queryByTestId('global-spinner')).not.toBeInTheDocument();
});

const selectElement = screen.getByTestId('select-available-leagues');
fireEvent.change(selectElement, { target: { value: '123' } });
fireEvent.click(screen.getByText(/Join League/i));
fireEvent.click(screen.getByTestId('join-league-button'));

await waitFor(() => {
expect(
screen.getByText('Added Test League to your leagues!'),
).toBeInTheDocument();
expect(mockAddUserToLeague).toHaveBeenCalledWith({
userDocumentId: user.documentId,
selectedLeague: league.leagueId,
selectedLeagues: [league.leagueId],
participants: [user.id],
survivors: [user.id],
});

expect(toast.custom).toHaveBeenCalledWith(
<Alert
variant={AlertVariants.Error}
message="Failed to add the league. Please try again."
/>,
);
});
});
});
13 changes: 9 additions & 4 deletions app/(main)/league/all/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,12 @@ const Leagues = (): JSX.Element => {
return (
<div className="Leagues mx-auto max-w-3xl pt-10">
{loadingData ? (
<GlobalSpinner />
<GlobalSpinner data-testid="global-spinner" />
) : (
<>
<h1 className="pb-10 text-center text-3xl font-bold tracking-tight">
Your Leagues
</h1>

<section className="grid gap-6 md:grid-cols-2 mb-10">
{leagues.length > 0 ? (
leagues.map((league) => (
Expand All @@ -145,7 +144,10 @@ const Leagues = (): JSX.Element => {
))
) : (
<div className="text-center">
<p className="text-lg font-bold">
<p
className="text-lg font-bold"
data-testid="no-leagues-message"
>
You are not enrolled in any leagues
</p>
</div>
Expand All @@ -169,6 +171,7 @@ const Leagues = (): JSX.Element => {
render={({ field, fieldState }) => (
<>
<select
data-testid="select-available-leagues"
{...field}
id="available-leagues"
className={`border border-border rounded p-2 w-full text-secondary ${
Expand Down Expand Up @@ -198,7 +201,9 @@ const Leagues = (): JSX.Element => {
)}
/>
</div>
<Button type="submit">Join League</Button>
<Button type="submit" data-testid="join-league-button">
Join League
</Button>
</form>
</>
)}
Expand Down
Loading

0 comments on commit 9d6f2d5

Please sign in to comment.