mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 18:40:01 -03:30
update JobTemplateForm tests
This commit is contained in:
parent
4f546be87a
commit
8b1ca12d8f
@ -16,6 +16,7 @@ function CheckboxField({ id, name, label, tooltip, validate, ...rest }) {
|
||||
validate={validate}
|
||||
render={({ field }) => (
|
||||
<Checkbox
|
||||
aria-label={label}
|
||||
label={
|
||||
<span>
|
||||
{label}
|
||||
|
||||
@ -57,7 +57,7 @@ FormField.propTypes = {
|
||||
type: PropTypes.string,
|
||||
validate: PropTypes.func,
|
||||
isRequired: PropTypes.bool,
|
||||
tooltip: PropTypes.string,
|
||||
tooltip: PropTypes.node,
|
||||
};
|
||||
|
||||
FormField.defaultProps = {
|
||||
|
||||
@ -12,10 +12,11 @@ const getInstanceGroups = async params => InstanceGroupsAPI.read(params);
|
||||
|
||||
class InstanceGroupsLookup extends React.Component {
|
||||
render() {
|
||||
const { value, tooltip, onChange, i18n } = this.props;
|
||||
const { value, tooltip, onChange, className, i18n } = this.props;
|
||||
|
||||
return (
|
||||
<FormGroup
|
||||
className={className}
|
||||
label={
|
||||
<Fragment>
|
||||
{i18n._(t`Instance Groups`)}{' '}
|
||||
|
||||
@ -92,6 +92,32 @@ const mockRelatedProjectPlaybooks = [
|
||||
'vault.yml',
|
||||
];
|
||||
|
||||
const mockInstanceGroups = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'instance_group',
|
||||
url: '/api/v2/instance_groups/1/',
|
||||
related: {
|
||||
jobs: '/api/v2/instance_groups/1/jobs/',
|
||||
instances: '/api/v2/instance_groups/1/instances/',
|
||||
},
|
||||
name: 'tower',
|
||||
capacity: 59,
|
||||
committed_capacity: 0,
|
||||
consumed_capacity: 0,
|
||||
percent_capacity_remaining: 100.0,
|
||||
jobs_running: 0,
|
||||
jobs_total: 3,
|
||||
instances: 1,
|
||||
controller: null,
|
||||
is_controller: false,
|
||||
is_isolated: false,
|
||||
policy_instance_percentage: 100,
|
||||
policy_instance_minimum: 0,
|
||||
policy_instance_list: [],
|
||||
},
|
||||
];
|
||||
|
||||
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
||||
data: mockRelatedCredentials,
|
||||
});
|
||||
@ -101,12 +127,25 @@ ProjectsAPI.readPlaybooks.mockResolvedValue({
|
||||
LabelsAPI.read.mockResolvedValue({ data: { results: [] } });
|
||||
|
||||
describe('<JobTemplateEdit />', () => {
|
||||
test('initially renders successfully', async done => {
|
||||
beforeEach(() => {
|
||||
LabelsAPI.read.mockResolvedValue({ data: { results: [] } });
|
||||
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
||||
data: mockRelatedCredentials,
|
||||
});
|
||||
JobTemplatesAPI.readInstanceGroups.mockReturnValue({
|
||||
data: { results: mockInstanceGroups },
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders successfully', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateEdit template={mockJobTemplate} />
|
||||
);
|
||||
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleSubmit should call api update', async done => {
|
||||
|
||||
@ -157,23 +157,6 @@ class JobTemplateForm extends Component {
|
||||
newLabel => newLabel.name !== label
|
||||
);
|
||||
this.setState({ newLabels: filteredLabels });
|
||||
} else if (typeof label === 'string') {
|
||||
setFieldValue('newLabels', [
|
||||
...newLabels,
|
||||
{
|
||||
name: label,
|
||||
organization: template.summary_fields.inventory.organization_id,
|
||||
},
|
||||
]);
|
||||
this.setState({
|
||||
newLabels: [
|
||||
...newLabels,
|
||||
{
|
||||
name: label,
|
||||
organization: template.summary_fields.inventory.organization_id,
|
||||
},
|
||||
],
|
||||
});
|
||||
} else {
|
||||
setFieldValue('newLabels', [
|
||||
...newLabels,
|
||||
@ -182,7 +165,12 @@ class JobTemplateForm extends Component {
|
||||
this.setState({
|
||||
newLabels: [
|
||||
...newLabels,
|
||||
{ name: label.name, associate: true, id: label.id },
|
||||
{
|
||||
name: label.name,
|
||||
associate: true,
|
||||
id: label.id,
|
||||
organization: template.summary_fields.inventory.organization_id,
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
@ -311,6 +299,12 @@ class JobTemplateForm extends Component {
|
||||
{ value: '3', key: '3', label: i18n._(t`3 (Debug)`) },
|
||||
{ value: '4', key: '4', label: i18n._(t`4 (Connection Debug)`) },
|
||||
];
|
||||
let callbackUrl;
|
||||
if (template && template.related) {
|
||||
const { origin } = document.location;
|
||||
const path = template.related.callback || `${template.url}callback`;
|
||||
callbackUrl = `${origin}${path}`;
|
||||
}
|
||||
|
||||
if (hasContentLoading) {
|
||||
return (
|
||||
@ -477,6 +471,7 @@ class JobTemplateForm extends Component {
|
||||
id="template-forks"
|
||||
name="forks"
|
||||
type="number"
|
||||
min="0"
|
||||
label={i18n._(t`Forks`)}
|
||||
tooltip={
|
||||
<span>
|
||||
@ -568,6 +563,7 @@ class JobTemplateForm extends Component {
|
||||
/>
|
||||
</FormRow>
|
||||
<InstanceGroupsLookup
|
||||
css="margin-top: 20px"
|
||||
value={relatedInstanceGroups}
|
||||
onChange={this.handleInstanceGroupsChange}
|
||||
tooltip={i18n._(
|
||||
@ -579,6 +575,7 @@ class JobTemplateForm extends Component {
|
||||
render={({ field, form }) => (
|
||||
<FormGroup
|
||||
label={i18n._(t`Job Tags`)}
|
||||
css="margin-top: 20px"
|
||||
fieldId="template-job-tags"
|
||||
>
|
||||
<Tooltip
|
||||
@ -603,6 +600,7 @@ class JobTemplateForm extends Component {
|
||||
render={({ field, form }) => (
|
||||
<FormGroup
|
||||
label={i18n._(t`Skip Tags`)}
|
||||
css="margin-top: 20px"
|
||||
fieldId="template-skip-tags"
|
||||
>
|
||||
<Tooltip
|
||||
@ -622,7 +620,12 @@ class JobTemplateForm extends Component {
|
||||
</FormGroup>
|
||||
)}
|
||||
/>
|
||||
<GridFormGroup isInline label={i18n._(t`Options`)}>
|
||||
<GridFormGroup
|
||||
fieldId="template-option-checkboxes"
|
||||
isInline
|
||||
label={i18n._(t`Options`)}
|
||||
css="margin-top: 20px"
|
||||
>
|
||||
<CheckboxField
|
||||
id="option-privilege-escalation"
|
||||
name="become_enabled"
|
||||
@ -641,7 +644,7 @@ class JobTemplateForm extends Component {
|
||||
position="right"
|
||||
content={i18n._(
|
||||
t`Enables creation of a provisioning callback URL. Using
|
||||
the URL a host can contact {{BRAND_NAME}} and request a
|
||||
the URL a host can contact BRAND_NAME and request a
|
||||
configuration update using this job template.`
|
||||
)}
|
||||
>
|
||||
@ -677,19 +680,22 @@ class JobTemplateForm extends Component {
|
||||
<div
|
||||
css={`
|
||||
${allowCallbacks ? '' : 'display: none'}
|
||||
margin-top: 20px;
|
||||
`}
|
||||
>
|
||||
<FormRow>
|
||||
<FormGroup
|
||||
label={i18n._(t`Provisioning Callback URL`)}
|
||||
fieldId="template-callback-url"
|
||||
>
|
||||
<TextInput
|
||||
id="template-callback-url"
|
||||
isDisabled
|
||||
value={`${document.location.origin}${template.related.callback}`}
|
||||
/>
|
||||
</FormGroup>
|
||||
{callbackUrl && (
|
||||
<FormGroup
|
||||
label={i18n._(t`Provisioning Callback URL`)}
|
||||
fieldId="template-callback-url"
|
||||
>
|
||||
<TextInput
|
||||
id="template-callback-url"
|
||||
isDisabled
|
||||
value={callbackUrl}
|
||||
/>
|
||||
</FormGroup>
|
||||
)}
|
||||
<FormField
|
||||
id="template-host-config-key"
|
||||
name="host_config_key"
|
||||
|
||||
@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
||||
import { sleep } from '@testUtils/testUtils';
|
||||
import JobTemplateForm, { _JobTemplateForm } from './JobTemplateForm';
|
||||
import { LabelsAPI } from '@api';
|
||||
import { LabelsAPI, JobTemplatesAPI } from '@api';
|
||||
|
||||
jest.mock('@api');
|
||||
|
||||
@ -29,17 +29,45 @@ describe('<JobTemplateForm />', () => {
|
||||
labels: { results: [{ name: 'Sushi', id: 1 }, { name: 'Major', id: 2 }] },
|
||||
},
|
||||
};
|
||||
const mockInstanceGroups = [
|
||||
{
|
||||
id: 1,
|
||||
type: 'instance_group',
|
||||
url: '/api/v2/instance_groups/1/',
|
||||
related: {
|
||||
jobs: '/api/v2/instance_groups/1/jobs/',
|
||||
instances: '/api/v2/instance_groups/1/instances/',
|
||||
},
|
||||
name: 'tower',
|
||||
capacity: 59,
|
||||
committed_capacity: 0,
|
||||
consumed_capacity: 0,
|
||||
percent_capacity_remaining: 100.0,
|
||||
jobs_running: 0,
|
||||
jobs_total: 3,
|
||||
instances: 1,
|
||||
controller: null,
|
||||
is_controller: false,
|
||||
is_isolated: false,
|
||||
policy_instance_percentage: 100,
|
||||
policy_instance_minimum: 0,
|
||||
policy_instance_list: [],
|
||||
},
|
||||
];
|
||||
beforeEach(() => {
|
||||
LabelsAPI.read.mockReturnValue({
|
||||
data: mockData.summary_fields.labels,
|
||||
});
|
||||
JobTemplatesAPI.readInstanceGroups.mockReturnValue({
|
||||
data: { results: mockInstanceGroups },
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
test('initially renders successfully', async done => {
|
||||
test('should render labels MultiSelect', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
template={mockData}
|
||||
@ -47,19 +75,18 @@ describe('<JobTemplateForm />', () => {
|
||||
handleCancel={jest.fn()}
|
||||
/>
|
||||
);
|
||||
|
||||
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
||||
await waitForElement(wrapper, 'Form', el => el.length === 0);
|
||||
expect(LabelsAPI.read).toHaveBeenCalled();
|
||||
expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalled();
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper
|
||||
.find('FormGroup[fieldId="template-labels"] MultiSelect Chip')
|
||||
.first()
|
||||
.text()
|
||||
).toEqual('Sushi');
|
||||
done();
|
||||
.find('FormGroup[fieldId="template-labels"] MultiSelect')
|
||||
.prop('associatedItems')
|
||||
).toEqual(mockData.summary_fields.labels.results);
|
||||
});
|
||||
|
||||
test('should update form values on input changes', async done => {
|
||||
test('should update form values on input changes', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
template={mockData}
|
||||
@ -96,10 +123,9 @@ describe('<JobTemplateForm />', () => {
|
||||
target: { value: 'new baz type', name: 'playbook' },
|
||||
});
|
||||
expect(form.state('values').playbook).toEqual('new baz type');
|
||||
done();
|
||||
});
|
||||
|
||||
test('should call handleSubmit when Submit button is clicked', async done => {
|
||||
test('should call handleSubmit when Submit button is clicked', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
@ -113,10 +139,9 @@ describe('<JobTemplateForm />', () => {
|
||||
wrapper.find('button[aria-label="Save"]').simulate('click');
|
||||
await sleep(1);
|
||||
expect(handleSubmit).toBeCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
test('should call handleCancel when Cancel button is clicked', async done => {
|
||||
test('should call handleCancel when Cancel button is clicked', async () => {
|
||||
const handleCancel = jest.fn();
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
@ -129,10 +154,9 @@ describe('<JobTemplateForm />', () => {
|
||||
expect(handleCancel).not.toHaveBeenCalled();
|
||||
wrapper.find('button[aria-label="Cancel"]').prop('onClick')();
|
||||
expect(handleCancel).toBeCalled();
|
||||
done();
|
||||
});
|
||||
|
||||
test('should call loadRelatedProjectPlaybooks when project value changes', async done => {
|
||||
test('should call loadRelatedProjectPlaybooks when project value changes', async () => {
|
||||
const loadRelatedProjectPlaybooks = jest.spyOn(
|
||||
_JobTemplateForm.prototype,
|
||||
'loadRelatedProjectPlaybooks'
|
||||
@ -150,15 +174,10 @@ describe('<JobTemplateForm />', () => {
|
||||
name: 'project',
|
||||
});
|
||||
expect(loadRelatedProjectPlaybooks).toHaveBeenCalledWith(10);
|
||||
done();
|
||||
});
|
||||
|
||||
test('handleNewLabel should arrange new labels properly', async done => {
|
||||
const handleNewLabel = jest.spyOn(
|
||||
_JobTemplateForm.prototype,
|
||||
'handleNewLabel'
|
||||
);
|
||||
const event = { key: 'Enter', preventDefault: () => {} };
|
||||
test('handleNewLabel should arrange new labels properly', async () => {
|
||||
const event = { key: 'Enter' };
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
template={mockData}
|
||||
@ -167,22 +186,25 @@ describe('<JobTemplateForm />', () => {
|
||||
/>
|
||||
);
|
||||
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
||||
const multiSelect = wrapper.find('MultiSelect');
|
||||
const multiSelect = wrapper.find(
|
||||
'FormGroup[fieldId="template-labels"] MultiSelect'
|
||||
);
|
||||
const component = wrapper.find('JobTemplateForm');
|
||||
|
||||
wrapper.setState({ newLabels: [], loadedLabels: [], removedLabels: [] });
|
||||
multiSelect.setState({ input: 'Foo' });
|
||||
component.find('input[aria-label="labels"]').prop('onKeyDown')(event);
|
||||
expect(handleNewLabel).toHaveBeenCalledWith('Foo');
|
||||
component
|
||||
.find('FormGroup[fieldId="template-labels"] input[aria-label="labels"]')
|
||||
.prop('onKeyDown')(event);
|
||||
|
||||
component.instance().handleNewLabel({ name: 'Bar', id: 2 });
|
||||
expect(component.state().newLabels).toEqual([
|
||||
{ name: 'Foo', organization: 1 },
|
||||
{ associate: true, id: 2, name: 'Bar' },
|
||||
]);
|
||||
done();
|
||||
const newLabels = component.state('newLabels');
|
||||
expect(newLabels).toHaveLength(2);
|
||||
expect(newLabels[0].name).toEqual('Foo');
|
||||
expect(newLabels[0].organization).toEqual(1);
|
||||
});
|
||||
test('disassociateLabel should arrange new labels properly', async done => {
|
||||
|
||||
test('disassociateLabel should arrange new labels properly', async () => {
|
||||
const wrapper = mountWithContexts(
|
||||
<JobTemplateForm
|
||||
template={mockData}
|
||||
@ -203,6 +225,5 @@ describe('<JobTemplateForm />', () => {
|
||||
component.instance().removeLabel({ name: 'Sushi', id: 1 });
|
||||
expect(component.state().newLabels.length).toBe(0);
|
||||
expect(component.state().removedLabels.length).toBe(1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user