Add card filter icons and tests

Signed-off-by: tylerhekman-procore <tyler.hekman@procore.com>
This commit is contained in:
tylerhekman-procore
2023-04-06 02:53:34 -07:00
parent 2ef8aee1d0
commit ec175f513c
6 changed files with 555 additions and 9 deletions
@@ -25,6 +25,8 @@ type Props = {
authorName: string;
authorAvatar?: string;
repositoryName: string;
isDraft: boolean;
repositoryIsArchived: boolean;
};
const Card: FunctionComponent<Props> = (props: PropsWithChildren<Props>) => {
@@ -36,6 +38,8 @@ const Card: FunctionComponent<Props> = (props: PropsWithChildren<Props>) => {
authorName,
authorAvatar,
repositoryName,
isDraft,
repositoryIsArchived,
children,
} = props;
@@ -51,6 +55,8 @@ const Card: FunctionComponent<Props> = (props: PropsWithChildren<Props>) => {
authorName={authorName}
authorAvatar={authorAvatar}
repositoryName={repositoryName}
isDraft={isDraft}
repositoryIsArchived={repositoryIsArchived}
/>
{children}
</Box>
@@ -14,9 +14,11 @@
* limitations under the License.
*/
import React, { FunctionComponent } from 'react';
import { Typography, Box } from '@material-ui/core';
import { Typography, Box, Tooltip } from '@material-ui/core';
import { getElapsedTime } from '../../utils/functions';
import { UserHeader } from '../UserHeader';
import { DraftPrIcon } from '../icons/DraftPr';
import UnarchiveIcon from '@material-ui/icons/Unarchive';
type Props = {
title: string;
@@ -25,6 +27,8 @@ type Props = {
authorName: string;
authorAvatar?: string;
repositoryName: string;
isDraft: boolean;
repositoryIsArchived: boolean;
};
const CardHeader: FunctionComponent<Props> = (props: Props) => {
@@ -35,6 +39,8 @@ const CardHeader: FunctionComponent<Props> = (props: Props) => {
authorName,
authorAvatar,
repositoryName,
isDraft,
repositoryIsArchived,
} = props;
return (
@@ -45,6 +51,22 @@ const CardHeader: FunctionComponent<Props> = (props: Props) => {
</Typography>
<UserHeader name={authorName} avatar={authorAvatar} />
</Box>
<Box display="flex" justifyContent="left">
{isDraft && (
<Tooltip title="Draft PR">
<Box display="flex" justifyContent="center" alignItems="center">
<DraftPrIcon />
</Box>
</Tooltip>
)}
{repositoryIsArchived && (
<Tooltip title="Repository is archived">
<Box display="flex" justifyContent="center" alignItems="center">
<UnarchiveIcon />
</Box>
</Tooltip>
)}
</Box>
<Typography component="h3">
<b>{title}</b>
</Typography>
@@ -0,0 +1,261 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { EntityTeamPullRequestsCard } from '../EntityTeamPullRequestsCard';
import { PullRequestsColumn } from '../../utils/types';
import { render } from '@testing-library/react';
import { fireEvent } from '@testing-library/react';
jest.mock('../../hooks/useUserRepositoriesAndTeam', () => {
return {
useUserRepositoriesAndTeam: () => {
return {
loading: false,
repositories: ['team-login/team-repo'],
teamMembers: ['team-member'],
teamMembersOrganization: 'test-org',
};
},
};
});
jest.mock('../../hooks/usePullRequestsByTeam', () => {
const buildPullRequest = (
prTitle: string,
authorLogin: string,
repoName: string,
isDraft: boolean,
isArchived: boolean,
) => {
return {
id: 'id',
title: prTitle,
url: 'url',
lastEditedAt: 'last-edited-at',
latestReviews: {
nodes: [],
},
mergeable: true,
state: 'state',
reviewDecision: null,
createdAt: 'created-at',
repository: {
name: repoName,
owner: {
login: 'team-login',
},
isArchived: isArchived,
},
isDraft: isDraft,
author: {
login: authorLogin,
avatarUrl: 'avatar-url',
id: 'id',
email: 'email',
name: 'name',
},
};
};
const pullRequests: PullRequestsColumn[] = [
{
title: 'column',
content: [
buildPullRequest(
'non-team-non-draft-non-archive',
'non-team-member',
'team-repo',
false,
false,
),
buildPullRequest(
'non-team-non-draft-is-archive',
'non-team-member',
'team-repo',
false,
true,
),
buildPullRequest(
'non-team-is-draft-non-archive',
'non-team-member',
'team-repo',
true,
false,
),
buildPullRequest(
'non-team-is-draft-is-archive',
'non-team-member',
'team-repo',
true,
true,
),
buildPullRequest(
'is-team-non-draft-non-archive',
'team-member',
'non-team-repo',
false,
false,
),
buildPullRequest(
'is-team-non-draft-is-archive',
'team-member',
'non-team-repo',
false,
true,
),
buildPullRequest(
'is-team-is-draft-non-archive',
'team-member',
'non-team-repo',
true,
false,
),
buildPullRequest(
'is-team-is-draft-is-archive',
'team-member',
'non-team-repo',
true,
true,
),
],
},
];
return {
usePullRequestsByTeam: () => {
return {
loading: false,
pullRequests: pullRequests,
refreshPullRequest: () => {},
};
},
};
});
describe('EntityTeamPullRequestsCard', () => {
it('should render', async () => {
await render(<EntityTeamPullRequestsCard />);
});
describe('non-team PRs', () => {
describe('non-draft PRs', () => {
it('should show non-team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, queryAllByTitle } = await render(
<EntityTeamPullRequestsCard />,
);
expect(getByText('non-team-non-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
it('should show non-team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('non-team-non-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
});
describe('draft PRs', () => {
it('should show draft non-team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
expect(getByText('non-team-is-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
it('should show draft non-team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('non-team-is-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
});
});
describe('team PRs', () => {
describe('non-draft PRs', () => {
it('should show team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
expect(getByText('is-team-non-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
it('should show team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('is-team-non-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
});
describe('draft PRs', () => {
it('should show draft team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
expect(getByText('is-team-is-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
it('should show draft team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsCard />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('is-team-is-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
});
});
});
@@ -0,0 +1,261 @@
/*
* Copyright 2023 The Backstage Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { EntityTeamPullRequestsContent } from '../EntityTeamPullRequestsContent';
import { PullRequestsColumn } from '../../utils/types';
import { render } from '@testing-library/react';
import { fireEvent } from '@testing-library/react';
jest.mock('../../hooks/useUserRepositoriesAndTeam', () => {
return {
useUserRepositoriesAndTeam: () => {
return {
loading: false,
repositories: ['team-login/team-repo'],
teamMembers: ['team-member'],
teamMembersOrganization: 'test-org',
};
},
};
});
jest.mock('../../hooks/usePullRequestsByTeam', () => {
const buildPullRequest = (
prTitle: string,
authorLogin: string,
repoName: string,
isDraft: boolean,
isArchived: boolean,
) => {
return {
id: 'id',
title: prTitle,
url: 'url',
lastEditedAt: 'last-edited-at',
latestReviews: {
nodes: [],
},
mergeable: true,
state: 'state',
reviewDecision: null,
createdAt: 'created-at',
repository: {
name: repoName,
owner: {
login: 'team-login',
},
isArchived: isArchived,
},
isDraft: isDraft,
author: {
login: authorLogin,
avatarUrl: 'avatar-url',
id: 'id',
email: 'email',
name: 'name',
},
};
};
const pullRequests: PullRequestsColumn[] = [
{
title: 'column',
content: [
buildPullRequest(
'non-team-non-draft-non-archive',
'non-team-member',
'team-repo',
false,
false,
),
buildPullRequest(
'non-team-non-draft-is-archive',
'non-team-member',
'team-repo',
false,
true,
),
buildPullRequest(
'non-team-is-draft-non-archive',
'non-team-member',
'team-repo',
true,
false,
),
buildPullRequest(
'non-team-is-draft-is-archive',
'non-team-member',
'team-repo',
true,
true,
),
buildPullRequest(
'is-team-non-draft-non-archive',
'team-member',
'non-team-repo',
false,
false,
),
buildPullRequest(
'is-team-non-draft-is-archive',
'team-member',
'non-team-repo',
false,
true,
),
buildPullRequest(
'is-team-is-draft-non-archive',
'team-member',
'non-team-repo',
true,
false,
),
buildPullRequest(
'is-team-is-draft-is-archive',
'team-member',
'non-team-repo',
true,
true,
),
],
},
];
return {
usePullRequestsByTeam: () => {
return {
loading: false,
pullRequests: pullRequests,
refreshPullRequest: () => {},
};
},
};
});
describe('EntityTeamPullRequestsContent', () => {
it('should render', async () => {
await render(<EntityTeamPullRequestsContent />);
});
describe('non-team PRs', () => {
describe('non-draft PRs', () => {
it('should show non-team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, queryAllByTitle } = await render(
<EntityTeamPullRequestsContent />,
);
expect(getByText('non-team-non-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
it('should show non-team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('non-team-non-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
});
describe('draft PRs', () => {
it('should show draft non-team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
expect(getByText('non-team-is-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
it('should show draft non-team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('non-team-is-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
});
});
describe('team PRs', () => {
describe('non-draft PRs', () => {
it('should show team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
expect(getByText('is-team-non-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
it('should show team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('is-team-non-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(0);
});
});
describe('draft PRs', () => {
it('should show draft team PRs for un-archived repos when archived option is not checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
expect(getByText('is-team-is-draft-non-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(0);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
it('should show draft team PRs for archived repos when archived option is checked', async () => {
const { getByText, getAllByText, getByTitle, queryAllByTitle } =
await render(<EntityTeamPullRequestsContent />);
const teamToggle = getByTitle('Show PRs from your team');
fireEvent.click(teamToggle);
const draftToggle = getByTitle('Show draft PRs');
fireEvent.click(draftToggle);
const archiveToggle = getByTitle('Show archived repos');
fireEvent.click(archiveToggle);
expect(getByText('is-team-is-draft-is-archive')).toBeInTheDocument();
expect(getAllByText('non-team-repo')).toHaveLength(1);
expect(queryAllByTitle('Repository is archived')).toHaveLength(1);
expect(queryAllByTitle('Draft PR')).toHaveLength(1);
});
});
});
});
@@ -52,21 +52,17 @@ const PullRequestCard: FunctionComponent<Props> = (props: Props) => {
const commentsReviews = getCommentedReviews(reviews);
const changeRequests = getChangeRequests(reviews);
// Resolved in this way to satisfy merge - Author: tylerhekman-procore
// This information should probably be moved into dedicated CardHeader fields
// instead of title prefixes
const cardTitleModifiers = [isDraft && '🔧 DRAFT', repositoryIsArchived && '📁 ARCHIVED'].filter(Boolean);
const cardTitle = cardTitleModifiers.length > 0 ? `(${cardTitleModifiers.join(' | ')}) - ${title}` : title;
return (
<Card
title={cardTitle}
title={title}
createdAt={createdAt}
updatedAt={updatedAt}
authorName={author.login}
authorAvatar={author.avatarUrl}
repositoryName={repositoryName}
prUrl={url}
isDraft={isDraft}
repositoryIsArchived={repositoryIsArchived}
>
{!!approvedReviews.length && (
<UserHeaderList