1
0
mirror of https://github.com/ansible/awx.git synced 2024-11-01 16:51:11 +03:00

Move organization form to functional component

This commit is contained in:
Jake McDermott 2019-12-18 08:40:47 -05:00
parent 2f9742e9de
commit 057320aed3
No known key found for this signature in database
GPG Key ID: 0E56ED990CDFCB4F
6 changed files with 311 additions and 360 deletions

View File

@ -50,8 +50,8 @@ function OrganizationAdd({ i18n }) {
<Config>
{({ me }) => (
<OrganizationForm
handleSubmit={handleSubmit}
handleCancel={handleCancel}
onSubmit={handleSubmit}
onCancel={handleCancel}
me={me || {}}
/>
)}

View File

@ -8,7 +8,7 @@ import { OrganizationsAPI } from '@api';
jest.mock('@api');
describe('<OrganizationAdd />', () => {
test('handleSubmit should post to api', async () => {
test('onSubmit should post to api', async () => {
const updatedOrgData = {
name: 'new name',
description: 'new description',
@ -16,11 +16,7 @@ describe('<OrganizationAdd />', () => {
};
await act(async () => {
const wrapper = mountWithContexts(<OrganizationAdd />);
wrapper.find('OrganizationForm').prop('handleSubmit')(
updatedOrgData,
[],
[]
);
wrapper.find('OrganizationForm').prop('onSubmit')(updatedOrgData, [], []);
});
expect(OrganizationsAPI.create).toHaveBeenCalledWith(updatedOrgData);
});
@ -32,6 +28,9 @@ describe('<OrganizationAdd />', () => {
wrapper = mountWithContexts(<OrganizationAdd />, {
context: { router: { history } },
});
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
});
expect(history.location.pathname).toEqual('/organizations');
@ -71,16 +70,12 @@ describe('<OrganizationAdd />', () => {
context: { router: { history } },
});
await waitForElement(wrapper, 'button[aria-label="Save"]');
await wrapper.find('OrganizationForm').prop('handleSubmit')(
orgData,
[3],
[]
);
await wrapper.find('OrganizationForm').prop('onSubmit')(orgData, [3], []);
});
expect(history.location.pathname).toEqual('/organizations/5');
});
test('handleSubmit should post instance groups', async () => {
test('onSubmit should post instance groups', async () => {
const orgData = {
name: 'new name',
description: 'new description',
@ -100,15 +95,17 @@ describe('<OrganizationAdd />', () => {
wrapper = mountWithContexts(<OrganizationAdd />);
});
await waitForElement(wrapper, 'button[aria-label="Save"]');
await wrapper.find('OrganizationForm').prop('handleSubmit')(
orgData,
[3],
[]
);
await wrapper.find('OrganizationForm').prop('onSubmit')(orgData, [3], []);
expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(5, 3);
});
test('AnsibleSelect component renders if there are virtual environments', async () => {
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
},
});
const config = {
custom_virtualenvs: ['foo', 'bar'],
};
@ -116,8 +113,9 @@ describe('<OrganizationAdd />', () => {
await act(async () => {
wrapper = mountWithContexts(<OrganizationAdd />, {
context: { config },
}).find('AnsibleSelect');
});
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('FormSelect')).toHaveLength(1);
expect(wrapper.find('FormSelectOption')).toHaveLength(3);
expect(
@ -129,6 +127,12 @@ describe('<OrganizationAdd />', () => {
});
test('AnsibleSelect component does not render if there are 0 virtual environments', async () => {
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
},
});
const config = {
custom_virtualenvs: [],
};
@ -136,8 +140,9 @@ describe('<OrganizationAdd />', () => {
await act(async () => {
wrapper = mountWithContexts(<OrganizationAdd />, {
context: { config },
}).find('AnsibleSelect');
});
});
expect(wrapper.find('FormSelect')).toHaveLength(0);
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('AnsibleSelect FormSelect')).toHaveLength(0);
});
});

View File

@ -46,8 +46,8 @@ function OrganizationEdit({ organization }) {
{({ me }) => (
<OrganizationForm
organization={organization}
handleSubmit={handleSubmit}
handleCancel={handleCancel}
onSubmit={handleSubmit}
onCancel={handleCancel}
me={me || {}}
/>
)}

View File

@ -2,7 +2,7 @@ import React from 'react';
import { act } from 'react-dom/test-utils';
import { createMemoryHistory } from 'history';
import { OrganizationsAPI } from '@api';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
import OrganizationEdit from './OrganizationEdit';
jest.mock('@api');
@ -18,7 +18,7 @@ describe('<OrganizationEdit />', () => {
},
};
test('handleSubmit should call api update', async () => {
test('onSubmit should call api update', async () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(<OrganizationEdit organization={mockData} />);
@ -29,16 +29,12 @@ describe('<OrganizationEdit />', () => {
description: 'new description',
custom_virtualenv: 'Buzz',
};
wrapper.find('OrganizationForm').prop('handleSubmit')(
updatedOrgData,
[],
[]
);
wrapper.find('OrganizationForm').prop('onSubmit')(updatedOrgData, [], []);
expect(OrganizationsAPI.update).toHaveBeenCalledWith(1, updatedOrgData);
});
test('handleSubmit associates and disassociates instance groups', async () => {
test('onSubmit associates and disassociates instance groups', async () => {
let wrapper;
await act(async () => {
wrapper = mountWithContexts(<OrganizationEdit organization={mockData} />);
@ -50,13 +46,12 @@ describe('<OrganizationEdit />', () => {
custom_virtualenv: 'Buzz',
};
await act(async () => {
wrapper.find('OrganizationForm').invoke('handleSubmit')(
wrapper.find('OrganizationForm').invoke('onSubmit')(
updatedOrgData,
[3, 4],
[2]
);
});
expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 3);
expect(OrganizationsAPI.associateInstanceGroup).toHaveBeenCalledWith(1, 4);
expect(OrganizationsAPI.disassociateInstanceGroup).toHaveBeenCalledWith(
@ -66,6 +61,12 @@ describe('<OrganizationEdit />', () => {
});
test('should navigate to organization detail when cancel is clicked', async () => {
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
},
});
const history = createMemoryHistory({});
let wrapper;
await act(async () => {
@ -74,9 +75,10 @@ describe('<OrganizationEdit />', () => {
{ context: { router: { history } } }
);
});
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper.find('button[aria-label="Cancel"]').invoke('onClick')();
});
expect(history.location.pathname).toEqual('/organizations/1/details');
});
});

View File

@ -1,206 +1,174 @@
import React, { Component, Fragment } from 'react';
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { QuestionCircleIcon } from '@patternfly/react-icons';
import { withRouter } from 'react-router-dom';
import { Formik, Field } from 'formik';
import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro';
import { QuestionCircleIcon } from '@patternfly/react-icons';
import { Tooltip, Form, FormGroup } from '@patternfly/react-core';
import { OrganizationsAPI } from '@api';
import { Config } from '@contexts/Config';
import { ConfigContext } from '@contexts/Config';
import AnsibleSelect from '@components/AnsibleSelect';
import ContentError from '@components/ContentError';
import ContentLoading from '@components/ContentLoading';
import FormRow from '@components/FormRow';
import FormField from '@components/FormField';
import FormActionGroup from '@components/FormActionGroup/FormActionGroup';
import AnsibleSelect from '@components/AnsibleSelect';
import { InstanceGroupsLookup } from '@components/Lookup/';
import { getAddedAndRemoved } from '@util/lists';
import { required, minMaxValue } from '@util/validators';
class OrganizationForm extends Component {
constructor(props) {
super(props);
function OrganizationForm({ organization, i18n, me, onCancel, onSubmit }) {
const defaultVenv = {
label: i18n._(t`Use Default Ansible Environment`),
value: '/venv/ansible/',
key: 'default',
};
const { custom_virtualenvs } = useContext(ConfigContext);
const [contentError, setContentError] = useState(null);
const [hasContentLoading, setHasContentLoading] = useState(true);
const [initialInstanceGroups, setInitialInstanceGroups] = useState([]);
const [instanceGroups, setInstanceGroups] = useState([]);
this.getRelatedInstanceGroups = this.getRelatedInstanceGroups.bind(this);
this.handleInstanceGroupsChange = this.handleInstanceGroupsChange.bind(
this
const handleCancel = () => {
onCancel();
};
const handleSubmit = values => {
const { added, removed } = getAddedAndRemoved(
initialInstanceGroups,
instanceGroups
);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
instanceGroups: [],
initialInstanceGroups: [],
formIsValid: true,
};
}
async componentDidMount() {
let instanceGroups = [];
if (!this.isEditingNewOrganization()) {
try {
instanceGroups = await this.getRelatedInstanceGroups();
} catch (err) {
this.setState({ error: err });
}
}
this.setState({
instanceGroups,
initialInstanceGroups: [...instanceGroups],
});
}
async getRelatedInstanceGroups() {
const {
organization: { id },
} = this.props;
const { data } = await OrganizationsAPI.readInstanceGroups(id);
return data.results;
}
isEditingNewOrganization() {
const { organization } = this.props;
return !organization.id;
}
handleInstanceGroupsChange(instanceGroups) {
this.setState({ instanceGroups });
}
handleSubmit(values) {
const { handleSubmit } = this.props;
const { instanceGroups, initialInstanceGroups } = this.state;
const initialIds = initialInstanceGroups.map(ig => ig.id);
const updatedIds = instanceGroups.map(ig => ig.id);
const groupsToAssociate = [...updatedIds].filter(
x => !initialIds.includes(x)
);
const groupsToDisassociate = [...initialIds].filter(
x => !updatedIds.includes(x)
);
const addedIds = added.map(({ id }) => id);
const removedIds = removed.map(({ id }) => id);
if (
typeof values.max_hosts !== 'number' ||
values.max_hosts === 'undefined'
) {
values.max_hosts = 0;
}
onSubmit(values, addedIds, removedIds);
};
handleSubmit(values, groupsToAssociate, groupsToDisassociate);
useEffect(() => {
(async () => {
const { id } = organization;
if (!id) {
setHasContentLoading(false);
return;
}
setContentError(null);
setHasContentLoading(true);
try {
const {
data: { results = [] },
} = await OrganizationsAPI.readInstanceGroups(id);
setInitialInstanceGroups(results);
setInstanceGroups(results);
} catch (error) {
setContentError(error);
} finally {
setHasContentLoading(false);
}
})();
}, [organization]);
if (contentError) {
return <ContentError error={contentError} />;
}
render() {
const { organization, handleCancel, i18n, me } = this.props;
const { instanceGroups, formIsValid, error } = this.state;
const defaultVenv = {
label: i18n._(t`Use Default Ansible Environment`),
value: '/venv/ansible/',
key: 'default',
};
if (hasContentLoading) {
return <ContentLoading />;
}
return (
<Formik
initialValues={{
name: organization.name,
description: organization.description,
custom_virtualenv: organization.custom_virtualenv || '',
max_hosts: organization.max_hosts || '0',
}}
onSubmit={this.handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="org-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required(null, i18n)}
isRequired
/>
<FormField
id="org-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
<FormField
id="org-max_hosts"
name="max_hosts"
type="number"
label={
<Fragment>
{i18n._(t`Max Hosts`)}{' '}
{
<Tooltip
position="right"
content={i18n._(t`The maximum number of hosts allowed
to be managed by this organization. Value defaults to
0 which means no limit. Refer to the Ansible
documentation for more details.`)}
>
<QuestionCircleIcon />
</Tooltip>
}
</Fragment>
}
validate={minMaxValue(0, 2147483647, i18n)}
me={me || {}}
isDisabled={!me.is_superuser}
/>
<Config>
{({ custom_virtualenvs }) =>
custom_virtualenvs &&
custom_virtualenvs.length > 1 && (
<Field
name="custom_virtualenv"
render={({ field }) => (
<FormGroup
fieldId="org-custom-virtualenv"
label={i18n._(t`Ansible Environment`)}
>
<AnsibleSelect
id="org-custom-virtualenv"
data={[
defaultVenv,
...custom_virtualenvs
.filter(datum => datum !== defaultVenv.value)
.map(datum => ({
label: datum,
value: datum,
key: datum,
})),
]}
{...field}
/>
</FormGroup>
)}
return (
<Formik
initialValues={{
name: organization.name,
description: organization.description,
custom_virtualenv: organization.custom_virtualenv || '',
max_hosts: organization.max_hosts || '0',
}}
onSubmit={handleSubmit}
render={formik => (
<Form autoComplete="off" onSubmit={formik.handleSubmit}>
<FormRow>
<FormField
id="org-name"
name="name"
type="text"
label={i18n._(t`Name`)}
validate={required(null, i18n)}
isRequired
/>
<FormField
id="org-description"
name="description"
type="text"
label={i18n._(t`Description`)}
/>
<FormField
id="org-max_hosts"
name="max_hosts"
type="number"
label={
<>
{i18n._(t`Max Hosts`)}{' '}
<Tooltip
position="right"
content={i18n._(
t`The maximum number of hosts allowed to be managed by this organization.
Value defaults to 0 which means no limit. Refer to the Ansible
documentation for more details.`
)}
>
<QuestionCircleIcon />
</Tooltip>
</>
}
validate={minMaxValue(0, Number.MAX_SAFE_INTEGER, i18n)}
me={me || {}}
isDisabled={!me.is_superuser}
/>
{custom_virtualenvs && custom_virtualenvs.length > 1 && (
<Field
name="custom_virtualenv"
render={({ field }) => (
<FormGroup
fieldId="org-custom-virtualenv"
label={i18n._(t`Ansible Environment`)}
>
<AnsibleSelect
id="org-custom-virtualenv"
data={[
defaultVenv,
...custom_virtualenvs
.filter(value => value !== defaultVenv.value)
.map(value => ({ value, label: value, key: value })),
]}
{...field}
/>
)
}
</Config>
</FormRow>
<InstanceGroupsLookup
value={instanceGroups}
onChange={this.handleInstanceGroupsChange}
tooltip={i18n._(
t`Select the Instance Groups for this Organization to run on.`
)}
/>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
submitDisabled={!formIsValid}
/>
{error ? <div>error</div> : null}
</Form>
)}
/>
);
}
</FormGroup>
)}
/>
)}
</FormRow>
<InstanceGroupsLookup
value={instanceGroups}
onChange={setInstanceGroups}
tooltip={i18n._(
t`Select the Instance Groups for this Organization to run on.`
)}
/>
<FormActionGroup
onCancel={handleCancel}
onSubmit={formik.handleSubmit}
/>
</Form>
)}
/>
);
}
FormField.propTypes = {
@ -209,8 +177,8 @@ FormField.propTypes = {
OrganizationForm.propTypes = {
organization: PropTypes.shape(),
handleSubmit: PropTypes.func.isRequired,
handleCancel: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
};
OrganizationForm.defaultProps = {

View File

@ -1,7 +1,6 @@
import React from 'react';
import { act } from 'react-dom/test-utils';
import { mountWithContexts } from '@testUtils/enzymeHelpers';
import { sleep } from '@testUtils/testUtils';
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
import { OrganizationsAPI } from '@api';
import OrganizationForm from './OrganizationForm';
@ -25,18 +24,20 @@ describe('<OrganizationForm />', () => {
instance_groups: '/api/v2/organizations/1/instance_groups',
},
};
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
afterEach(() => {
jest.clearAllMocks();
});
test('should request related instance groups from api', async () => {
let wrapper;
await act(async () => {
mountWithContexts(
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={jest.fn()}
onSubmit={jest.fn()}
onCancel={jest.fn()}
me={meConfig.me}
/>,
{
@ -44,12 +45,11 @@ describe('<OrganizationForm />', () => {
}
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
});
test('componentDidMount should set instanceGroups to state', async () => {
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
@ -60,8 +60,8 @@ describe('<OrganizationForm />', () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={jest.fn()}
onSubmit={jest.fn()}
onCancel={jest.fn()}
me={meConfig.me}
/>,
{
@ -70,84 +70,109 @@ describe('<OrganizationForm />', () => {
);
});
await waitForElement(
wrapper,
'InstanceGroupsLookup',
el => el.length === 1
);
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalled();
expect(wrapper.find('OrganizationForm').state().instanceGroups).toEqual(
mockInstanceGroups
);
expect(wrapper.find('InstanceGroupsLookup Chip span')).toHaveLength(2);
});
test('changing instance group successfully sets instanceGroups state', async () => {
test('Instance group is rendered when added', async () => {
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: { results: [] },
});
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={jest.fn()}
onSubmit={jest.fn()}
onCancel={jest.fn()}
me={meConfig.me}
/>
);
});
const lookup = wrapper.find('InstanceGroupsLookup');
const lookup = await waitForElement(
wrapper,
'InstanceGroupsLookup',
el => el.length === 1
);
expect(lookup.length).toBe(1);
lookup.prop('onChange')(
[
{
id: 1,
name: 'foo',
},
],
'instanceGroups'
expect(lookup.find('Chip span')).toHaveLength(0);
await act(async () => {
lookup.prop('onChange')(
[
{
id: 1,
name: 'foo',
},
],
'instanceGroups'
);
});
const group = await waitForElement(
wrapper,
'InstanceGroupsLookup Chip span',
el => el.length === 1
);
expect(wrapper.find('OrganizationForm').state().instanceGroups).toEqual([
{
id: 1,
name: 'foo',
},
]);
expect(group.text()).toEqual('foo');
});
test('changing inputs should update form values', async () => {
test('changing inputs and saving triggers expected callback', async () => {
let wrapper;
const onSubmit = jest.fn();
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={jest.fn()}
onSubmit={onSubmit}
onCancel={jest.fn()}
me={meConfig.me}
/>
);
});
const form = wrapper.find('Formik');
wrapper.find('input#org-name').simulate('change', {
target: { value: 'new foo', name: 'name' },
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper.find('input#org-name').simulate('change', {
target: { value: 'new foo', name: 'name' },
});
wrapper.find('input#org-description').simulate('change', {
target: { value: 'new bar', name: 'description' },
});
wrapper.find('input#org-max_hosts').simulate('change', {
target: { value: 134, name: 'max_hosts' },
});
});
expect(form.state('values').name).toEqual('new foo');
wrapper.find('input#org-description').simulate('change', {
target: { value: 'new bar', name: 'description' },
await act(async () => {
wrapper.find('button[aria-label="Save"]').simulate('click');
});
expect(form.state('values').description).toEqual('new bar');
wrapper.find('input#org-max_hosts').simulate('change', {
target: { value: '134', name: 'max_hosts' },
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(onSubmit.mock.calls[0][0]).toEqual({
name: 'new foo',
description: 'new bar',
custom_virtualenv: 'Fizz',
max_hosts: 134,
});
expect(form.state('values').max_hosts).toEqual('134');
});
test('AnsibleSelect component renders if there are virtual environments', async () => {
const config = {
custom_virtualenvs: ['foo', 'bar'],
};
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
},
});
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={jest.fn()}
onSubmit={jest.fn()}
onCancel={jest.fn()}
me={meConfig.me}
/>,
{
@ -155,6 +180,7 @@ describe('<OrganizationForm />', () => {
}
);
});
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(wrapper.find('FormSelect')).toHaveLength(1);
expect(wrapper.find('FormSelectOption')).toHaveLength(3);
expect(
@ -165,36 +191,7 @@ describe('<OrganizationForm />', () => {
).toEqual('/venv/ansible/');
});
test('calls handleSubmit when form submitted', async () => {
const handleSubmit = jest.fn();
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
me={meConfig.me}
/>
);
});
expect(handleSubmit).not.toHaveBeenCalled();
wrapper.find('button[aria-label="Save"]').simulate('click');
await sleep(1);
expect(handleSubmit).toHaveBeenCalledWith(
{
name: 'Foo',
description: 'Bar',
max_hosts: 1,
custom_virtualenv: 'Fizz',
},
[],
[]
);
});
test('handleSubmit associates and disassociates instance groups', async () => {
const mockInstanceGroups = [{ name: 'One', id: 1 }, { name: 'Two', id: 2 }];
test('onSubmit associates and disassociates instance groups', async () => {
OrganizationsAPI.readInstanceGroups.mockReturnValue({
data: {
results: mockInstanceGroups,
@ -206,7 +203,7 @@ describe('<OrganizationForm />', () => {
max_hosts: 1,
custom_virtualenv: 'Fizz',
};
const handleSubmit = jest.fn();
const onSubmit = jest.fn();
OrganizationsAPI.update.mockResolvedValue(1, mockDataForm);
OrganizationsAPI.associateInstanceGroup.mockResolvedValue('done');
OrganizationsAPI.disassociateInstanceGroup.mockResolvedValue('done');
@ -215,8 +212,8 @@ describe('<OrganizationForm />', () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
onSubmit={onSubmit}
onCancel={jest.fn()}
me={meConfig.me}
/>,
{
@ -224,47 +221,21 @@ describe('<OrganizationForm />', () => {
}
);
});
wrapper.find('InstanceGroupsLookup').prop('onChange')(
[{ name: 'One', id: 1 }, { name: 'Three', id: 3 }],
'instanceGroups'
);
wrapper.find('button[aria-label="Save"]').simulate('click');
await sleep(0);
expect(handleSubmit).toHaveBeenCalledWith(mockDataForm, [3], [2]);
});
test('handleSubmit is called with max_hosts value if it is in range', async () => {
const handleSubmit = jest.fn();
let wrapper;
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
me={meConfig.me}
/>
wrapper.find('InstanceGroupsLookup').prop('onChange')(
[{ name: 'One', id: 1 }, { name: 'Three', id: 3 }],
'instanceGroups'
);
});
wrapper.find('button[aria-label="Save"]').simulate('click');
await sleep(0);
expect(handleSubmit).toHaveBeenCalledWith(
{
name: 'Foo',
description: 'Bar',
max_hosts: 1,
custom_virtualenv: 'Fizz',
},
[],
[]
);
await act(async () => {
wrapper.find('button[aria-label="Save"]').simulate('click');
});
expect(onSubmit).toHaveBeenCalledWith(mockDataForm, [3], [2]);
});
test('handleSubmit does not get called if max_hosts value is out of range', async () => {
const handleSubmit = jest.fn();
test('onSubmit does not get called if max_hosts value is out of range', async () => {
const onSubmit = jest.fn();
// mount with negative value
let wrapper1;
const mockDataNegative = JSON.parse(JSON.stringify(mockData));
@ -273,38 +244,41 @@ describe('<OrganizationForm />', () => {
wrapper1 = mountWithContexts(
<OrganizationForm
organization={mockDataNegative}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
onSubmit={onSubmit}
onCancel={jest.fn()}
me={meConfig.me}
/>
);
});
wrapper1.find('button[aria-label="Save"]').simulate('click');
await sleep(0);
expect(handleSubmit).not.toHaveBeenCalled();
await waitForElement(wrapper1, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper1.find('button[aria-label="Save"]').simulate('click');
});
expect(onSubmit).not.toHaveBeenCalled();
// mount with out of range value
let wrapper2;
const mockDataOoR = JSON.parse(JSON.stringify(mockData));
mockDataOoR.max_hosts = 999999999999;
const mockDataOutOfRange = JSON.parse(JSON.stringify(mockData));
mockDataOutOfRange.max_hosts = 999999999999999999999;
await act(async () => {
wrapper2 = mountWithContexts(
<OrganizationForm
organization={mockDataOoR}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
organization={mockDataOutOfRange}
onSubmit={onSubmit}
onCancel={jest.fn()}
me={meConfig.me}
/>
);
});
wrapper2.find('button[aria-label="Save"]').simulate('click');
await sleep(0);
expect(handleSubmit).not.toHaveBeenCalled();
await waitForElement(wrapper2, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper2.find('button[aria-label="Save"]').simulate('click');
});
expect(onSubmit).not.toHaveBeenCalled();
});
test('handleSubmit is called and max_hosts value defaults to 0 if input is not a number', async () => {
const handleSubmit = jest.fn();
test('onSubmit is called and max_hosts value defaults to 0 if input is not a number', async () => {
const onSubmit = jest.fn();
// mount with String value (default to zero)
const mockDataString = JSON.parse(JSON.stringify(mockData));
mockDataString.max_hosts = 'Bee';
@ -313,15 +287,17 @@ describe('<OrganizationForm />', () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockDataString}
handleSubmit={handleSubmit}
handleCancel={jest.fn()}
onSubmit={onSubmit}
onCancel={jest.fn()}
me={meConfig.me}
/>
);
});
wrapper.find('button[aria-label="Save"]').simulate('click');
await sleep(0);
expect(handleSubmit).toHaveBeenCalledWith(
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
await act(async () => {
wrapper.find('button[aria-label="Save"]').simulate('click');
});
expect(onSubmit).toHaveBeenCalledWith(
{
name: 'Foo',
description: 'Bar',
@ -333,22 +309,22 @@ describe('<OrganizationForm />', () => {
);
});
test('calls "handleCancel" when Cancel button is clicked', async () => {
const handleCancel = jest.fn();
test('calls "onCancel" when Cancel button is clicked', async () => {
const onCancel = jest.fn();
let wrapper;
await act(async () => {
wrapper = mountWithContexts(
<OrganizationForm
organization={mockData}
handleSubmit={jest.fn()}
handleCancel={handleCancel}
onSubmit={jest.fn()}
onCancel={onCancel}
me={meConfig.me}
/>
);
});
expect(handleCancel).not.toHaveBeenCalled();
await waitForElement(wrapper, 'ContentLoading', el => el.length === 0);
expect(onCancel).not.toHaveBeenCalled();
wrapper.find('button[aria-label="Cancel"]').prop('onClick')();
expect(handleCancel).toBeCalled();
expect(onCancel).toBeCalled();
});
});