Allows trigger button to render without pager duty key

This commit is contained in:
Juan Lulkin
2021-02-23 18:00:55 +01:00
parent 674202d2d2
commit 4c049a1a13
5 changed files with 189 additions and 31 deletions
+5
View File
@@ -0,0 +1,5 @@
---
'@backstage/plugin-pagerduty': patch
---
Allows the TriggerButton component to render when key is missing
@@ -0,0 +1,149 @@
/*
* Copyright 2020 Spotify AB
*
* 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 { act, fireEvent, waitFor } from '@testing-library/react';
import { renderInTestApp } from '@backstage/test-utils';
import {
ApiRegistry,
alertApiRef,
createApiRef,
ApiProvider,
IdentityApi,
identityApiRef,
} from '@backstage/core';
import { pagerDutyApiRef } from '../../api';
import { Entity } from '@backstage/catalog-model';
import { EntityProvider } from '@backstage/plugin-catalog-react';
import { TriggerButton } from './';
describe('TriggerButton', () => {
const mockIdentityApi: Partial<IdentityApi> = {
getUserId: () => 'guest@example.com',
};
const mockTriggerAlarmFn = jest.fn();
const mockPagerDutyApi = {
triggerAlarm: mockTriggerAlarmFn,
};
const apis = ApiRegistry.from([
[
alertApiRef,
createApiRef({
id: 'core.alert',
description: 'Used to report alerts and forward them to the app',
}),
],
[identityApiRef, mockIdentityApi],
[pagerDutyApiRef, mockPagerDutyApi],
]);
it('renders the trigger button, opens and closes dialog', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'pagerduty-test',
annotations: {
'pagerduty.com/integration-key': 'abc123',
},
},
};
const { queryByRole, getByRole, getByTestId } = await renderInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<TriggerButton design="button" />
</EntityProvider>
</ApiProvider>,
);
expect(getByTestId('trigger-button')).toBeInTheDocument();
expect(queryByRole('dialog')).not.toBeInTheDocument();
const triggerButton = getByTestId('trigger-button');
expect(triggerButton.textContent).toBe('Create Incident');
await act(async () => {
fireEvent.click(triggerButton);
});
await waitFor(() => {
expect(getByRole('dialog')).toBeInTheDocument();
});
const closeButton = getByTestId('close-button');
await act(async () => {
fireEvent.click(closeButton);
});
await waitFor(() => {
expect(queryByRole('dialog')).not.toBeInTheDocument();
});
});
it('renders the trigger button with children', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'pagerduty-test',
annotations: {
'pagerduty.com/integration-key': 'abc123',
},
},
};
const { getByTestId } = await renderInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<TriggerButton design="button">Send an alert</TriggerButton>
</EntityProvider>
</ApiProvider>,
);
const triggerButton = getByTestId('trigger-button');
expect(triggerButton.textContent).toBe('Send an alert');
});
it('renders a disabled trigger button if entity does not include key', async () => {
const entity: Entity = {
apiVersion: 'backstage.io/v1alpha1',
kind: 'Component',
metadata: {
name: 'pagerduty-test',
},
};
const { queryByRole, getByTestId } = await renderInTestApp(
<ApiProvider apis={apis}>
<EntityProvider entity={entity}>
<TriggerButton design="button" />
</EntityProvider>
</ApiProvider>,
);
expect(getByTestId('trigger-button')).toBeInTheDocument();
const triggerButton = getByTestId('trigger-button');
expect(triggerButton.textContent).toBe('Missing integration key');
await act(async () => {
fireEvent.click(triggerButton);
});
await waitFor(() => {
expect(queryByRole('dialog')).not.toBeInTheDocument();
});
});
});
@@ -13,8 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { useCallback, PropsWithChildren } from 'react';
import { createGlobalState } from 'react-use';
import React, { useCallback, PropsWithChildren, useState } from 'react';
import { makeStyles, Button } from '@material-ui/core';
import { useEntity } from '@backstage/plugin-catalog-react';
import { BackstageTheme } from '@backstage/theme';
@@ -50,8 +49,6 @@ const useStyles = makeStyles<BackstageTheme>(theme => ({
},
}));
export const useShowDialog = createGlobalState(false);
export function TriggerButton({
design,
onIncidentCreated,
@@ -59,7 +56,7 @@ export function TriggerButton({
}: PropsWithChildren<TriggerButtonProps>) {
const { buttonStyle, triggerAlarm } = useStyles();
const { entity } = useEntity();
const [dialogShown = false, setDialogShown] = useShowDialog();
const [dialogShown, setDialogShown] = useState<boolean>(false);
const showDialog = useCallback(() => {
setDialogShown(true);
@@ -68,9 +65,8 @@ export function TriggerButton({
setDialogShown(false);
}, [setDialogShown]);
const integrationKey = entity.metadata.annotations![
PAGERDUTY_INTEGRATION_KEY
];
const integrationKey =
entity.metadata.annotations?.[PAGERDUTY_INTEGRATION_KEY];
return (
<>
@@ -79,16 +75,21 @@ export function TriggerButton({
{...(design === 'link' && { color: 'secondary' })}
onClick={showDialog}
className={design === 'link' ? triggerAlarm : buttonStyle}
disabled={!integrationKey}
>
{children ?? 'Create Incident'}
{integrationKey
? children ?? 'Create Incident'
: 'Missing integration key'}
</Button>
<TriggerDialog
showDialog={dialogShown}
handleDialog={hideDialog}
name={entity.metadata.name}
integrationKey={integrationKey}
onIncidentCreated={onIncidentCreated}
/>
{integrationKey && (
<TriggerDialog
showDialog={dialogShown}
handleDialog={hideDialog}
name={entity.metadata.name}
integrationKey={integrationKey}
onIncidentCreated={onIncidentCreated}
/>
)}
</>
);
}
@@ -14,8 +14,8 @@
* limitations under the License.
*/
import React from 'react';
import { render, fireEvent, act } from '@testing-library/react';
import { wrapInTestApp } from '@backstage/test-utils';
import { fireEvent, act } from '@testing-library/react';
import { renderInTestApp } from '@backstage/test-utils';
import {
ApiRegistry,
alertApiRef,
@@ -62,18 +62,16 @@ describe('TriggerDialog', () => {
},
};
const { getByText, getByRole, getByTestId } = render(
wrapInTestApp(
<ApiProvider apis={apis}>
<TriggerDialog
showDialog
handleDialog={() => {}}
name={entity.metadata.name}
integrationKey="abc123"
onIncidentCreated={() => {}}
/>
</ApiProvider>,
),
const { getByText, getByRole, getByTestId } = await renderInTestApp(
<ApiProvider apis={apis}>
<TriggerDialog
showDialog
handleDialog={() => {}}
name={entity.metadata.name}
integrationKey="abc123"
onIncidentCreated={() => {}}
/>
</ApiProvider>,
);
expect(getByRole('dialog')).toBeInTheDocument();
@@ -140,7 +140,12 @@ export const TriggerDialog = ({
>
Trigger Incident
</Button>
<Button id="close" color="primary" onClick={handleDialog}>
<Button
data-testid="close-button"
id="close"
color="primary"
onClick={handleDialog}
>
Close
</Button>
</DialogActions>