Skip to content

Commit

Permalink
Implemented authguard class and tests (#9)
Browse files Browse the repository at this point in the history
  • Loading branch information
CaptainExtremis authored May 20, 2024
1 parent abc2684 commit 940554f
Show file tree
Hide file tree
Showing 4 changed files with 171 additions and 0 deletions.
150 changes: 150 additions & 0 deletions src/__tests__/components/authguard/authguard.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
import '@testing-library/jest-dom';
import {
render,
screen,
cleanup,
waitFor,
} from '@testing-library/react';
import { userEvent } from '@testing-library/user-event';
import type { AppRouterInstance } from 'next/dist/shared/lib/app-router-context.shared-runtime';
import navigation from 'next/navigation';
import { AuthGuard } from '@/components/utils/authguard';
import { User } from '@/model/types/user';
import { UserContext, UserContextType } from '@/contexts/user-context';
import { Builder } from 'builder-pattern';
import { UserType } from '@/model/enums/user-type';
import { useState } from 'react';

jest.mock('next/navigation', () => ({
useRouter: jest.fn()
}));

describe('Authguard', () => {
let router: AppRouterInstance;

beforeEach(() => {
router = Builder<AppRouterInstance>().push(jest.fn()).build();
jest.spyOn(navigation, 'useRouter').mockImplementation(() => router)
});

afterEach(cleanup);

it('renders a child component', () => {
const user: User = {
uid: '',
email: '',
name: '',
avatar: 2,
type: UserType.Challenger,
completedActions: {
electionReminders: false,
registerToVote: false,
sharedChallenge: false
},
badges: [],
challengeEndDate: '',
completedChallenge: false,
redeemedAward: false,
contributedTo: [],
shareCode: ''
};
const userContextValue = Builder<UserContextType>().user(user).build();
render(
<UserContext.Provider value={userContextValue}>
<AuthGuard>
<div data-testid="test"></div>
</AuthGuard>
</UserContext.Provider>
);
expect(screen.queryByTestId('test')).toBeInTheDocument();
})

it('calls signin page', () => {
const userContextValue = Builder<UserContextType>().user(null).build();

render(
<UserContext.Provider value={userContextValue}>
<AuthGuard />
</UserContext.Provider>
);

expect(router.push).toHaveBeenCalledWith('/signin');
})

it('does not call signin page', () => {
const user: User = {
uid: '',
email: '',
name: '',
avatar: 2,
type: UserType.Challenger,
completedActions: {
electionReminders: false,
registerToVote: false,
sharedChallenge: false
},
badges: [],
challengeEndDate: '',
completedChallenge: false,
redeemedAward: false,
contributedTo: [],
shareCode: ''
};

const userContextValue = Builder<UserContextType>().user(user).build();
render(
<UserContext.Provider value={userContextValue}>
<AuthGuard />
</UserContext.Provider>
);
expect(router.push).not.toHaveBeenCalled();
})

it('redirects the user', async () => {
function TestComponent() {

const [user, setUser] = useState<User | null>(
{
uid: '',
email: '',
name: '',
avatar: 2,
type: UserType.Challenger,
completedActions: {
electionReminders: false,
registerToVote: false,
sharedChallenge: false
},
badges: [],
challengeEndDate: '',
completedChallenge: false,
redeemedAward: false,
contributedTo: [],
shareCode: ''
}
);

const signout = () => setUser(null);

const UserContextValue = Builder<UserContextType>().user(user).build();

return < UserContext.Provider value={UserContextValue}>
<AuthGuard>
<button onClick={signout}>Sign out</button>
</AuthGuard>
</UserContext.Provider>
}

const user = userEvent.setup();
render(
<TestComponent />
)

expect(router.push).not.toHaveBeenCalled();

const button = screen.getByText('Sign out');

await user.click(button);
await waitFor(() => expect(router.push).toHaveBeenLastCalledWith('/signin'));
});
});
20 changes: 20 additions & 0 deletions src/components/utils/authguard/authguard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
'use client';
import { UserContext } from '@/contexts/user-context';
import { useContextSafely } from '@/hooks/functions/use-context-safely';
import { useRouter } from 'next/navigation';
import type { ReactNode } from 'react';

interface AuthGuardProps {
children?: ReactNode;
}

export function AuthGuard({ children }: AuthGuardProps) {
const { user } = useContextSafely(UserContext, 'AuthGuard');
const router = useRouter();

if (!user) {
router.push('/signin');
}

return <>{children}</>;
}
1 change: 1 addition & 0 deletions src/components/utils/authguard/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { AuthGuard } from './authguard';
Empty file.

0 comments on commit 940554f

Please sign in to comment.