fix tests with errors

This commit is contained in:
Keith J. Grant
2021-07-02 13:25:05 -07:00
parent 4b41bbbf34
commit ad2f042f97
11 changed files with 121 additions and 97 deletions

View File

@@ -6,14 +6,18 @@ import CheckboxListItem from './CheckboxListItem';
describe('CheckboxListItem', () => { describe('CheckboxListItem', () => {
test('renders the expected content', () => { test('renders the expected content', () => {
const wrapper = mount( const wrapper = mount(
<CheckboxListItem <table>
itemId={1} <tbody>
name="Buzz" <CheckboxListItem
label="Buzz" itemId={1}
isSelected={false} name="Buzz"
onSelect={() => {}} label="Buzz"
onDeselect={() => {}} isSelected={false}
/> onSelect={() => {}}
onDeselect={() => {}}
/>
</tbody>
</table>
); );
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
}); });

View File

@@ -36,6 +36,10 @@ function ErrorDetail({ error }) {
const { response } = error; const { response } = error;
const [isExpanded, setIsExpanded] = useState(false); const [isExpanded, setIsExpanded] = useState(false);
if (!error) {
return null;
}
const handleToggle = () => { const handleToggle = () => {
setIsExpanded(!isExpanded); setIsExpanded(!isExpanded);
}; };
@@ -84,7 +88,10 @@ function ErrorDetail({ error }) {
} }
ErrorDetail.propTypes = { ErrorDetail.propTypes = {
error: PropTypes.instanceOf(Error).isRequired, error: PropTypes.instanceOf(Error),
};
ErrorDetail.defaultProps = {
error: null,
}; };
export default ErrorDetail; export default ErrorDetail;

View File

@@ -15,8 +15,8 @@ describe('<JobDetail />', () => {
expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label); expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label);
expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value); expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value);
} }
afterEach(() => { afterEach(() => {
wrapper.unmount();
jest.clearAllMocks(); jest.clearAllMocks();
}); });

View File

