flush out more type defs; JobDetail tests

This commit is contained in:
Keith Grant
2019-07-11 15:02:42 -07:00
parent 40f9b0dc7f
commit 552164c25c
6 changed files with 120 additions and 19 deletions

View File

@@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import { shape, string, bool } from 'prop-types'; import { shape } from 'prop-types';
import { toTitleCase } from '@util/strings'; import { toTitleCase } from '@util/strings';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import Chip from './Chip'; import Chip from './Chip';
import { Credential } from '../../types';
function CredentialChip ({ credential, i18n, ...props }) { function CredentialChip ({ credential, i18n, ...props }) {
let type; let type;
@@ -23,11 +24,7 @@ function CredentialChip ({ credential, i18n, ...props }) {
) )
} }
CredentialChip.propTypes = { CredentialChip.propTypes = {
credential: shape({ credential: Credential.isRequired,
cloud: bool,
kind: string,
name: string.isRequired,
}).isRequired,
i18n: shape({}).isRequired, i18n: shape({}).isRequired,
}; };

View File

@@ -5,6 +5,7 @@ import CredentialChip from './CredentialChip';
describe('CredentialChip', () => { describe('CredentialChip', () => {
test('should render SSH kind', () => { test('should render SSH kind', () => {
const credential = { const credential = {
id: 1,
kind: 'ssh', kind: 'ssh',
name: 'foo', name: 'foo',
}; };
@@ -17,6 +18,7 @@ describe('CredentialChip', () => {
test('should render AWS kind', () => { test('should render AWS kind', () => {
const credential = { const credential = {
id: 1,
kind: 'aws', kind: 'aws',
name: 'foo', name: 'foo',
}; };
@@ -29,6 +31,7 @@ describe('CredentialChip', () => {
test('should render with "Cloud"', () => { test('should render with "Cloud"', () => {
const credential = { const credential = {
id: 1,
cloud: true, cloud: true,
kind: 'other', kind: 'other',
name: 'foo', name: 'foo',
@@ -42,6 +45,7 @@ describe('CredentialChip', () => {
test('should render with other kind', () => { test('should render with other kind', () => {
const credential = { const credential = {
id: 1,
kind: 'other', kind: 'other',
name: 'foo', name: 'foo',
}; };

View File

@@ -1,5 +1,4 @@
import React from 'react'; import React from 'react';
import { shape } from 'prop-types';
import { Link, withRouter } from 'react-router-dom'; import { Link, withRouter } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
@@ -9,6 +8,7 @@ import { DetailList, Detail } from '@components/DetailList';
import { ChipGroup, Chip, CredentialChip } from '@components/Chip'; import { ChipGroup, Chip, CredentialChip } from '@components/Chip';
import { VariablesInput } from '@components/CodeMirrorInput'; import { VariablesInput } from '@components/CodeMirrorInput';
import { toTitleCase } from '@util/strings'; import { toTitleCase } from '@util/strings';
import { Job } from '../../../types';
const ActionButtonWrapper = styled.div` const ActionButtonWrapper = styled.div`
display: flex; display: flex;
@@ -105,7 +105,7 @@ function JobDetail({ job, i18n }) {
{labels && labels.count > 0 && ( {labels && labels.count > 0 && (
<Detail <Detail
fullWidth fullWidth
label={i18n._(t`Credentials`)} label={i18n._(t`Labels`)}
value={ value={
<ChipGroup showOverflowAfter={5}> <ChipGroup showOverflowAfter={5}>
{labels.results.map(l => ( {labels.results.map(l => (
@@ -150,7 +150,7 @@ function JobDetail({ job, i18n }) {
); );
} }
JobDetail.propTypes = { JobDetail.propTypes = {
job: shape({}).isRequired, job: Job.isRequired,
}; };
export default withI18n()(withRouter(JobDetail)); export default withI18n()(withRouter(JobDetail));

View File

@@ -1,22 +1,60 @@
import React from 'react'; import React from 'react';
import { mountWithContexts } from '@testUtils/enzymeHelpers'; import { mountWithContexts } from '@testUtils/enzymeHelpers';
import JobDetail from './JobDetail'; import JobDetail from './JobDetail';
describe('<JobDetail />', () => { describe('<JobDetail />', () => {
const mockDetails = { let job;
name: 'Foo',
}; beforeEach(() => {
job = {
name: 'Foo',
summary_fields: {},
};
});
test('initially renders succesfully', () => { test('initially renders succesfully', () => {
mountWithContexts(<JobDetail job={mockDetails} />); mountWithContexts(<JobDetail job={job} />);
}); });
test('should display a Close button', () => { test('should display a Close button', () => {
const wrapper = mountWithContexts(<JobDetail job={mockDetails} />); const wrapper = mountWithContexts(<JobDetail job={job} />);
expect(wrapper.find('Button[aria-label="close"]').length).toBe(1); expect(wrapper.find('Button[aria-label="close"]').length).toBe(1);
wrapper.unmount(); wrapper.unmount();
}); });
test('should display details', () => {
job.status = 'Successful';
job.started = '2019-07-02T17:35:22.753817Z';
job.finished = '2019-07-02T17:35:34.910800Z';
const wrapper = mountWithContexts(<JobDetail job={job} />);
const details = wrapper.find('Detail');
function assertDetail(detail, label, value) {
expect(detail.prop('label')).toEqual(label);
expect(detail.prop('value')).toEqual(value);
}
assertDetail(details.at(0), 'Status', 'Successful');
assertDetail(details.at(1), 'Started', job.started);
assertDetail(details.at(2), 'Finished', job.finished);
});
test('should display credentials', () => {
job.summary_fields.credentials = [
{
id: 1,
name: 'Foo',
cloud: false,
kind: 'ssh',
},
];
const wrapper = mountWithContexts(<JobDetail job={job} />);
const credentialChip = wrapper.find('CredentialChip');
expect(credentialChip.prop('credential')).toEqual(
job.summary_fields.credentials[0]
);
});
}); });

View File

@@ -0,0 +1,9 @@
/* eslint-disable-next-line import/prefer-default-export */
export const JOB_TYPE_URLS = {
job: 'playbook',
project_update: 'project',
system_job: 'system',
inventory_update: 'inventory',
ad_hoc_command: 'command',
workflow_job: 'workflow',
};

View File

@@ -65,8 +65,61 @@ export const QSConfig = shape({
export const JobTemplate = shape({ export const JobTemplate = shape({
name: string.isRequired, name: string.isRequired,
description: string, description: string,
inventory: oneOfType([number, string]).isRequired, inventory: number,
job_type: oneOf(['run', 'check']), job_type: oneOf(['run', 'check']),
playbook: string.isRequired, playbook: string,
project: oneOfType([number, string]).isRequired, project: number,
});
export const Project = shape({
id: number.isRequired,
name: string.isRequired,
});
export const Inventory = shape({
id: number.isRequired,
name: string.isRequired,
});
export const InstanceGroup = shape({
id: number.isRequired,
name: string.isRequired,
});
export const Label = shape({
id: number.isRequired,
name: string.isRequired,
});
export const Credential = shape({
id: number.isRequired,
name: string.isRequired,
cloud: bool,
kind: string,
});
export const Job = shape({
status: string,
started: string,
finished: string,
job_type: string,
summary_fields: shape({
job_template: JobTemplate,
project: Project,
inventory: Inventory,
instance_group: InstanceGroup,
credentials: arrayOf(Credential),
labels: shape({
count: number,
results: arrayOf(Label),
}),
}),
scm_revision: string,
limit: oneOfType([number, string]),
verbosity: number,
execution_mode: string,
job_slice_number: number,
job_slice_count: number,
extra_vars: string,
artifacts: shape({}),
}); });