feat(plugins/pagerduty): handle empty response when querying services

* raise NotFoundError in async hook
* show ServiceNotFoundError empty state when async hook errors

Signed-off-by: Alec Jacobs <cajacobs5401@gmail.com>
This commit is contained in:
Alec Jacobs
2022-05-27 10:43:28 -07:00
parent bb4fb80dac
commit 02c2978b79
2 changed files with 73 additions and 17 deletions
@@ -19,7 +19,12 @@ import { PagerDutyCard, isPluginApplicableToEntity } from '../PagerDutyCard';
import { Entity } from '@backstage/catalog-model';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { TestApiRegistry, wrapInTestApp } from '@backstage/test-utils';
import { pagerDutyApiRef, UnauthorizedError, PagerDutyClient } from '../../api';
import {
pagerDutyApiRef,
UnauthorizedError,
NotFoundError,
PagerDutyClient,
} from '../../api';
import { Service, User } from '../types';
import { alertApiRef } from '@backstage/core-plugin-api';
@@ -166,6 +171,24 @@ describe('PageDutyCard', () => {
expect(getByText('Missing or invalid PagerDuty Token')).toBeInTheDocument();
});
it('Handles custom NotFoundError', async () => {
mockPagerDutyApi.getServiceByIntegrationKey = jest
.fn()
.mockRejectedValueOnce(new NotFoundError());
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(getByText('PagerDuty Service Not Found')).toBeInTheDocument();
});
it('handles general error', async () => {
mockPagerDutyApi.getServiceByIntegrationKey = jest
.fn()
@@ -187,6 +210,25 @@ describe('PageDutyCard', () => {
),
).toBeInTheDocument();
});
it('handles empty response from getServiceByIntegrationKey', async () => {
mockPagerDutyApi.getServiceByIntegrationKey = jest
.fn()
.mockImplementationOnce(async () => []);
const { getByText, queryByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<PagerDutyCard />
</EntityProvider>
</ApiProvider>,
),
);
await waitFor(() => !queryByTestId('progress'));
expect(getByText('PagerDuty Service Not Found')).toBeInTheDocument();
});
it('opens the dialog when trigger button is clicked', async () => {
mockPagerDutyApi.getServiceByIntegrationKey = jest
.fn()
@@ -20,15 +20,16 @@ import { Incidents } from '../Incident';
import { EscalationPolicy } from '../Escalation';
import useAsync from 'react-use/lib/useAsync';
import { Alert } from '@material-ui/lab';
import { pagerDutyApiRef, UnauthorizedError } from '../../api';
import { pagerDutyApiRef, UnauthorizedError, NotFoundError } from '../../api';
import AlarmAddIcon from '@material-ui/icons/AlarmAdd';
import { MissingTokenError } from '../Errors/MissingTokenError';
import { MissingTokenError, ServiceNotFoundError } from '../Errors';
import WebIcon from '@material-ui/icons/Web';
import DateRangeIcon from '@material-ui/icons/DateRange';
import { usePagerdutyEntity } from '../../hooks';
import { PAGERDUTY_INTEGRATION_KEY, PAGERDUTY_SERVICE_ID } from '../constants';
import { TriggerDialog } from '../TriggerDialog';
import { ChangeEvents } from '../ChangeEvents';
import { Service } from '../types';
import { useApi } from '@backstage/core-plugin-api';
import {
@@ -75,29 +76,42 @@ export const PagerDutyCard = () => {
loading,
error,
} = useAsync(async () => {
let service: Service;
const services = await api.getServiceByIntegrationKey(
integrationKey as string,
);
service = services[0];
if (!service) throw new NotFoundError();
return {
id: services[0].id,
name: services[0].name,
url: services[0].html_url,
policyId: services[0].escalation_policy.id,
policyLink: services[0].escalation_policy.html_url,
id: service.id,
name: service.name,
url: service.html_url,
policyId: service.escalation_policy.id,
policyLink: service.escalation_policy.html_url,
};
});
if (error instanceof UnauthorizedError) {
return <MissingTokenError />;
}
if (error) {
return (
<Alert severity="error">
Error encountered while fetching information. {error.message}
</Alert>
);
let errorNode: ReactNode;
switch (error.constructor) {
case UnauthorizedError:
errorNode = <MissingTokenError />;
break;
case NotFoundError:
errorNode = <ServiceNotFoundError />;
break;
default:
errorNode = (
<Alert severity="error">
Error encountered while fetching information. {error.message}
</Alert>
);
}
return <BasicCard>{errorNode}</BasicCard>;
}
if (loading) {