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

feat: team list refactor and tests #1168

Merged
merged 5 commits into from
Mar 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
29 changes: 14 additions & 15 deletions frontend/src/components/Teams/TeamsList/TeamItem/TeamItem.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import { TeamUserRoles } from '@/utils/enums/team.user.roles';
import TeamItem, { TeamItemProps } from './index';

const DEFAULT_PROPS = {
userId: '',
team: TeamFactory.create(),
};

Expand All @@ -18,8 +17,13 @@ jest.mock('next/router', () => ({
useRouter: () => router,
}));

const render = (props: TeamItemProps = DEFAULT_PROPS) =>
renderWithProviders(<TeamItem {...props} />, { routerOptions: router });
const render = (props: TeamItemProps = DEFAULT_PROPS, options?: any) =>
renderWithProviders(<TeamItem {...props} />, {
routerOptions: router,
sessionOptions: {
user: options?.user,
},
});

describe('Components/TeamItem', () => {
let testProps: TeamItemProps;
Expand All @@ -32,10 +36,9 @@ describe('Components/TeamItem', () => {
const teamItemProps = { ...testProps };

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

// Assert
expect(getByTestId('teamitemTitle')).toBeInTheDocument();
expect(getByText(teamItemProps.team.name)).toBeInTheDocument();
});

Expand All @@ -50,11 +53,10 @@ describe('Components/TeamItem', () => {
};

// Act
const { getByTestId } = render(teamItemProps);
const { getByText } = render(teamItemProps);

// Assert
expect(getByTestId('teamitemBoards')).toBeInTheDocument();
expect(getByTestId('teamitemBoards')).toHaveTextContent('3 team boards');
expect(getByText('3 team boards')).toBeInTheDocument();
});

it('should render no team boards', () => {
Expand All @@ -68,18 +70,16 @@ describe('Components/TeamItem', () => {
};

// Act
const { getByTestId } = render(teamItemProps);
const { getByText } = render(teamItemProps);

// Assert
expect(getByTestId('teamitemBoards')).toBeInTheDocument();
expect(getByTestId('teamitemBoards')).toHaveTextContent('No boards');
expect(getByText('No boards')).toBeInTheDocument();
});

it('should render create first board', () => {
// Arrange
const teamAdmin = TeamUserFactory.create({ role: TeamUserRoles.ADMIN });
const teamItemProps = {
userId: teamAdmin.user._id,
team: {
...testProps.team,
boardsCount: 0,
Expand All @@ -88,10 +88,9 @@ describe('Components/TeamItem', () => {
};

// Act
const { getByTestId } = render(teamItemProps);
const { getByText } = render(teamItemProps, { user: teamAdmin.user });

// Assert
expect(getByTestId('teamitemBoards')).toBeInTheDocument();
expect(getByTestId('teamitemBoards')).toHaveTextContent('Create first board');
expect(getByText('Create first board')).toBeInTheDocument();
});
});
9 changes: 3 additions & 6 deletions frontend/src/components/Teams/TeamsList/TeamItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,15 @@ const InnerContainer = styled(Flex, Box, {
});

export type TeamItemProps = {
userId: string | undefined;
team: Team;
isTeamPage?: boolean;
};

const TeamItem = React.memo<TeamItemProps>(({ userId, team, isTeamPage }) => {
const TeamItem = React.memo<TeamItemProps>(({ team, isTeamPage }) => {
const { data: session } = useSession();

const router = useRouter();

const isSAdmin = session?.user.isSAdmin;

const { id: userId, isSAdmin } = { ...session?.user };
const { id, users, name } = team;
const userFound: TeamUser | undefined = users.find((member) => member.user?._id === userId);
const userRole = userFound?.role;
Expand All @@ -61,7 +58,7 @@ const TeamItem = React.memo<TeamItemProps>(({ userId, team, isTeamPage }) => {
}, [isSAdmin, team, userId]);

return (
<Flex direction="column">
<Flex direction="column" data-testid="teamItem">
<InnerContainer align="center" elevation="1" gap="40">
<Flex align="center" gap="8" css={{ flex: '1' }}>
<Icon
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type TeamTitleProps = {

const TeamTitle = ({ teamId, title, isTeamPage }: TeamTitleProps) => {
const renderTitle = () => (
<Text link={isTeamPage} size="sm" fontWeight="bold" overflow="wrap" data-testid="teamitemTitle">
<Text link={isTeamPage} size="sm" fontWeight="bold" overflow="wrap">
{title}
</Text>
);
Expand Down
52 changes: 52 additions & 0 deletions frontend/src/components/Teams/TeamsList/TeamsList.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { createMockRouter } from '@/utils/testing/mocks';
import { renderWithProviders } from '@/utils/testing/renderWithProviders';
import { TeamFactory } from '@/utils/factories/team';
import { fireEvent, waitFor } from '@testing-library/react';
import { ROUTES } from '@/utils/routes';
import TeamsList, { TeamsListProps } from '.';

const DEFAULT_PROPS = {
teams: TeamFactory.createMany(3),
};

const router = createMockRouter({ pathname: '/teams' });

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

const render = (props: TeamsListProps = DEFAULT_PROPS) =>
renderWithProviders(<TeamsList {...props} />, { routerOptions: router });

describe('Components/TeamsList', () => {
let testProps: TeamsListProps;
beforeEach(() => {
testProps = { ...DEFAULT_PROPS };
});

it('should render correctly', () => {
// Arrange
const teamItemProps = { ...testProps };

// Act
const { getAllByTestId } = render(teamItemProps);

// Assert
expect(getAllByTestId('teamItem')).toHaveLength(teamItemProps.teams.length);
});

it('should render empty state correctly', async () => {
// Arrange
const teamItemProps = { ...testProps, teams: [] };

// Act
const { getByTestId, getByText } = render(teamItemProps);
fireEvent.click(getByText('Create your first team'));

// Assert
expect(getByTestId('emptyTeams')).toBeInTheDocument();
await waitFor(() => {
expect(router.push).toHaveBeenCalledWith(ROUTES.NewTeam, ROUTES.NewTeam, expect.anything());
});
});
});
18 changes: 12 additions & 6 deletions frontend/src/components/Teams/TeamsList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,25 @@
import React from 'react';

import { Team } from '@/types/team/team';
import Flex from '@/components/Primitives/Flex';
import EmptyTeams from './partials/EmptyTeams';
import ListOfCards from './partials/ListOfCards';

type TeamsListProps = {
userId: string;
import TeamItem from './TeamItem';

export type TeamsListProps = {
teams: Team[];
isFetching: boolean;
};

const TeamsList = ({ userId, teams, isFetching }: TeamsListProps) => {
const TeamsList = ({ teams }: TeamsListProps) => {
if (teams?.length === 0) return <EmptyTeams />;

return <ListOfCards isLoading={isFetching} teams={teams} userId={userId} />;
return (
<Flex direction="column" gap="8">
{teams.map((team: Team) => (
<TeamItem key={team.id} team={team} isTeamPage />
))}
</Flex>
);
};

export default TeamsList;
37 changes: 37 additions & 0 deletions frontend/src/components/Teams/TeamsList/partials/EmptyTeams.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { styled } from '@/styles/stitches/stitches.config';
import Link from 'next/link';

import Text from '@/components/Primitives/Text';
import Box from '@/components/Primitives/Box';
import Flex from '@/components/Primitives/Flex';

import EmptyTeamsImage from '@/components/images/EmptyTeams';

const StyledBox = styled(Flex, Box, {
position: 'relative',
borderRadius: '$12',
backgroundColor: 'white',
mt: '$14',
p: '$48',
});

const EmptyTeams = () => (
<StyledBox
align="center"
direction="column"
elevation="1"
justify="center"
data-testid="emptyTeams"
>
<EmptyTeamsImage />
<Text css={{ mt: '$40', textAlign: 'center' }} size="md">
<Link href="/teams/new">
<Text link fontWeight="medium">
Create your first team
</Text>
</Link>{' '}
now.
</Text>
</StyledBox>
);
export default EmptyTeams;

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

5 changes: 1 addition & 4 deletions frontend/src/components/Users/UserEdit/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,9 @@ import React from 'react';
import ListOfCards from './partials/ListOfCards';

type UserEditProps = {
userId: string | undefined;
isLoading: boolean;
};

const UsersEdit = ({ userId, isLoading }: UserEditProps) => (
<ListOfCards userId={userId} isLoading={isLoading} />
);
const UsersEdit = ({ isLoading }: UserEditProps) => <ListOfCards isLoading={isLoading} />;

export default UsersEdit;
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,17 @@ import { useRecoilValue } from 'recoil';
import { userTeamsListState } from '@/store/team/atom/team.atom';

type ListOfCardsProp = {
userId: string | undefined;
isLoading: boolean;
};

const ListOfCards = React.memo<ListOfCardsProp>(({ userId, isLoading }) => {
const ListOfCards = React.memo<ListOfCardsProp>(({ isLoading }) => {
const teamsOfUsers = useRecoilValue(userTeamsListState);

return (
<ScrollableContent direction="column" gap="24" justify="start">
<Flex direction="column" gap="8">
{teamsOfUsers?.map((team: Team) => (
<TeamItem key={team.id} team={team} userId={userId} isTeamPage={false} />
<TeamItem key={team.id} team={team} isTeamPage={false} />
))}
</Flex>
{isLoading && (
Expand Down
Loading