diff --git a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx index d386d279ce..545e9e8c1d 100644 --- a/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx +++ b/plugins/xcmetrics/src/components/OverviewComponent/OverviewComponent.test.tsx @@ -16,28 +16,14 @@ import React from 'react'; import { OverviewComponent } from './OverviewComponent'; import { renderInTestApp } from '@backstage/test-utils'; -import { XcmetricsApi, xcmetricsApiRef } from '../../api'; +import { xcmetricsApiRef } from '../../api'; import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; +import { mockUserId, mockXcmetricsApi } from '../../test-utils'; describe('OverviewComponent', () => { it('should render', async () => { - const mockUserId = 'mockUser'; - const mockApi: jest.Mocked = { - getBuilds: jest.fn().mockResolvedValue([ - { - userid: mockUserId, - warningCount: 1, - duration: 123.45, - isCi: false, - projectName: 'App', - buildStatus: 'succeeded', - schema: 'AppSchema', - }, - ]), - }; - const rendered = await renderInTestApp( - + , ); @@ -47,12 +33,10 @@ describe('OverviewComponent', () => { }); it('should render an empty state when no builds exist', async () => { - const mockApi: jest.Mocked = { - getBuilds: jest.fn().mockResolvedValue([]), - }; + mockXcmetricsApi.getBuilds = jest.fn().mockResolvedValue([]); const rendered = await renderInTestApp( - + , ); @@ -61,12 +45,13 @@ describe('OverviewComponent', () => { it('should show an error when API not responding', async () => { const errorMessage = 'MockErrorMessage'; - const mockApi: jest.Mocked = { - getBuilds: jest.fn().mockRejectedValue({ message: errorMessage }), - }; + + mockXcmetricsApi.getBuilds = jest + .fn() + .mockRejectedValue({ message: errorMessage }); const rendered = await renderInTestApp( - + , ); diff --git a/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx new file mode 100644 index 0000000000..470f69fa8d --- /dev/null +++ b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.test.tsx @@ -0,0 +1,42 @@ +/* + * Copyright 2021 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 } from '@backstage/test-utils'; +import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; +import userEvent from '@testing-library/user-event'; +import { StatusCellComponent } from './StatusCellComponent'; +import { xcmetricsApiRef } from '../../api'; +import { mockBuildId, mockStatus, mockXcmetricsApi } from '../../test-utils'; +import { formatStatus } from '../../utils'; + +describe('StatusCellComponent', () => { + it('should render', async () => { + const rendered = await renderInTestApp( + + + , + ); + + userEvent.hover(rendered.getByTestId(mockBuildId)); + expect( + await rendered.findByText(formatStatus(mockStatus)), + ).toBeInTheDocument(); + }); +}); diff --git a/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.tsx b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.tsx index f8c05612a6..b0537c53b7 100644 --- a/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.tsx +++ b/plugins/xcmetrics/src/components/StatusCellComponent/StatusCellComponent.tsx @@ -16,7 +16,7 @@ import { makeStyles, Tooltip } from '@material-ui/core'; import React from 'react'; import { BackstageTheme } from '@backstage/theme'; -import { BuildStatusResult, xcmetricsApiRef } from '../../api'; +import { BuildStatus, BuildStatusResult, xcmetricsApiRef } from '../../api'; import { cn, formatDuration, formatStatus } from '../../utils'; import { useAsync } from 'react-use'; import { useApi } from '@backstage/core-plugin-api'; @@ -36,7 +36,7 @@ const TooltipContent = ({ buildId }: TooltipContentProps) => { if (error) { return
{error.message}
; } else if (loading || !build) { - return ; + return ; } return ( @@ -60,11 +60,15 @@ const TooltipContent = ({ buildId }: TooltipContentProps) => { }; interface StatusCellProps { - buildStatus: BuildStatusResult; // TODO: Rename this + buildStatus?: BuildStatusResult; size: number; spacing: number; } +type StatusStyle = { + [key in BuildStatus]: any; +}; + const useStyles = makeStyles(theme => ({ root: { width: ({ size }) => size, @@ -76,33 +80,43 @@ const useStyles = makeStyles(theme => ({ transform: 'scale(1.2)', }, }, - succeeded: { - backgroundColor: - theme.palette.type === 'light' - ? theme.palette.success.light - : theme.palette.success.main, - }, - failed: { - backgroundColor: theme.palette.error[theme.palette.type], - }, - stopped: { - backgroundColor: theme.palette.warning[theme.palette.type], - }, + ...({ + succeeded: { + backgroundColor: + theme.palette.type === 'light' + ? theme.palette.success.light + : theme.palette.success.main, + }, + } as StatusStyle), // Make sure that key matches a status + ...({ + failed: { + backgroundColor: theme.palette.error[theme.palette.type], + }, + } as StatusStyle), + ...({ + stopped: { + backgroundColor: theme.palette.warning[theme.palette.type], + }, + } as StatusStyle), })); export const StatusCellComponent = (props: StatusCellProps) => { const classes = useStyles(props); - const { buildStatus: buildStatusItem } = props; + const { buildStatus } = props; + + if (!buildStatus) { + return
; + } return ( } + title={} enterNextDelay={500} arrow >
); diff --git a/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.test.tsx b/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.test.tsx index 3a84bda0e3..5c3832da91 100644 --- a/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.test.tsx +++ b/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.test.tsx @@ -16,40 +16,19 @@ import React from 'react'; import { renderInTestApp } from '@backstage/test-utils'; import { ApiProvider, ApiRegistry } from '@backstage/core-app-api'; -import userEvent from '@testing-library/user-event'; import { StatusMatrixComponent } from './StatusMatrixComponent'; -import { XcmetricsApi, xcmetricsApiRef } from '../../api'; -import { formatStatus } from '../../utils'; +import { xcmetricsApiRef } from '../../api'; +import { mockBuildId, mockXcmetricsApi } from '../../test-utils'; describe('StatusMatrixComponent', () => { it('should render', async () => { - const mockId = 'mockId'; - const mockStatus = 'succeeded'; - const mockApi: jest.Mocked = { - getBuildStatuses: jest - .fn() - .mockResolvedValue([{ id: mockId, buildStatus: mockStatus }]), - getBuild: jest.fn().mockResolvedValue({ - id: mockId, - buildStatus: mockStatus, - duration: 10.0, - startTimestamp: new Date().getTime().toString(), - }), - getBuilds: jest.fn().mockResolvedValue([]), - }; - const rendered = await renderInTestApp( - + , ); - const cell = rendered.getByTestId(mockId); + const cell = rendered.getByTestId(mockBuildId); expect(cell).toBeInTheDocument(); - - userEvent.hover(cell); - expect( - await rendered.findByText(formatStatus(mockStatus)), - ).toBeInTheDocument(); }); }); diff --git a/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.tsx b/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.tsx index 92c605e8fb..3a6c7e1618 100644 --- a/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.tsx +++ b/plugins/xcmetrics/src/components/StatusMatrixComponent/StatusMatrixComponent.tsx @@ -66,7 +66,13 @@ export const StatusMatrixComponent = () => { > {loading && [...new Array(cols * MAX_ROWS)].map((_, index) => { - return
; + return ( + + ); })} {builds && diff --git a/plugins/xcmetrics/src/test-utils/index.ts b/plugins/xcmetrics/src/test-utils/index.ts new file mode 100644 index 0000000000..55e29260d1 --- /dev/null +++ b/plugins/xcmetrics/src/test-utils/index.ts @@ -0,0 +1,16 @@ +/* + * Copyright 2021 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. + */ +export * from './mockXcmetricsApi'; diff --git a/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts b/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts new file mode 100644 index 0000000000..58419dfd48 --- /dev/null +++ b/plugins/xcmetrics/src/test-utils/mockXcmetricsApi.ts @@ -0,0 +1,44 @@ +/* + * Copyright 2021 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 { XcmetricsApi } from '../api'; + +export const mockUserId = 'user_id'; +export const mockBuildId = 'build_id'; +export const mockStatus = 'succeeded'; + +export const mockXcmetricsApi: jest.Mocked = { + getBuildStatuses: jest + .fn() + .mockResolvedValue([{ id: mockBuildId, status: mockStatus }]), + getBuild: jest.fn().mockResolvedValue({ + id: mockBuildId, + buildStatus: 'succeeded', + duration: 10.0, + startTimestamp: '1626365026', + }), + getBuilds: jest.fn().mockResolvedValue([ + { + userid: mockUserId, + warningCount: 1, + duration: 123.45, + isCi: false, + projectName: 'App', + buildStatus: mockStatus, + schema: 'AppSchema', + }, + ]), + getBuildCounts: jest.fn(), +};