fix tests and improve error handling

Signed-off-by: Brian Fletcher <brian@roadie.io>
This commit is contained in:
Brian Fletcher
2022-12-05 13:10:22 +00:00
parent f68ff9a3d8
commit 281df37809
13 changed files with 181 additions and 72 deletions
@@ -21,7 +21,7 @@ spec:
# Intentional no displayName for testing
email: breanna-davison@example.com
picture: https://avatars.dicebear.com/api/avataaars/breanna-davison@example.com.svg?background=%23fff
memberOf: [team-a]
memberOf: [team-a, team-not-exist]
---
apiVersion: backstage.io/v1alpha1
kind: User
@@ -14,11 +14,20 @@
* limitations under the License.
*/
import { renderInTestApp } from '@backstage/test-utils';
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
import { screen } from '@testing-library/react';
import React from 'react';
import { entityRouteRef } from '../../routes';
import { EntityRefLink } from './EntityRefLink';
import { catalogApiRef } from '../../api';
import { CatalogApi } from '@backstage/catalog-client';
import { ApiProvider } from '@backstage/core-app-api';
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
const apis = TestApiRegistry.from([catalogApiRef, catalogApi]);
describe('<EntityRefLink />', () => {
it('renders link for entity in default namespace', async () => {
@@ -34,11 +43,16 @@ describe('<EntityRefLink />', () => {
lifecycle: 'production',
},
};
await renderInTestApp(<EntityRefLink entityRef={entity} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entity} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText('component:software')).toHaveAttribute(
'href',
@@ -60,11 +74,16 @@ describe('<EntityRefLink />', () => {
lifecycle: 'production',
},
};
await renderInTestApp(<EntityRefLink entityRef={entity} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entity} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText('component:test/software')).toHaveAttribute(
'href',
'/catalog/test/component/software',
@@ -86,7 +105,9 @@ describe('<EntityRefLink />', () => {
},
};
await renderInTestApp(
<EntityRefLink entityRef={entity} defaultKind="Component" />,
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entity} defaultKind="Component" />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
@@ -105,11 +126,16 @@ describe('<EntityRefLink />', () => {
namespace: 'default',
name: 'software',
};
await renderInTestApp(<EntityRefLink entityRef={entityName} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entityName} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText('component:software')).toHaveAttribute(
'href',
'/catalog/default/component/software',
@@ -122,11 +148,16 @@ describe('<EntityRefLink />', () => {
namespace: 'test',
name: 'software',
};
await renderInTestApp(<EntityRefLink entityRef={entityName} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entityName} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText('component:test/software')).toHaveAttribute(
'href',
'/catalog/test/component/software',
@@ -140,7 +171,9 @@ describe('<EntityRefLink />', () => {
name: 'software',
};
await renderInTestApp(
<EntityRefLink entityRef={entityName} defaultKind="component" />,
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entityName} defaultKind="component" />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
@@ -160,9 +193,11 @@ describe('<EntityRefLink />', () => {
name: 'software',
};
await renderInTestApp(
<EntityRefLink entityRef={entityName} defaultKind="component">
Custom Children
</EntityRefLink>,
<ApiProvider apis={apis}>
<EntityRefLink entityRef={entityName} defaultKind="component">
Custom Children
</EntityRefLink>
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
@@ -47,6 +47,7 @@ import EmailIcon from '@material-ui/icons/Email';
import InfoIcon from '@material-ui/icons/Info';
import useAsync from 'react-use/lib/useAsync';
import { catalogApiRef } from '../../api';
import { Alert } from '@material-ui/lab';
/**
* Props for {@link EntityRefLink}.
@@ -77,13 +78,21 @@ export const PeekAheadPopover = ({
popupState,
entityRef,
}: PeekAheadPopoverProps) => {
const catalogApi = useApi(catalogApiRef);
const entityRoute = useRouteRef(entityRouteRef);
const classes = useStyles();
const catalogApi = useApi(catalogApiRef);
const { value, loading, error } = useAsync(async () => {
const {
value: entity,
loading,
error,
} = useAsync(async () => {
if (popupState.isOpen) {
return catalogApi.getEntityByRef(entityRef);
const retrievedEntity = await catalogApi.getEntityByRef(entityRef);
if (!retrievedEntity) {
throw new Error(`${entityRef.name} was not found`);
}
return retrievedEntity;
}
return undefined;
}, [popupState]);
@@ -115,25 +124,25 @@ export const PeekAheadPopover = ({
</Typography>
<Typography>{entityRef.kind}</Typography>
<Typography variant="body2">
{error && error.message}
{value && (
{error && <Alert severity="warning">{error.message}</Alert>}
{entity && (
<>
{value.metadata.description}
{entity.metadata.description}
<br />
<br />
{value.spec?.type}
{entity.spec?.type}
</>
)}
</Typography>
</CardContent>
<CardActions>
{value &&
(isUserEntity(value) || isGroupEntity(value)) &&
value.spec.profile?.email && (
<Tooltip title={`Email ${value.spec.profile.email}`}>
{entity &&
(isUserEntity(entity) || isGroupEntity(entity)) &&
entity.spec.profile?.email && (
<Tooltip title={`Email ${entity.spec.profile.email}`}>
<Button
target="_blank"
href={`mailto:${value.spec.profile.email}`}
href={`mailto:${entity.spec.profile.email}`}
size="small"
>
<EmailIcon color="action" />
@@ -14,11 +14,20 @@
* limitations under the License.
*/
import { renderInTestApp } from '@backstage/test-utils';
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
import { screen } from '@testing-library/react';
import React from 'react';
import { entityRouteRef } from '../../routes';
import { EntityRefLinks } from './EntityRefLinks';
import { catalogApiRef } from '../../api';
import { CatalogApi } from '@backstage/catalog-client';
import { ApiProvider } from '@backstage/core-app-api';
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
const apis = TestApiRegistry.from([catalogApiRef, catalogApi]);
describe('<EntityRefLinks />', () => {
it('renders a single link', async () => {
@@ -29,11 +38,16 @@ describe('<EntityRefLinks />', () => {
name: 'software',
},
];
await renderInTestApp(<EntityRefLinks entityRefs={entityNames} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLinks entityRefs={entityNames} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText('component:software')).toHaveAttribute(
'href',
'/catalog/default/component/software',
@@ -53,11 +67,16 @@ describe('<EntityRefLinks />', () => {
name: 'interface',
},
];
await renderInTestApp(<EntityRefLinks entityRefs={entityNames} />, {
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
await renderInTestApp(
<ApiProvider apis={apis}>
<EntityRefLinks entityRefs={entityNames} />
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
},
},
});
);
expect(screen.getByText(',')).toBeInTheDocument();
expect(screen.getByText('component:software')).toHaveAttribute(
'href',
@@ -20,12 +20,21 @@ import {
RELATION_PART_OF,
SystemEntity,
} from '@backstage/catalog-model';
import { renderInTestApp } from '@backstage/test-utils';
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
import { waitFor, screen } from '@testing-library/react';
import React from 'react';
import { entityRouteRef } from '../../routes';
import { EntityTable } from './EntityTable';
import { componentEntityColumns, systemEntityColumns } from './presets';
import { catalogApiRef } from '../../api';
import { CatalogApi } from '@backstage/catalog-client';
import { ApiProvider } from '@backstage/core-app-api';
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
const apis = TestApiRegistry.from([catalogApiRef, catalogApi]);
describe('systemEntityColumns', () => {
it('shows systems', async () => {
@@ -55,12 +64,14 @@ describe('systemEntityColumns', () => {
];
await renderInTestApp(
<EntityTable
title="My Systems"
entities={entities}
emptyContent={<div>EMPTY</div>}
columns={systemEntityColumns}
/>,
<ApiProvider apis={apis}>
<EntityTable
title="My Systems"
entities={entities}
emptyContent={<div>EMPTY</div>}
columns={systemEntityColumns}
/>
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
@@ -107,12 +118,14 @@ describe('componentEntityColumns', () => {
];
await renderInTestApp(
<EntityTable
title="My Components"
entities={entities}
emptyContent={<div>EMPTY</div>}
columns={componentEntityColumns}
/>,
<ApiProvider apis={apis}>
<EntityTable
title="My Components"
entities={entities}
emptyContent={<div>EMPTY</div>}
columns={componentEntityColumns}
/>
</ApiProvider>,
{
mountedRoutes: {
'/catalog/:namespace/:kind/:name/*': entityRouteRef,
+1
View File
@@ -52,6 +52,7 @@
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
},
"devDependencies": {
"@backstage/catalog-client": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/core-app-api": "workspace:^",
"@backstage/dev-utils": "workspace:^",
@@ -14,11 +14,19 @@
* limitations under the License.
*/
import { entityRouteRef } from '@backstage/plugin-catalog-react';
import { renderInTestApp } from '@backstage/test-utils';
import { entityRouteRef, catalogApiRef } from '@backstage/plugin-catalog-react';
import { renderInTestApp, TestApiRegistry } from '@backstage/test-utils';
import { lightTheme } from '@backstage/theme';
import { ThemeProvider } from '@material-ui/core';
import React from 'react';
import { CatalogApi } from '@backstage/catalog-client';
import { ApiProvider } from '@backstage/core-app-api';
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
const apis = TestApiRegistry.from([catalogApiRef, catalogApi]);
import { rootRouteRef } from '../../routes';
import { PlaylistCard } from './PlaylistCard';
@@ -27,18 +35,20 @@ describe('<PlaylistCard/>', () => {
it('renders playlist info', async () => {
const rendered = await renderInTestApp(
<ThemeProvider theme={lightTheme}>
<PlaylistCard
playlist={{
id: 'id1',
name: 'playlist-1',
description: 'test description',
owner: 'group:default/some-owner',
public: true,
entities: 3,
followers: 2,
isFollowing: false,
}}
/>
<ApiProvider apis={apis}>
<PlaylistCard
playlist={{
id: 'id1',
name: 'playlist-1',
description: 'test description',
owner: 'group:default/some-owner',
public: true,
entities: 3,
followers: 2,
isFollowing: false,
}}
/>
</ApiProvider>
</ThemeProvider>,
{
mountedRoutes: {
@@ -32,11 +32,13 @@
"postpack": "backstage-cli package postpack"
},
"dependencies": {
"@backstage/catalog-client": "workspace:^",
"@backstage/core-app-api": "workspace:^",
"@backstage/core-components": "workspace:^",
"@backstage/core-plugin-api": "workspace:^",
"@backstage/integration-react": "workspace:^",
"@backstage/plugin-catalog": "workspace:^",
"@backstage/plugin-catalog-react": "workspace:^",
"@backstage/plugin-search-react": "workspace:^",
"@backstage/plugin-techdocs": "workspace:^",
"@backstage/plugin-techdocs-react": "workspace:^",
@@ -22,6 +22,8 @@ import { screen } from 'testing-library__dom';
import { renderToStaticMarkup } from 'react-dom/server';
import { Route } from 'react-router-dom';
import { act, render } from '@testing-library/react';
import { CatalogApi } from '@backstage/catalog-client';
import { catalogApiRef } from '@backstage/plugin-catalog-react';
import { wrapInTestApp, TestApiProvider } from '@backstage/test-utils';
import { FlatRoutes } from '@backstage/core-app-api';
@@ -59,6 +61,10 @@ const scmIntegrationsApi = {
fromConfig: jest.fn().mockReturnValue({}),
};
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
/** @ignore */
type TechDocsAddonTesterTestApiPair<TApi> = TApi extends infer TImpl
? readonly [ApiRef<TApi>, Partial<TImpl>]
@@ -198,6 +204,7 @@ export class TechDocsAddonTester {
[techdocsStorageApiRef, techdocsStorageApi],
[searchApiRef, searchApi],
[scmIntegrationsApiRef, scmIntegrationsApi],
[catalogApiRef, catalogApi],
...this.options.apis,
];
@@ -50,6 +50,7 @@
"react": "^16.13.1 || ^17.0.0"
},
"devDependencies": {
"@backstage/catalog-client": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/core-app-api": "workspace:^",
"@backstage/dev-utils": "workspace:^",
+1
View File
@@ -65,6 +65,7 @@
"react-router-dom": "6.0.0-beta.0 || ^6.3.0"
},
"devDependencies": {
"@backstage/catalog-client": "workspace:^",
"@backstage/cli": "workspace:^",
"@backstage/core-app-api": "workspace:^",
"@backstage/dev-utils": "workspace:^",
@@ -17,9 +17,10 @@ import React from 'react';
import { act } from '@testing-library/react';
import { ThemeProvider } from '@material-ui/core';
import { scmIntegrationsApiRef } from '@backstage/integration-react';
import { CatalogApi } from '@backstage/catalog-client';
import { lightTheme } from '@backstage/theme';
import { entityRouteRef } from '@backstage/plugin-catalog-react';
import { catalogApiRef, entityRouteRef } from '@backstage/plugin-catalog-react';
import { renderInTestApp, TestApiProvider } from '@backstage/test-utils';
import { techdocsApiRef, techdocsStorageApiRef } from '../../../api';
@@ -66,6 +67,10 @@ const techdocsStorageApiMock: jest.Mocked<typeof techdocsStorageApiRef.T> = {
syncEntityDocs: jest.fn(),
};
const catalogApi: jest.Mocked<CatalogApi> = {
getEntityByRef: jest.fn(),
} as any;
const Wrapper = ({ children }: { children: React.ReactNode }) => {
return (
<ThemeProvider theme={lightTheme}>
@@ -74,6 +79,7 @@ const Wrapper = ({ children }: { children: React.ReactNode }) => {
[scmIntegrationsApiRef, {}],
[techdocsApiRef, techdocsApiMock],
[techdocsStorageApiRef, techdocsStorageApiMock],
[catalogApiRef, catalogApi],
]}
>
{children}
+5
View File
@@ -7189,6 +7189,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/plugin-playlist@workspace:plugins/playlist"
dependencies:
"@backstage/catalog-client": "workspace:^"
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/core-app-api": "workspace:^"
@@ -8058,6 +8059,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/plugin-techdocs-addons-test-utils@workspace:plugins/techdocs-addons-test-utils"
dependencies:
"@backstage/catalog-client": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/core-app-api": "workspace:^"
"@backstage/core-components": "workspace:^"
@@ -8065,6 +8067,7 @@ __metadata:
"@backstage/dev-utils": "workspace:^"
"@backstage/integration-react": "workspace:^"
"@backstage/plugin-catalog": "workspace:^"
"@backstage/plugin-catalog-react": "workspace:^"
"@backstage/plugin-search-react": "workspace:^"
"@backstage/plugin-techdocs": "workspace:^"
"@backstage/plugin-techdocs-react": "workspace:^"
@@ -8126,6 +8129,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/plugin-techdocs-module-addons-contrib@workspace:plugins/techdocs-module-addons-contrib"
dependencies:
"@backstage/catalog-client": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/core-app-api": "workspace:^"
"@backstage/core-components": "workspace:^"
@@ -8229,6 +8233,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@backstage/plugin-techdocs@workspace:plugins/techdocs"
dependencies:
"@backstage/catalog-client": "workspace:^"
"@backstage/catalog-model": "workspace:^"
"@backstage/cli": "workspace:^"
"@backstage/config": "workspace:^"