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

test: add hook mocks to team tests #1413

Merged
merged 9 commits into from
Apr 20, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const CreateHeader = ({ title, disableBack, handleBack }: CreateHeaderProps) =>
<Text color="primary800" fontWeight="bold" heading={3}>
{title}
</Text>
<Button isIcon disabled={disableBack} onClick={handleBack} size="lg">
<Button isIcon data-testid="backButton" disabled={disableBack} onClick={handleBack} size="lg">
<Icon css={{ color: '$primaryBase' }} name="close" />
</Button>
</Header>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const TeamRolePopover = React.memo(({ handleRoleChange }: TeamRolePopoverProps)
<PopoverItem
align="end"
css={{ pr: '$16', height: '$100' }}
data-testid="teamMemberPopover"
direction="column"
onClick={() => {
handleRoleChange(TeamUserRoles.MEMBER);
Expand All @@ -47,6 +48,7 @@ const TeamRolePopover = React.memo(({ handleRoleChange }: TeamRolePopoverProps)
<PopoverItem
align="end"
css={{ pr: '$16', height: '$100' }}
data-testid="teamAdminPopover"
direction="column"
onClick={() => {
handleRoleChange(TeamUserRoles.ADMIN);
Expand All @@ -65,6 +67,7 @@ const TeamRolePopover = React.memo(({ handleRoleChange }: TeamRolePopoverProps)
<PopoverItem
align="end"
css={{ pr: '$16', height: '$100' }}
data-testid="teamStakeholderPopover"
direction="column"
onClick={() => {
handleRoleChange(TeamUserRoles.STAKEHOLDER);
Expand Down
3 changes: 2 additions & 1 deletion frontend/src/components/Sidebar/Sidebar.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Sidebar, { SidebarProps } from '@/components/Sidebar/Sidebar';
import Sidebar from '@/components/Sidebar/Sidebar';
import { libraryMocks } from '@/utils/testing/mocks';
import { renderWithProviders } from '@/utils/testing/renderWithProviders';
import { SidebarProps } from '@components/Sidebar/types';

const DEFAULT_PROPS = {
firstName: 'First',
Expand Down
60 changes: 58 additions & 2 deletions frontend/src/components/Teams/CreateTeam/CreateTeam.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,31 @@
import { UseMutationResult } from '@tanstack/react-query';
import { fireEvent, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';

import CreateTeam from '@/components/Teams/CreateTeam/CreateTeam';
import { ROUTES } from '@/constants/routes';
import { renderWithProviders } from '@/utils/testing/renderWithProviders';
import useCreateTeam from '@hooks/teams/useCreateTeam';
import { libraryMocks } from '@utils/testing/mocks';

const render = () => renderWithProviders(<CreateTeam />);
const { mockRouter } = libraryMocks.mockNextRouter({ pathname: ROUTES.NewTeam });

const render = () => renderWithProviders(<CreateTeam />, { routerOptions: mockRouter });

const mockUseCreateTeam = useCreateTeam as jest.Mock<Partial<UseMutationResult>>;
jest.mock('@/hooks/teams/useCreateTeam');

describe('Teams/CreateTeam', () => {
beforeEach(() => {
mockUseCreateTeam.mockReturnValue({
mutate: jest.fn(),
} as Partial<UseMutationResult>);
});

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

it('should render correctly', () => {
// Act
const { getByTestId, queryByLabelText } = render();
Expand All @@ -22,12 +42,48 @@ describe('Teams/CreateTeam', () => {
it('should open a UserListDialog', async () => {
// Act
const { getByTestId } = render();
fireEvent.click(getByTestId('addRemoveMembersTrigger'));

// Assert
fireEvent.click(getByTestId('addRemoveMembersTrigger'));

await waitFor(() => {
expect(getByTestId('userListDialog')).toBeInTheDocument();
});
});

it('should handle create team', async () => {
// Arrange
const createTeamMutation = jest.fn();

mockUseCreateTeam.mockReturnValue({
mutate: createTeamMutation,
status: 'success',
} as Partial<UseMutationResult>);

// Act
const { getByText, getByLabelText } = render();

await userEvent.type(getByLabelText('Team name'), 'MyTeam');

fireEvent.click(getByText('Create team'));

// Assert

await waitFor(() => {
expect(createTeamMutation).toBeCalledWith({ name: 'MyTeam', users: [] });
expect(mockRouter.push).toHaveBeenCalledWith(ROUTES.Teams);
});
});

it('should redirect back', async () => {
// Act
const { getByTestId } = render();
fireEvent.click(getByTestId('backButton'));

// Assert

await waitFor(() => {
expect(mockRouter.back).toHaveBeenCalled();
});
});
});
147 changes: 147 additions & 0 deletions frontend/src/components/Teams/Team/ListMembers/ListMembers.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,147 @@
import { UseMutationResult, UseQueryResult } from '@tanstack/react-query';
import { fireEvent, waitFor } from '@testing-library/react';

import { ROUTES } from '@/constants/routes';
import useTeam from '@/hooks/teams/useTeam';
import { createTeamState } from '@/store/team.atom';
import { usersListState } from '@/store/user.atom';
import {
renderWithProviders,
RenderWithProvidersOptions,
} from '@/utils/testing/renderWithProviders';
import ListMembers, { ListMembersProps } from '@components/Teams/Team/ListMembers/ListMembers';
import useUpdateTeamUsers from '@hooks/teams/useUpdateTeamUsers';
import useCurrentSession, { UseCurrentSessionResult } from '@hooks/useCurrentSession';
import { TeamUserRoles } from '@utils/enums/team.user.roles';
import { TeamFactory } from '@utils/factories/team';
import { UserListFactory } from '@utils/factories/user';
import { libraryMocks } from '@utils/testing/mocks';
import { verifyIfIsNewJoiner } from '@utils/verifyIfIsNewJoiner';

const { mockRouter } = libraryMocks.mockNextRouter({ pathname: ROUTES.NewTeam });

const render = (props?: Partial<ListMembersProps>, options?: Partial<RenderWithProvidersOptions>) =>
renderWithProviders(<ListMembers isOpen isTeamPage={false} setIsOpen={jest.fn()} {...props} />, {
routerOptions: mockRouter,
...options,
});

const mockUseUpdateTeamUsers = useUpdateTeamUsers as jest.Mock<Partial<UseMutationResult>>;
const mockUseTeam = useTeam as jest.Mock<Partial<UseQueryResult>>;
const mockUseCurrentSession = useCurrentSession as jest.Mock<Partial<UseCurrentSessionResult>>;

jest.mock('@/hooks/teams/useUpdateTeamUsers');
jest.mock('@/hooks/teams/useTeam');
jest.mock('@/hooks/useCurrentSession');

describe('Teams/CreateTeam', () => {
beforeEach(() => {
mockUseUpdateTeamUsers.mockReturnValue({
mutate: jest.fn(),
} as Partial<UseMutationResult>);

mockUseTeam.mockReturnValue({
data: TeamFactory.create(),
} as Partial<UseQueryResult>);

mockUseCurrentSession.mockReturnValue({
isSAdmin: true,
userId: '123',
} as Partial<UseCurrentSessionResult>);
});

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

it('should update team members list on team page', async () => {
// Act
const users = UserListFactory.createMany(2, [{ isChecked: true }, { isChecked: false }]);
const team = TeamFactory.create();
const updateTeamUsersMutation = jest.fn();

mockUseTeam.mockReturnValue({
data: team,
} as Partial<UseQueryResult>);

mockUseUpdateTeamUsers.mockReturnValue({
mutate: updateTeamUsersMutation,
} as Partial<UseMutationResult>);

const initialState = ({ set }: any) => {
set(usersListState, users);
};

const { mockRouter: teamPageMockRouter } = libraryMocks.mockNextRouter({
pathname: ROUTES.TeamPage(team.id),
query: { teamId: team.id },
});

const { getByText } = render(
{ isTeamPage: true },
{
routerOptions: teamPageMockRouter,
recoilOptions: { initialState, recoilHandler: jest.fn(), recoilState: usersListState },
},
);

const isNewJoiner = verifyIfIsNewJoiner(users[0].joinedAt, users[0].providerAccountCreatedAt);

// Assert
fireEvent.click(getByText('Update'));

await waitFor(() => {
expect(updateTeamUsersMutation).toBeCalledWith({
addUsers: [
{
user: users[0]._id,
role: TeamUserRoles.MEMBER,
isNewJoiner,
canBeResponsible: !isNewJoiner,
team: team.id,
},
],
removeUsers: [],
team: team.id,
});
});
});

it('should update team members list on create team page', async () => {
// Act
const user = UserListFactory.create({ isChecked: true });
const recoilHandler = jest.fn();

const initialState = ({ set }: any) => {
set(usersListState, [user]);
};

mockUseCurrentSession.mockReturnValue({
isSAdmin: false,
userId: user._id,
} as Partial<UseCurrentSessionResult>);

const { getByText } = render(
{ isTeamPage: false },
{
recoilOptions: { initialState, recoilHandler, recoilState: createTeamState },
},
);

const isNewJoiner = verifyIfIsNewJoiner(user.joinedAt, user.providerAccountCreatedAt);

// Assert
fireEvent.click(getByText('Update'));

await waitFor(() => {
expect(recoilHandler).toBeCalledWith([
{
user,
role: TeamUserRoles.MEMBER,
isNewJoiner,
canBeResponsible: !isNewJoiner,
},
]);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ import { TeamUserRoles } from '@/utils/enums/team.user.roles';
import { ToastStateEnum } from '@/utils/enums/toast-types';
import { verifyIfIsNewJoiner } from '@/utils/verifyIfIsNewJoiner';

type Props = {
export type ListMembersProps = {
setIsOpen: Dispatch<SetStateAction<boolean>>;
isOpen: boolean;
isTeamPage?: boolean;
};

const ListMembers = ({ isOpen, setIsOpen, isTeamPage }: Props) => {
const ListMembers = ({ isOpen, setIsOpen, isTeamPage }: ListMembersProps) => {
const {
query: { teamId },
} = useRouter();
Expand Down
Loading