@@ -1,4 +1,5 @@
import React from 'react'; import React from 'react';
import { shallow } from 'enzyme';
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers'; import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
import HostEventModal from './HostEventModal'; import HostEventModal from './HostEventModal';
@@ -62,53 +63,53 @@ const jsonValue = `{
] ]
}`; }`;
let detailsSection; // let detailsSection;
let jsonSection; // let jsonSection;
let standardOutSection; // let standardOutSection;
let standardErrorSection; // let standardErrorSection;
//
const findSections = wrapper => { // const findSections = wrapper => {
detailsSection = wrapper.find('section').at(0); // detailsSection = wrapper.find('section').at(0);
jsonSection = wrapper.find('section').at(1); // jsonSection = wrapper.find('section').at(1);
standardOutSection = wrapper.find('section').at(2); // standardOutSection = wrapper.find('section').at(2);
standardErrorSection = wrapper.find('section').at(3); // standardErrorSection = wrapper.find('section').at(3);
}; // };
describe('HostEventModal', () => { describe('HostEventModal', () => {
test('initially renders successfully', () => { test('initially renders successfully', () => {
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={() => {}} /> <HostEventModal hostEvent={hostEvent} onClose={() => {}} />
); );
expect(wrapper).toHaveLength(1); expect(wrapper).toHaveLength(1);
}); });
test('should render all tabs', () => { test('should render all tabs', () => {
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen /> <HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen />
); );
/* eslint-disable react/button-has-type */ expect(wrapper.find('Tabs Tab').length).toEqual(4);
expect(wrapper.find('Tabs TabButton').length).toEqual(4);
}); });
test('should show details tab content on mount', () => { test('should initially show details tab', () => {
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen /> <HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen />
); );
findSections(wrapper); expect(wrapper.find('Tabs').prop('activeKey')).toEqual(0);
expect(detailsSection.find('TextList').length).toBe(1); expect(wrapper.find('Detail')).toHaveLength(5);
function assertDetail(label, value) { function assertDetail(index, label, value) {
expect(wrapper.find(`Detail[label="${label}"] dt`).text()).toBe(label); const detail = wrapper.find('Detail').at(index);
expect(wrapper.find(`Detail[label="${label}"] dd`).text()).toBe(value); expect(detail.prop('label')).toEqual(label);
expect(detail.prop('value')).toEqual(value);
} }
// StatusIcon adds visibly hidden accessibility text " changed " const detail = wrapper.find('Detail').first();
assertDetail('Host Name', ' changed foo'); expect(detail.prop('value').props.children).toEqual([null, 'foo']);
assertDetail('Play', 'all'); assertDetail(1, 'Play', 'all');
assertDetail('Task', 'command'); assertDetail(2, 'Task', 'command');
assertDetail('Module', 'command'); assertDetail(3, 'Module', 'command');
assertDetail('Command', 'free-m'); assertDetail(4, 'Command', hostEvent.event_data.res.cmd);
}); });
test('should display successful host status icon', () => { test('should display successful host status icon', () => {
@@ -180,34 +181,30 @@ describe('HostEventModal', () => {
}); });
test('should display JSON tab content on tab click', () => { test('should display JSON tab content on tab click', () => {
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen /> <HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen />
); );
findSections(wrapper); const handleTabClick = wrapper.find('Tabs').prop('onSelect');
expect(jsonSection.find('EmptyState').length).toBe(1); handleTabClick(null, 1);
wrapper.find('button[aria-label="JSON tab"]').simulate('click'); wrapper.update();
findSections(wrapper);
expect(jsonSection.find('CodeEditor').length).toBe(1);
const codeEditor = jsonSection.find('CodeEditor'); const codeEditor = wrapper.find('CodeEditor');
expect(codeEditor.prop('mode')).toBe('javascript'); expect(codeEditor.prop('mode')).toBe('javascript');
expect(codeEditor.prop('readOnly')).toBe(true); expect(codeEditor.prop('readOnly')).toBe(true);
expect(codeEditor.prop('value')).toEqual(jsonValue); expect(codeEditor.prop('value')).toEqual(jsonValue);
}); });
test('should display Standard Out tab content on tab click', () => { test('should display Standard Out tab content on tab click', () => {
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen /> <HostEventModal hostEvent={hostEvent} onClose={() => {}} isOpen />
); );
findSections(wrapper); const handleTabClick = wrapper.find('Tabs').prop('onSelect');
expect(standardOutSection.find('EmptyState').length).toBe(1); handleTabClick(null, 2);
wrapper.find('button[aria-label="Standard out tab"]').simulate('click'); wrapper.update();
findSections(wrapper);
expect(standardOutSection.find('CodeEditor').length).toBe(1);
const codeEditor = standardOutSection.find('CodeEditor'); const codeEditor = wrapper.find('CodeEditor');
expect(codeEditor.prop('mode')).toBe('javascript'); expect(codeEditor.prop('mode')).toBe('javascript');
expect(codeEditor.prop('readOnly')).toBe(true); expect(codeEditor.prop('readOnly')).toBe(true);
expect(codeEditor.prop('value')).toEqual(hostEvent.event_data.res.stdout); expect(codeEditor.prop('value')).toEqual(hostEvent.event_data.res.stdout);
@@ -222,28 +219,27 @@ describe('HostEventModal', () => {
}, },
}, },
}; };
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEventError} onClose={() => {}} isOpen /> <HostEventModal hostEvent={hostEventError} onClose={() => {}} isOpen />
); );
findSections(wrapper);
expect(standardErrorSection.find('EmptyState').length).toBe(1);
wrapper.find('button[aria-label="Standard error tab"]').simulate('click');
findSections(wrapper);
expect(standardErrorSection.find('CodeEditor').length).toBe(1);
const codeEditor = standardErrorSection.find('CodeEditor'); const handleTabClick = wrapper.find('Tabs').prop('onSelect');
handleTabClick(null, 3);
wrapper.update();
const codeEditor = wrapper.find('CodeEditor');
expect(codeEditor.prop('mode')).toBe('javascript'); expect(codeEditor.prop('mode')).toBe('javascript');
expect(codeEditor.prop('readOnly')).toBe(true); expect(codeEditor.prop('readOnly')).toBe(true);
expect(codeEditor.prop('value')).toEqual(' '); expect(codeEditor.prop('value')).toEqual(' ');
}); });
test('should call onClose when close button is clicked', () => { test('should pass onClose to Modal', () => {
const onClose = jest.fn(); const onClose = jest.fn();
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={hostEvent} onClose={onClose} isOpen /> <HostEventModal hostEvent={hostEvent} onClose={onClose} isOpen />
); );
wrapper.find('button[aria-label="Close"]').simulate('click');
expect(onClose).toBeCalled(); expect(wrapper.find('Modal').prop('onClose')).toEqual(onClose);
}); });
test('should render standard out of debug task', () => { test('should render standard out of debug task', () => {
@@ -258,12 +254,17 @@ describe('HostEventModal', () => {
}, },
}, },
}; };
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={debugTaskAction} onClose={() => {}} isOpen /> <HostEventModal hostEvent={debugTaskAction} onClose={() => {}} isOpen />
); );
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
findSections(wrapper); const handleTabClick = wrapper.find('Tabs').prop('onSelect');
const codeEditor = standardOutSection.find('CodeEditor'); handleTabClick(null, 2);
wrapper.update();
const codeEditor = wrapper.find('CodeEditor');
expect(codeEditor.prop('mode')).toBe('javascript');
expect(codeEditor.prop('readOnly')).toBe(true);
expect(codeEditor.prop('value')).toEqual('foo bar'); expect(codeEditor.prop('value')).toEqual('foo bar');
}); });
@@ -277,12 +278,17 @@ describe('HostEventModal', () => {
}, },
}, },
}; };
const wrapper = mountWithContexts( const wrapper = shallow(
<HostEventModal hostEvent={yumTaskAction} onClose={() => {}} isOpen /> <HostEventModal hostEvent={yumTaskAction} onClose={() => {}} isOpen />
); );
wrapper.find('button[aria-label="Standard out tab"]').simulate('click');
findSections(wrapper); const handleTabClick = wrapper.find('Tabs').prop('onSelect');
const codeEditor = standardOutSection.find('CodeEditor'); handleTabClick(null, 2);
wrapper.update();
const codeEditor = wrapper.find('CodeEditor');
expect(codeEditor.prop('mode')).toBe('javascript');
expect(codeEditor.prop('readOnly')).toBe(true);
expect(codeEditor.prop('value')).toEqual('baz'); expect(codeEditor.prop('value')).toEqual('baz');
}); });
}); });

View File

@@ -1,37 +1,26 @@
import React from 'react'; import React from 'react';
import { createMemoryHistory } from 'history'; import { shallow } from 'enzyme';
import { mountWithContexts } from '../../../testUtils/enzymeHelpers';
import Jobs from './Jobs'; import Jobs from './Jobs';
jest.mock('react-router-dom', () => ({ jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'), ...jest.requireActual('react-router-dom'),
useRouteMatch: () => ({
path: '/',
}),
})); }));
describe('<Jobs />', () => { describe('<Jobs />', () => {
test('initially renders successfully', () => { test('initially renders successfully', async () => {
mountWithContexts(<Jobs />); const wrapper = shallow(<Jobs />);
expect(wrapper.find('JobList')).toHaveLength(1);
}); });
test('should display a breadcrumb heading', () => { test('should display a breadcrumb heading', () => {
const history = createMemoryHistory({ const wrapper = shallow(<Jobs />);
initialEntries: ['/jobs'], const screenHeader = wrapper.find('ScreenHeader');
expect(screenHeader).toHaveLength(1);
expect(screenHeader.prop('breadcrumbConfig')).toEqual({
'/jobs': 'Jobs',
}); });
const match = { path: '/jobs', url: '/jobs', isExact: true };
const wrapper = mountWithContexts(<Jobs />, {
context: {
router: {
history,
route: {
location: history.location,
match,
},
},
},
});
expect(wrapper.find('Title').length).toBe(1);
wrapper.unmount();
}); });
}); });

View File

@@ -41,6 +41,8 @@ describe('<Subscription />', () => {
config: { config: {
license_info: { license_info: {
license_type: 'enterprise', license_type: 'enterprise',
automated_instances: '1',
automated_since: '1614714228',
}, },
}, },
}, },

View File

@@ -76,7 +76,12 @@ describe('<SubscriptionDetail />', () => {
test('should render edit button for system admin', () => { test('should render edit button for system admin', () => {
wrapper = mountWithContexts(<SubscriptionDetail />, { wrapper = mountWithContexts(<SubscriptionDetail />, {
context: { ...config, me: { is_superuser: true } }, context: {
config: {
...config,
me: { is_superuser: true },
},
},
}); });
expect(wrapper.find('Button[aria-label="edit"]').length).toBe(1); expect(wrapper.find('Button[aria-label="edit"]').length).toBe(1);

View File

@@ -290,7 +290,7 @@ function JobTemplateDetail({ template }) {
totalChips={summary_fields.credentials.length} totalChips={summary_fields.credentials.length}
> >
{summary_fields.credentials.map(c => ( {summary_fields.credentials.map(c => (
<Link to={`/credentials/${c.id}/details`}> <Link to={`/credentials/${c.id}/details`} key={c.id}>
<CredentialChip key={c.id} credential={c} isReadOnly /> <CredentialChip key={c.id} credential={c} isReadOnly />
</Link> </Link>
))} ))}

View File

@@ -37,6 +37,7 @@ describe('<JobTemplateDetail />', () => {
afterEach(() => { afterEach(() => {
jest.clearAllMocks(); jest.clearAllMocks();
}); });
test('should render successfully with missing summary fields', async () => { test('should render successfully with missing summary fields', async () => {
await act(async () => { await act(async () => {
wrapper = mountWithContexts( wrapper = mountWithContexts(

View File

@@ -16,6 +16,7 @@ export function required(message) {
return undefined; return undefined;
}; };
} }
export function validateTime() { export function validateTime() {
return value => { return value => {
const timeRegex = new RegExp( const timeRegex = new RegExp(

View File

@@ -1,3 +1,5 @@
import { i18n } from '@lingui/core';
import en from '../locales/en/messages';
import { import {
required, required,
minLength, minLength,
@@ -13,6 +15,12 @@ import {
} from './validators'; } from './validators';
describe('validators', () => { describe('validators', () => {
beforeAll(() => {
i18n.loadLocaleData({ en: { plurals: en } });
i18n.load({ en });
i18n.activate('en');
});
test('required returns undefined if value given', () => { test('required returns undefined if value given', () => {
expect(required(null)('some value')).toBeUndefined(); expect(required(null)('some value')).toBeUndefined();
expect(required('oops')('some value')).toBeUndefined(); expect(required('oops')('some value')).toBeUndefined();
@@ -169,6 +177,7 @@ describe('validators', () => {
test('bob has email', () => { test('bob has email', () => {
expect(requiredEmail()('bob@localhost')).toBeUndefined(); expect(requiredEmail()('bob@localhost')).toBeUndefined();
}); });
test('validate time validates properly', () => { test('validate time validates properly', () => {
expect(validateTime()('12:15 PM')).toBeUndefined(); expect(validateTime()('12:15 PM')).toBeUndefined();
expect(validateTime()('1:15 PM')).toBeUndefined(); expect(validateTime()('1:15 PM')).toBeUndefined();