add notification list tests

This commit is contained in:
Keith Grant 2020-08-10 16:23:54 -07:00
parent 8bb1c985c0
commit 4c555815b3
6 changed files with 336 additions and 28 deletions

View File

@ -0,0 +1,61 @@
import React from 'react';
import { mount } from 'enzyme';
import StatusLabel from './StatusLabel';
describe('StatusLabel', () => {
test('should render success', () => {
const wrapper = mount(<StatusLabel status="success" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('CheckCircleIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('green');
expect(wrapper.text()).toEqual('Success');
});
test('should render failed', () => {
const wrapper = mount(<StatusLabel status="failed" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('ExclamationCircleIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('red');
expect(wrapper.text()).toEqual('Failed');
});
test('should render error', () => {
const wrapper = mount(<StatusLabel status="error" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('ExclamationCircleIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('red');
expect(wrapper.text()).toEqual('Error');
});
test('should render running', () => {
const wrapper = mount(<StatusLabel status="running" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('SyncAltIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('blue');
expect(wrapper.text()).toEqual('Running');
});
test('should render pending', () => {
const wrapper = mount(<StatusLabel status="pending" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('ClockIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('blue');
expect(wrapper.text()).toEqual('Pending');
});
test('should render waiting', () => {
const wrapper = mount(<StatusLabel status="waiting" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('ClockIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('grey');
expect(wrapper.text()).toEqual('Waiting');
});
test('should render canceled', () => {
const wrapper = mount(<StatusLabel status="canceled" />);
expect(wrapper).toHaveLength(1);
expect(wrapper.find('ExclamationTriangleIcon')).toHaveLength(1);
expect(wrapper.find('Label').prop('color')).toEqual('orange');
expect(wrapper.text()).toEqual('Canceled');
});
});

View File

@ -1,33 +1,17 @@
import React, { useState, useEffect, useCallback } from 'react';
import React, { useCallback } from 'react';
import { Link, useHistory } from 'react-router-dom';
import { withI18n } from '@lingui/react';
import {
Button,
Chip,
TextList,
TextListItem,
TextListItemVariants,
TextListVariants,
Label,
} from '@patternfly/react-core';
import { Button } from '@patternfly/react-core';
import { t } from '@lingui/macro';
import AlertModal from '../../../components/AlertModal';
import { CardBody, CardActionsRow } from '../../../components/Card';
import ChipGroup from '../../../components/ChipGroup';
import ContentError from '../../../components/ContentError';
import ContentLoading from '../../../components/ContentLoading';
import CredentialChip from '../../../components/CredentialChip';
import {
Detail,
DetailList,
DeletedDetail,
UserDateDetail,
} from '../../../components/DetailList';
import DeleteButton from '../../../components/DeleteButton';
import ErrorDetail from '../../../components/ErrorDetail';
import LaunchButton from '../../../components/LaunchButton';
import { VariablesDetail } from '../../../components/CodeMirrorInput';
import { NotificationTemplatesAPI } from '../../../api';
import useRequest, { useDismissableError } from '../../../util/useRequest';
import { NOTIFICATION_TYPES } from '../constants';

View File

@ -0,0 +1,202 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { OrganizationsAPI } from '../../../api';
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
import NotificationTemplateList from './NotificationTemplateList';
jest.mock('../../../api');
const mockTemplates = {
data: {
count: 3,
results: [
{
name: 'Boston',
id: 1,
url: '/notification_templates/1',
type: 'slack',
summary_fields: {
recent_notifications: [
{
status: 'success',
},
],
user_capabilities: {
delete: true,
edit: true,
},
},
},
{
name: 'Minneapolis',
id: 2,
url: '/notification_templates/2',
summary_fields: {
recent_notifications: [],
user_capabilities: {
delete: true,
edit: true,
},
},
},
{
name: 'Philidelphia',
id: 3,
url: '/notification_templates/3',
summary_fields: {
recent_notifications: [
{
status: 'failed',
},
{
status: 'success',
},
],
user_capabilities: {
delete: true,
edit: true,
},
},
},
],
},
};
describe('<NotificationTemplateList />', () => {
let wrapper;
beforeEach(() => {
OrganizationsAPI.read.mockResolvedValue(mockTemplates);
OrganizationsAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
POST: {},
},
},
});
});
afterEach(() => {
jest.clearAllMocks();
});
test('should load notifications', async () => {
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
expect(OrganizationsAPI.read).toHaveBeenCalledTimes(1);
expect(wrapper.find('NotificationTemplateListItem').length).toBe(3);
});
test('should select item', async () => {
const itemCheckboxInput = 'input#select-template-1';
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
expect(wrapper.find(itemCheckboxInput).prop('checked')).toEqual(false);
await act(async () => {
wrapper
.find(itemCheckboxInput)
.closest('DataListCheck')
.props()
.onChange();
});
wrapper.update();
expect(wrapper.find(itemCheckboxInput).prop('checked')).toEqual(true);
});
test('should delete notifications', async () => {
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
expect(OrganizationsAPI.read).toHaveBeenCalledTimes(1);
await act(async () => {
wrapper
.find('Checkbox#select-all')
.props()
.onChange(true);
});
wrapper.update();
await act(async () => {
wrapper.find('button[aria-label="Delete"]').simulate('click');
wrapper.update();
});
const deleteButton = global.document.querySelector(
'body div[role="dialog"] button[aria-label="confirm delete"]'
);
expect(deleteButton).not.toEqual(null);
await act(async () => {
deleteButton.click();
});
expect(OrganizationsAPI.destroy).toHaveBeenCalledTimes(3);
expect(OrganizationsAPI.read).toHaveBeenCalledTimes(2);
});
test('should show error dialog shown for failed deletion', async () => {
const itemCheckboxInput = 'input#select-template-1';
OrganizationsAPI.destroy.mockRejectedValue(
new Error({
response: {
config: {
method: 'delete',
url: '/api/v2/organizations/1',
},
data: 'An error occurred',
},
})
);
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
await act(async () => {
wrapper
.find(itemCheckboxInput)
.closest('DataListCheck')
.props()
.onChange();
});
wrapper.update();
await act(async () => {
wrapper.find('button[aria-label="Delete"]').simulate('click');
wrapper.update();
});
const deleteButton = global.document.querySelector(
'body div[role="dialog"] button[aria-label="confirm delete"]'
);
expect(deleteButton).not.toEqual(null);
await act(async () => {
deleteButton.click();
});
wrapper.update();
const modal = wrapper.find('Modal');
expect(modal.prop('isOpen')).toEqual(true);
expect(modal.prop('title')).toEqual('Error!');
});
test('should show add button', async () => {
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
expect(wrapper.find('ToolbarAddButton').length).toBe(1);
});
test('should hide add button (rbac)', async () => {
OrganizationsAPI.readOptions.mockResolvedValue({
data: {
actions: {
GET: {},
},
},
});
await act(async () => {
wrapper = mountWithContexts(<NotificationTemplateList />);
});
wrapper.update();
expect(wrapper.find('ToolbarAddButton').length).toBe(0);
});
});

View File

@ -34,7 +34,10 @@ function NotificationTemplateListItem({
onSelect,
i18n,
}) {
const latestStatus = template.summary_fields?.recent_notifications[0]?.status;
const recentNotifications = template.summary_fields?.recent_notifications;
const latestStatus = recentNotifications
? recentNotifications[0]?.status
: null;
const [status, setStatus] = useState(latestStatus);
useEffect(() => {
@ -44,7 +47,7 @@ function NotificationTemplateListItem({
const { request: sendTestNotification, isLoading, error } = useRequest(
useCallback(() => {
NotificationTemplatesAPI.test(template.id);
setStatus('pending');
setStatus('running');
}, [template.id])
);
@ -72,11 +75,11 @@ function NotificationTemplateListItem({
<b>{template.name}</b>
</Link>
</DataListCell>,
<DataListCell>
<DataListCell key="status">
{status && <StatusLabel status={status} />}
</DataListCell>,
<DataListCell key="type">
<strong css="margin-right: 24px">{i18n._(t`Type`)}</strong>
<strong>{i18n._(t`Type:`)}</strong>{' '}
{NOTIFICATION_TYPES[template.notification_type] ||
template.notification_type}
</DataListCell>,

View File

@ -0,0 +1,64 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
import { NotificationTemplatesAPI } from '../../../api';
import NotificationTemplateListItem from './NotificationTemplateListItem';
jest.mock('../../../api/models/NotificationTemplates');
const template = {
id: 3,
notification_type: 'slack',
name: 'Test Notification',
summary_fields: {
user_capabilities: {
edit: true,
},
recent_notifications: [
{
status: 'success',
},
],
},
};
describe('<NotificationTemplateListItem />', () => {
test('should render template row', () => {
const wrapper = mountWithContexts(
<NotificationTemplateListItem
template={template}
detailUrl="/notification_templates/3/detail"
/>
);
const cells = wrapper.find('DataListCell');
expect(cells).toHaveLength(3);
expect(cells.at(0).text()).toEqual('Test Notification');
expect(cells.at(1).text()).toEqual('Success');
expect(cells.at(2).text()).toEqual('Type: Slack');
});
test('should send test notification', async () => {
NotificationTemplatesAPI.test.mockResolvedValue({});
const wrapper = mountWithContexts(
<NotificationTemplateListItem
template={template}
detailUrl="/notification_templates/3/detail"
/>
);
await act(async () => {
wrapper
.find('Button')
.at(0)
.invoke('onClick')();
});
expect(NotificationTemplatesAPI.test).toHaveBeenCalledTimes(1);
expect(
wrapper
.find('DataListCell')
.at(1)
.text()
).toEqual('Running');
});
});

View File

@ -1,18 +1,14 @@
import React from 'react';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import NotificationTemplates from './NotificationTemplates';
describe('<NotificationTemplates />', () => {
let pageWrapper;
let pageSections;
let title;
beforeEach(() => {
pageWrapper = mountWithContexts(<NotificationTemplates />);
pageSections = pageWrapper.find('PageSection');
title = pageWrapper.find('Title');
});
afterEach(() => {
@ -22,8 +18,6 @@ describe('<NotificationTemplates />', () => {
test('initially renders without crashing', () => {
expect(pageWrapper.length).toBe(1);
expect(pageSections.length).toBe(2);
expect(title.length).toBe(1);
expect(title.props().size).toBe('2xl');
expect(pageSections.first().props().variant).toBe('light');
});
});