From f9f9aa64f8a394bd0fbe641596631ce81a846e43 Mon Sep 17 00:00:00 2001 From: Kamil Wolny Date: Tue, 9 Aug 2022 23:43:17 +0100 Subject: [PATCH] feat: use refactored hooks in components and component tests for basic rendering of the plugin Signed-off-by: Kamil Wolny --- .../GitHubIssues/GitHubIssues.test.tsx | 127 ++++++++++++++++++ .../components/GitHubIssues/GitHubIssues.tsx | 38 ++---- .../GitHubIssues/IssueCard/IssueCard.tsx | 2 +- .../GitHubIssues/IssuesList/IssuesList.tsx | 9 +- 4 files changed, 142 insertions(+), 34 deletions(-) create mode 100644 plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx new file mode 100644 index 0000000000..7b9d6d87b2 --- /dev/null +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.test.tsx @@ -0,0 +1,127 @@ +/* + * Copyright 2022 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 { renderInTestApp, TestApiProvider } from '@backstage/test-utils'; +import { + EntityProvider, + catalogApiRef, + CatalogApi, +} from '@backstage/plugin-catalog-react'; + +import { generateTestIssue } from '../../utils'; +import { GitHubIssuesApi, gitHubIssuesApiRef } from '../../api'; + +import { GitHubIssues } from './GitHubIssues'; +import { Entity } from '@backstage/catalog-model'; + +jest + .useFakeTimers() + .setSystemTime(new Date('2020-04-20T08:15:47.614Z').getTime()); + +const entityComponent = { + metadata: { + annotations: { + 'github.com/project-slug': 'backstage/backstage', + }, + name: 'backstage', + }, + apiVersion: 'backstage.io/v1alpha1', + kind: 'Component', +} as unknown as Entity; + +const mockCatalogApi = { + getEntities: () => ({}), +} as CatalogApi; + +describe('GitHubIssues', () => { + it('should render correctly when there are no issues in GitHub', async () => { + const mockApi = { + fetchIssuesByRepoFromGitHub: async () => ({ + backstage: { + issues: { + totalCount: 0, + edges: [], + }, + }, + }), + } as GitHubIssuesApi; + + const apis = [ + [gitHubIssuesApiRef, mockApi], + [catalogApiRef, mockCatalogApi], + ] as const; + + const { getByTestId } = await renderInTestApp( + + + + + , + ); + + expect(getByTestId('no-issues-msg')).toHaveTextContent( + 'Hurray! No Issues 🚀', + ); + }); + + it('should render correctly', async () => { + const testIssue = generateTestIssue({ + createdAt: '2020-04-19T10:15:47.614Z', + updatedAt: '2020-04-20T00:15:47.614Z', + }); + + const mockApi = { + fetchIssuesByRepoFromGitHub: async () => ({ + backstage: { + issues: { + totalCount: 1, + edges: [testIssue], + }, + }, + }), + } as GitHubIssuesApi; + const apis = [ + [gitHubIssuesApiRef, mockApi], + [catalogApiRef, mockCatalogApi], + ] as const; + + const { getByText, getByTestId } = await renderInTestApp( + + + + + , + ); + + getByText('All repositories (1 Issue)'); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + testIssue.node.title, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + testIssue.node.repository.nameWithOwner, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + `Created at: 22 hours ago by ${testIssue.node.author.login}`, + ); + + expect(getByTestId(`issue-${testIssue.node.url}`)).toHaveTextContent( + `Last update at: 8 hours ago`, + ); + }); +}); diff --git a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx index 5380c8eb22..574c15d3b3 100644 --- a/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/GitHubIssues.tsx @@ -20,12 +20,9 @@ import { InfoCard, Progress } from '@backstage/core-components'; import RefreshIcon from '@material-ui/icons/Refresh'; import { useEntityGitHubRepositories } from '../../hooks/useEntityGitHubRepositories'; -import { - RepoIssues, - useGetIssuesByRepoFromGitHub, -} from '../../hooks/useGetIssuesByRepoFromGitHub'; +import { useGetIssuesByRepoFromGitHub } from '../../hooks/useGetIssuesByRepoFromGitHub'; -import { IssueList } from './IssuesList'; +import { IssuesList } from './IssuesList'; import { NoRepositoriesInfo } from './NoRepositoriesInfo'; /** @@ -39,29 +36,12 @@ export type GitHubIssuesProps = { export const GitHubIssues = (props: GitHubIssuesProps) => { const { itemsPerPage = 10, itemsPerRepo = 40 } = props; - const [isLoading, setIsLoading] = React.useState(true); - - const [issuesByRepository, setIssuesByRepository] = - React.useState>(); - const { repositories } = useEntityGitHubRepositories(); - const getIssues = useGetIssuesByRepoFromGitHub(); - - const fetchGitHubIssues = React.useCallback(async () => { - setIsLoading(true); - const issuesByRepo = await getIssues(repositories, itemsPerRepo); - - setIssuesByRepository(issuesByRepo); - setIsLoading(false); - }, [itemsPerRepo, getIssues, repositories]); - - React.useEffect(() => { - if (repositories.length) { - fetchGitHubIssues(); - } else { - setIsLoading(false); - } - }, [repositories.length, fetchGitHubIssues]); + const { + isLoading, + gitHubIssuesByRepo: issuesByRepository, + retry, + } = useGetIssuesByRepoFromGitHub(repositories, itemsPerRepo); if (!repositories.length) { return ; @@ -72,7 +52,7 @@ export const GitHubIssues = (props: GitHubIssuesProps) => { title={ Open GitHub Issues - + @@ -80,7 +60,7 @@ export const GitHubIssues = (props: GitHubIssuesProps) => { > {isLoading && } - diff --git a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx index 95658fb343..ccf30a9a84 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssueCard/IssueCard.tsx @@ -59,7 +59,7 @@ export const IssueCard = (props: IssueCardProps) => { } = props; return ( - + diff --git a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx index f279294928..b46eab22b6 100644 --- a/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx +++ b/plugins/github-issues/src/components/GitHubIssues/IssuesList/IssuesList.tsx @@ -19,14 +19,14 @@ import { Box } from '@material-ui/core'; import { Pagination } from '@material-ui/lab'; import { IssueCard } from '../IssueCard'; -import { RepoIssues } from '../../../hooks/useGetIssuesByRepoFromGitHub'; +import { IssuesByRepo } from '../../../api'; import { RepositoryFilters } from './Filters'; export type PluginMode = 'page' | 'card'; export type IssueListProps = { itemsPerPage?: number; - issuesByRepository?: Record; + issuesByRepository?: IssuesByRepo; }; const getIssuesCountForFilterLabel = ( @@ -37,7 +37,7 @@ const getIssuesCountForFilterLabel = ( issuesAvailable < totalIssues ? '*' : '' }`; -export const IssueList = ({ +export const IssuesList = ({ itemsPerPage = 10, issuesByRepository, }: IssueListProps) => { @@ -140,6 +140,7 @@ export const IssueList = ({ index, ) => ( Hurray! No Issues 🚀 +

Hurray! No Issues 🚀

)} {issues.length / itemsPerPage > 1 ? (