mirror of
https://github.com/ansible/awx.git
synced 2026-05-08 01:47:35 -02:30
Adds error handling test to add and edit form. Updates Form component
This commit is contained in:
@@ -48,7 +48,7 @@ class WorkflowJobTemplates extends Base {
|
|||||||
|
|
||||||
readScheduleList(id, params) {
|
readScheduleList(id, params) {
|
||||||
return this.http.get(`${this.baseUrl}${id}/schedules/`, {
|
return this.http.get(`${this.baseUrl}${id}/schedules/`, {
|
||||||
params
|
params,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ function CredentialLookup({
|
|||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
readOnly={!canDelete}
|
readOnly={!canDelete}
|
||||||
|
name="credential"
|
||||||
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
|
selectItem={item => dispatch({ type: 'SELECT_ITEM', item })}
|
||||||
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
|
deselectItem={item => dispatch({ type: 'DESELECT_ITEM', item })}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -221,36 +221,34 @@ class Template extends Component {
|
|||||||
<JobList defaultParams={{ job__job_template: template.id }} />
|
<JobList defaultParams={{ job__job_template: template.id }} />
|
||||||
</Route>
|
</Route>
|
||||||
)}
|
)}
|
||||||
{template?.id && (
|
{template && (
|
||||||
<Route path="/templates/:templateType/:id/completed_jobs">
|
<Route
|
||||||
<JobList defaultParams={{ job__job_template: template.id }} />
|
path="/templates/:templateType/:id/schedules"
|
||||||
</Route>
|
render={() => (
|
||||||
)}
|
<ScheduleList loadSchedules={this.loadSchedules} />
|
||||||
{template && (
|
)}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
<Route
|
<Route
|
||||||
path="/templates/:templateType/:id/schedules"
|
key="not-found"
|
||||||
render={() => <ScheduleList loadSchedules={this.loadSchedules} />}
|
path="*"
|
||||||
|
render={() =>
|
||||||
|
!hasContentLoading && (
|
||||||
|
<ContentError isNotFound>
|
||||||
|
{match.params.id && (
|
||||||
|
<Link
|
||||||
|
to={`/templates/${match.params.templateType}/${match.params.id}/details`}
|
||||||
|
>
|
||||||
|
{i18n._(`View Template Details`)}
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
</ContentError>
|
||||||
|
)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
</Switch>
|
||||||
<Route
|
</Card>
|
||||||
key="not-found"
|
</PageSection>
|
||||||
path="*"
|
|
||||||
render={() =>
|
|
||||||
!hasContentLoading && (
|
|
||||||
<ContentError isNotFound>
|
|
||||||
{match.params.id && (
|
|
||||||
<Link
|
|
||||||
to={`/templates/${match.params.templateType}/${match.params.id}/details`}
|
|
||||||
>
|
|
||||||
{i18n._(`View Template Details`)}
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</ContentError>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
</Switch>
|
|
||||||
</Card>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Templates extends Component {
|
|||||||
'/templates': i18n._(t`Templates`),
|
'/templates': i18n._(t`Templates`),
|
||||||
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
||||||
'/templates/workflow_job_template/add': i18n._(
|
'/templates/workflow_job_template/add': i18n._(
|
||||||
t`Create New Workflow Job Template`
|
t`Create New Workflow Template`
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
@@ -35,6 +35,9 @@ class Templates extends Component {
|
|||||||
const breadcrumbConfig = {
|
const breadcrumbConfig = {
|
||||||
'/templates': i18n._(t`Templates`),
|
'/templates': i18n._(t`Templates`),
|
||||||
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
'/templates/job_template/add': i18n._(t`Create New Job Template`),
|
||||||
|
'/templates/workflow_job_template/add': i18n._(
|
||||||
|
t`Create New Workflow Template`
|
||||||
|
),
|
||||||
[`/templates/${template.type}/${template.id}`]: `${template.name}`,
|
[`/templates/${template.type}/${template.id}`]: `${template.name}`,
|
||||||
[`/templates/${template.type}/${template.id}/details`]: i18n._(
|
[`/templates/${template.type}/${template.id}/details`]: i18n._(
|
||||||
t`Details`
|
t`Details`
|
||||||
|
|||||||
@@ -186,16 +186,6 @@ class WorkflowJobTemplate extends Component {
|
|||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{template?.id && (
|
|
||||||
<Route path="/templates/workflow_job_template/:id/completed_jobs">
|
|
||||||
<JobList
|
|
||||||
defaultParams={{
|
|
||||||
workflow_job__workflow_job_template: template.id,
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</Route>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{template?.id && (
|
{template?.id && (
|
||||||
<Route path="/templates/workflow_job_template/:id/completed_jobs">
|
<Route path="/templates/workflow_job_template/:id/completed_jobs">
|
||||||
<JobList
|
<JobList
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ function WorkflowJobTemplateAdd() {
|
|||||||
const {
|
const {
|
||||||
data: { id },
|
data: { id },
|
||||||
} = await WorkflowJobTemplatesAPI.create(remainingValues);
|
} = await WorkflowJobTemplatesAPI.create(remainingValues);
|
||||||
await submitLabels(id, labels, organizationId);
|
await Promise.all(await submitLabels(id, labels, organizationId));
|
||||||
history.push(`/templates/workflow_job_template/${id}/details`);
|
history.push(`/templates/workflow_job_template/${id}/details`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
setFormSubmitError(err);
|
setFormSubmitError(err);
|
||||||
|
|||||||
@@ -1,43 +1,60 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route } from 'react-router-dom';
|
import { Route } from 'react-router-dom';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { WorkflowJobTemplatesAPI } from '@api';
|
import { WorkflowJobTemplatesAPI, OrganizationsAPI, LabelsAPI } from '@api';
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
|
|
||||||
import WorkflowJobTemplateAdd from './WorkflowJobTemplateAdd';
|
import WorkflowJobTemplateAdd from './WorkflowJobTemplateAdd';
|
||||||
|
|
||||||
jest.mock('@api');
|
jest.mock('@api/models/WorkflowJobTemplates');
|
||||||
|
jest.mock('@api/models/Organizations');
|
||||||
|
jest.mock('@api/models/Labels');
|
||||||
|
jest.mock('@api/models/Inventories');
|
||||||
|
|
||||||
describe('<WorkflowJobTemplateAdd/>', () => {
|
describe('<WorkflowJobTemplateAdd/>', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let history;
|
let history;
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
WorkflowJobTemplatesAPI.create.mockResolvedValue({ data: { id: 1 } });
|
WorkflowJobTemplatesAPI.create.mockResolvedValue({ data: { id: 1 } });
|
||||||
|
OrganizationsAPI.read.mockResolvedValue({ results: [{ id: 1 }] });
|
||||||
|
LabelsAPI.read.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
results: [
|
||||||
|
{ name: 'Label 1', id: 1 },
|
||||||
|
{ name: 'Label 2', id: 2 },
|
||||||
|
{ name: 'Label 3', id: 3 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
history = createMemoryHistory({
|
history = createMemoryHistory({
|
||||||
initialEntries: ['/templates/workflow_job_template/add'],
|
initialEntries: ['/templates/workflow_job_template/add'],
|
||||||
});
|
});
|
||||||
wrapper = mountWithContexts(
|
await act(async () => {
|
||||||
<Route
|
wrapper = await mountWithContexts(
|
||||||
path="/templates/workflow_job_template/add"
|
<Route
|
||||||
component={() => <WorkflowJobTemplateAdd />}
|
path="/templates/workflow_job_template/add"
|
||||||
/>,
|
component={() => <WorkflowJobTemplateAdd />}
|
||||||
{
|
/>,
|
||||||
context: {
|
{
|
||||||
router: {
|
context: {
|
||||||
history,
|
router: {
|
||||||
route: {
|
history,
|
||||||
location: history.location,
|
route: {
|
||||||
|
location: history.location,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
}
|
);
|
||||||
);
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
afterEach(async () => {
|
afterEach(async () => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('initially renders successfully', async () => {
|
test('initially renders successfully', async () => {
|
||||||
@@ -67,28 +84,39 @@ describe('<WorkflowJobTemplateAdd/>', () => {
|
|||||||
|
|
||||||
test('throwing error renders FormSubmitError component', async () => {
|
test('throwing error renders FormSubmitError component', async () => {
|
||||||
const error = new Error('oops');
|
const error = new Error('oops');
|
||||||
WorkflowJobTemplatesAPI.create.mockImplementation(() =>
|
WorkflowJobTemplatesAPI.create.mockRejectedValue(error);
|
||||||
Promise.reject(error)
|
|
||||||
);
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
await wrapper.find('WorkflowJobTemplateForm').prop('handleSubmit')({
|
wrapper.find('WorkflowJobTemplateForm').invoke('handleSubmit')({
|
||||||
id: 6,
|
name: 'Foo',
|
||||||
name: 'Alex',
|
|
||||||
description: 'Apollo and Athena',
|
|
||||||
inventory: { id: 1, name: 'Inventory 1' },
|
|
||||||
organization: 2,
|
|
||||||
scm_branch: 'master',
|
|
||||||
limit: '5000',
|
|
||||||
variables: '---',
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
expect(wrapper.find('ContentError').length).toBe(0);
|
expect(WorkflowJobTemplatesAPI.create).toHaveBeenCalled();
|
||||||
expect(wrapper.length).toBe(1);
|
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(WorkflowJobTemplatesAPI.create).toBeCalled();
|
|
||||||
expect(wrapper.find('ContentError').length).toBe(1);
|
|
||||||
expect(wrapper.find('WorkflowJobTemplateForm').prop('submitError')).toEqual(
|
expect(wrapper.find('WorkflowJobTemplateForm').prop('submitError')).toEqual(
|
||||||
error
|
error
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('throwing error prevents navigation away from form', async () => {
|
||||||
|
OrganizationsAPI.read.mockRejectedValue(
|
||||||
|
new Error({
|
||||||
|
response: {
|
||||||
|
config: {
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
data: 'An error occurred',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
WorkflowJobTemplatesAPI.update.mockResolvedValue();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
await wrapper.find('Button[aria-label="Save"]').simulate('click');
|
||||||
|
});
|
||||||
|
expect(wrapper.find('WorkflowJobTemplateForm').length).toBe(1);
|
||||||
|
expect(OrganizationsAPI.read).toBeCalled();
|
||||||
|
expect(history.location.pathname).toBe(
|
||||||
|
'/templates/workflow_job_template/add'
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ function WorkflowJobTemplateDetail({ template, i18n, webhook_key }) {
|
|||||||
)}
|
)}
|
||||||
{template.webhook_service && (
|
{template.webhook_service && (
|
||||||
<TextListItem component={TextListItemVariants.li}>
|
<TextListItem component={TextListItemVariants.li}>
|
||||||
{i18n._(t`- Webhooks`)}
|
{i18n._(t`- Enable Webhook`)}
|
||||||
</TextListItem>
|
</TextListItem>
|
||||||
)}
|
)}
|
||||||
</TextList>
|
</TextList>
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ function WorkflowJobTemplateEdit({ template, webhook_key }) {
|
|||||||
const handleSubmit = async values => {
|
const handleSubmit = async values => {
|
||||||
const { labels, ...remainingValues } = values;
|
const { labels, ...remainingValues } = values;
|
||||||
try {
|
try {
|
||||||
await submitLabels(labels, values.organization, template.organization);
|
await Promise.all(
|
||||||
|
await submitLabels(labels, values.organization, template.organization)
|
||||||
|
);
|
||||||
await WorkflowJobTemplatesAPI.update(template.id, remainingValues);
|
await WorkflowJobTemplatesAPI.update(template.id, remainingValues);
|
||||||
history.push(`/templates/workflow_job_template/${template.id}/details`);
|
history.push(`/templates/workflow_job_template/${template.id}/details`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Route } from 'react-router-dom';
|
import { Route } from 'react-router-dom';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { WorkflowJobTemplatesAPI, OrganizationsAPI } from '@api';
|
import { WorkflowJobTemplatesAPI, OrganizationsAPI, LabelsAPI } from '@api';
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit';
|
import WorkflowJobTemplateEdit from './WorkflowJobTemplateEdit';
|
||||||
|
|
||||||
jest.mock('@api/models/WorkflowJobTemplates');
|
jest.mock('@api/models/WorkflowJobTemplates');
|
||||||
|
jest.mock('@api/models/Labels');
|
||||||
jest.mock('@api/models/Organizations');
|
jest.mock('@api/models/Organizations');
|
||||||
|
jest.mock('@api/models/Inventories');
|
||||||
|
|
||||||
const mockTemplate = {
|
const mockTemplate = {
|
||||||
id: 6,
|
id: 6,
|
||||||
@@ -27,8 +29,14 @@ const mockTemplate = {
|
|||||||
describe('<WorkflowJobTemplateEdit/>', () => {
|
describe('<WorkflowJobTemplateEdit/>', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
let history;
|
let history;
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
LabelsAPI.read.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
results: [{ name: 'Label 1', id: 1 }, { name: 'Label 2', id: 2 }],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
OrganizationsAPI.read.mockResolvedValue({ results: [{ id: 1 }] });
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
history = createMemoryHistory({
|
history = createMemoryHistory({
|
||||||
initialEntries: ['/templates/workflow_job_template/6/edit'],
|
initialEntries: ['/templates/workflow_job_template/6/edit'],
|
||||||
@@ -93,7 +101,6 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
|||||||
id: 1,
|
id: 1,
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
await expect(WorkflowJobTemplatesAPI.associateLabel).toBeCalledTimes(1);
|
await expect(WorkflowJobTemplatesAPI.associateLabel).toBeCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -108,7 +115,6 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
|||||||
|
|
||||||
test('throwing error renders FormSubmitError component', async () => {
|
test('throwing error renders FormSubmitError component', async () => {
|
||||||
const error = new Error('oops');
|
const error = new Error('oops');
|
||||||
OrganizationsAPI.read.mockResolvedValue({ results: [{ id: 1 }] });
|
|
||||||
WorkflowJobTemplatesAPI.update.mockRejectedValue(error);
|
WorkflowJobTemplatesAPI.update.mockRejectedValue(error);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Button[aria-label="Save"]').simulate('click');
|
wrapper.find('Button[aria-label="Save"]').simulate('click');
|
||||||
@@ -120,13 +126,26 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('throwing error prevents form submission', () => {
|
test('throwing error prevents form submission', async () => {
|
||||||
OrganizationsAPI.read.mockRejectedValue(new Error('An error occurred'));
|
const templateWithoutOrg = {
|
||||||
WorkflowJobTemplatesAPI.update.mockResolvedValue();
|
id: 6,
|
||||||
|
name: 'Foo',
|
||||||
|
description: 'Foo description',
|
||||||
|
summary_fields: {
|
||||||
|
inventory: { id: 1, name: 'Inventory 1' },
|
||||||
|
labels: {
|
||||||
|
results: [{ name: 'Label 1', id: 1 }, { name: 'Label 2', id: 2 }],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
scm_branch: 'devel',
|
||||||
|
limit: '5000',
|
||||||
|
variables: '---',
|
||||||
|
};
|
||||||
|
|
||||||
act(() => {
|
let newWrapper;
|
||||||
wrapper = mountWithContexts(
|
await act(async () => {
|
||||||
<WorkflowJobTemplateEdit template={mockTemplate} />,
|
newWrapper = await mountWithContexts(
|
||||||
|
<WorkflowJobTemplateEdit template={templateWithoutOrg} />,
|
||||||
{
|
{
|
||||||
context: {
|
context: {
|
||||||
router: {
|
router: {
|
||||||
@@ -136,9 +155,22 @@ describe('<WorkflowJobTemplateEdit/>', () => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
wrapper.find('Button[aria-label="Save"]').simulate('click');
|
OrganizationsAPI.read.mockRejectedValue(
|
||||||
|
new Error({
|
||||||
|
response: {
|
||||||
|
config: {
|
||||||
|
method: 'get',
|
||||||
|
},
|
||||||
|
data: 'An error occurred',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
WorkflowJobTemplatesAPI.update.mockResolvedValue();
|
||||||
|
|
||||||
expect(wrapper.find('WorkflowJobTemplateForm').length).toBe(1);
|
await act(async () => {
|
||||||
|
await newWrapper.find('Button[aria-label="Save"]').simulate('click');
|
||||||
|
});
|
||||||
|
expect(newWrapper.find('WorkflowJobTemplateForm').length).toBe(1);
|
||||||
expect(OrganizationsAPI.read).toBeCalled();
|
expect(OrganizationsAPI.read).toBeCalled();
|
||||||
expect(WorkflowJobTemplatesAPI.update).not.toBeCalled();
|
expect(WorkflowJobTemplatesAPI.update).not.toBeCalled();
|
||||||
expect(history.location.pathname).toBe(
|
expect(history.location.pathname).toBe(
|
||||||
|
|||||||
@@ -49,12 +49,15 @@ function WorkflowJobTemplateForm({
|
|||||||
submitError,
|
submitError,
|
||||||
}) {
|
}) {
|
||||||
const urlOrigin = window.location.origin;
|
const urlOrigin = window.location.origin;
|
||||||
|
|
||||||
const { id } = useParams();
|
const { id } = useParams();
|
||||||
const wfjtAddMatch = useRouteMatch('/templates/workflow_job_template/add');
|
const wfjtAddMatch = useRouteMatch('/templates/workflow_job_template/add');
|
||||||
|
|
||||||
const [hasContentError, setContentError] = useState(null);
|
const [hasContentError, setContentError] = useState(null);
|
||||||
|
const [webhook_url, setWebhookUrl] = useState(
|
||||||
|
template?.related?.webhook_receiver
|
||||||
|
? `${urlOrigin}${template.related.webhook_receiver}`
|
||||||
|
: ''
|
||||||
|
);
|
||||||
const [inventory, setInventory] = useState(
|
const [inventory, setInventory] = useState(
|
||||||
template?.summary_fields?.inventory || null
|
template?.summary_fields?.inventory || null
|
||||||
);
|
);
|
||||||
@@ -141,8 +144,11 @@ function WorkflowJobTemplateForm({
|
|||||||
);
|
);
|
||||||
setWebhookCredential(initialWebhookCredential);
|
setWebhookCredential(initialWebhookCredential);
|
||||||
|
|
||||||
form.setFieldValue('webhook_url', form.initialValues.webhook_url);
|
setWebhookUrl(
|
||||||
|
template?.related?.webhook_receiver
|
||||||
|
? `${urlOrigin}${template.related.webhook_receiver}`
|
||||||
|
: ''
|
||||||
|
);
|
||||||
form.setFieldValue('webhook_service', form.initialValues.webhook_service);
|
form.setFieldValue('webhook_service', form.initialValues.webhook_service);
|
||||||
setWebHookService(form.initialValues.webhook_service);
|
setWebHookService(form.initialValues.webhook_service);
|
||||||
|
|
||||||
@@ -151,8 +157,7 @@ function WorkflowJobTemplateForm({
|
|||||||
form.setFieldValue('webhook_credential', null);
|
form.setFieldValue('webhook_credential', null);
|
||||||
setWebhookCredential(null);
|
setWebhookCredential(null);
|
||||||
|
|
||||||
form.setFieldValue(
|
setWebhookUrl(
|
||||||
'webhook_url',
|
|
||||||
`${urlOrigin}/api/v2/workflow_job_templates/${template.id}/${webhookServiceValue}/`
|
`${urlOrigin}/api/v2/workflow_job_templates/${template.id}/${webhookServiceValue}/`
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -171,7 +176,7 @@ function WorkflowJobTemplateForm({
|
|||||||
initialWebhookKey = webhookKey;
|
initialWebhookKey = webhookKey;
|
||||||
form.setFieldValue('webhook_credential', null);
|
form.setFieldValue('webhook_credential', null);
|
||||||
form.setFieldValue('webhook_service', '');
|
form.setFieldValue('webhook_service', '');
|
||||||
form.setFieldValue('webhook_url', '');
|
setWebhookUrl('');
|
||||||
setWebHookService('');
|
setWebHookService('');
|
||||||
setWebHookKey('');
|
setWebHookKey('');
|
||||||
} else {
|
} else {
|
||||||
@@ -203,11 +208,8 @@ function WorkflowJobTemplateForm({
|
|||||||
labels: template.summary_fields?.labels?.results || [],
|
labels: template.summary_fields?.labels?.results || [],
|
||||||
extra_vars: template.variables || '---',
|
extra_vars: template.variables || '---',
|
||||||
limit: template.limit || '',
|
limit: template.limit || '',
|
||||||
scmBranch: template.scm_branch || '',
|
scm_branch: template.scm_branch || '',
|
||||||
allow_simultaneous: template.allow_simultaneous || false,
|
allow_simultaneous: template.allow_simultaneous || false,
|
||||||
webhook_url:
|
|
||||||
template?.related?.webhook_receiver &&
|
|
||||||
`${urlOrigin}${template?.related?.webhook_receiver}`,
|
|
||||||
webhook_credential:
|
webhook_credential:
|
||||||
template?.summary_fields?.webhook_credential?.id || null,
|
template?.summary_fields?.webhook_credential?.id || null,
|
||||||
webhook_service: template.webhook_service || '',
|
webhook_service: template.webhook_service || '',
|
||||||
@@ -290,8 +292,8 @@ function WorkflowJobTemplateForm({
|
|||||||
tooltip={i18n._(
|
tooltip={i18n._(
|
||||||
t`Select a branch for the workflow. This branch is applied to all job template nodes that prompt for a branch.`
|
t`Select a branch for the workflow. This branch is applied to all job template nodes that prompt for a branch.`
|
||||||
)}
|
)}
|
||||||
id="wfjt-scmBranch"
|
id="wfjt-scm_branch"
|
||||||
name="scmBranch"
|
name="scm_branch"
|
||||||
/>
|
/>
|
||||||
</FormColumnLayout>
|
</FormColumnLayout>
|
||||||
<FormFullWidthLayout>
|
<FormFullWidthLayout>
|
||||||
@@ -333,17 +335,13 @@ function WorkflowJobTemplateForm({
|
|||||||
isInline
|
isInline
|
||||||
label={i18n._(t`Options`)}
|
label={i18n._(t`Options`)}
|
||||||
>
|
>
|
||||||
<Field
|
<Field id="wfjt-webhooks" name="hasWebhooks">
|
||||||
id="wfjt-webhooks"
|
|
||||||
name="hasWebhooks"
|
|
||||||
label={i18n._(t`Webhooks`)}
|
|
||||||
>
|
|
||||||
{({ form }) => (
|
{({ form }) => (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
aria-label={i18n._(t`Webhooks`)}
|
aria-label={i18n._(t`Enable Webhook`)}
|
||||||
label={
|
label={
|
||||||
<span>
|
<span>
|
||||||
{i18n._(t`Webhooks`)}
|
{i18n._(t`Enable Webhook`)}
|
||||||
|
|
||||||
<FieldTooltip
|
<FieldTooltip
|
||||||
content={i18n._(
|
content={i18n._(
|
||||||
@@ -408,16 +406,24 @@ function WorkflowJobTemplateForm({
|
|||||||
</Field>
|
</Field>
|
||||||
{!wfjtAddMatch && (
|
{!wfjtAddMatch && (
|
||||||
<>
|
<>
|
||||||
<FormField
|
<FormGroup
|
||||||
type="text"
|
type="text"
|
||||||
|
fieldId="wfjt-webhookURL"
|
||||||
label={i18n._(t`Webhook URL`)}
|
label={i18n._(t`Webhook URL`)}
|
||||||
id="wfjt-webhook-url"
|
id="wfjt-webhook-url"
|
||||||
name="webhook_url"
|
name="webhook_url"
|
||||||
tooltip={i18n._(
|
>
|
||||||
t`Webhook services can launch jobs with this job template by making a POST request to this URL.`
|
<FieldTooltip
|
||||||
)}
|
content={i18n._(
|
||||||
isReadOnly
|
t`Webhook services can launch jobs with this workflow job template by making a POST request to this URL.`
|
||||||
/>
|
)}
|
||||||
|
/>
|
||||||
|
<TextInput
|
||||||
|
aria-label={i18n._(t`Webhook URL`)}
|
||||||
|
value={webhook_url}
|
||||||
|
isReadOnly
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
<Field>
|
<Field>
|
||||||
{({ form }) => (
|
{({ form }) => (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
|||||||
@@ -6,13 +6,17 @@ import { sleep } from '@testUtils/testUtils';
|
|||||||
|
|
||||||
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
import { mountWithContexts } from '@testUtils/enzymeHelpers';
|
||||||
import WorkflowJobTemplateForm from './WorkflowJobTemplateForm';
|
import WorkflowJobTemplateForm from './WorkflowJobTemplateForm';
|
||||||
import { WorkflowJobTemplatesAPI } from '@api';
|
import {
|
||||||
|
WorkflowJobTemplatesAPI,
|
||||||
|
LabelsAPI,
|
||||||
|
OrganizationsAPI,
|
||||||
|
InventoriesAPI,
|
||||||
|
} from '@api';
|
||||||
|
|
||||||
jest.mock('@api/models/WorkflowJobTemplates');
|
jest.mock('@api/models/WorkflowJobTemplates');
|
||||||
|
jest.mock('@api/models/Labels');
|
||||||
WorkflowJobTemplatesAPI.updateWebhookKey.mockResolvedValue({
|
jest.mock('@api/models/Organizations');
|
||||||
data: { webhook_key: 'sdafdghjkl2345678ionbvcxz' },
|
jest.mock('@api/models/Inventories');
|
||||||
});
|
|
||||||
|
|
||||||
describe('<WorkflowJobTemplateForm/>', () => {
|
describe('<WorkflowJobTemplateForm/>', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
@@ -38,12 +42,31 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(async () => {
|
||||||
|
WorkflowJobTemplatesAPI.updateWebhookKey.mockResolvedValue({
|
||||||
|
data: { webhook_key: 'sdafdghjkl2345678ionbvcxz' },
|
||||||
|
});
|
||||||
|
LabelsAPI.read.mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
results: [
|
||||||
|
{ name: 'Label 1', id: 1 },
|
||||||
|
{ name: 'Label 2', id: 2 },
|
||||||
|
{ name: 'Label 3', id: 3 },
|
||||||
|
],
|
||||||
|
},
|
||||||
|
});
|
||||||
|
OrganizationsAPI.read.mockResolvedValue({
|
||||||
|
results: [{ id: 1 }, { id: 2 }],
|
||||||
|
});
|
||||||
|
InventoriesAPI.read.mockResolvedValue({
|
||||||
|
results: [{ id: 1, name: 'Foo' }, { id: 2, name: 'Bar' }],
|
||||||
|
});
|
||||||
|
|
||||||
history = createMemoryHistory({
|
history = createMemoryHistory({
|
||||||
initialEntries: ['/templates/workflow_job_template/6/edit'],
|
initialEntries: ['/templates/workflow_job_template/6/edit'],
|
||||||
});
|
});
|
||||||
act(() => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = await mountWithContexts(
|
||||||
<Route
|
<Route
|
||||||
path="/templates/workflow_job_template/:id/edit"
|
path="/templates/workflow_job_template/:id/edit"
|
||||||
component={() => (
|
component={() => (
|
||||||
@@ -86,7 +109,7 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
'Field[name="organization"]',
|
'Field[name="organization"]',
|
||||||
'Field[name="inventory"]',
|
'Field[name="inventory"]',
|
||||||
'FormField[name="limit"]',
|
'FormField[name="limit"]',
|
||||||
'FormField[name="scmBranch"]',
|
'FormField[name="scm_branch"]',
|
||||||
'Field[name="labels"]',
|
'Field[name="labels"]',
|
||||||
'VariablesField',
|
'VariablesField',
|
||||||
];
|
];
|
||||||
@@ -108,8 +131,8 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
},
|
},
|
||||||
{ element: 'wfjt-limit', value: { value: 1234567890, name: 'limit' } },
|
{ element: 'wfjt-limit', value: { value: 1234567890, name: 'limit' } },
|
||||||
{
|
{
|
||||||
element: 'wfjt-scmBranch',
|
element: 'wfjt-scm_branch',
|
||||||
value: { value: 'new branch', name: 'scmBranch' },
|
value: { value: 'new branch', name: 'scm_branch' },
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
const changeInputs = async ({ element, value }) => {
|
const changeInputs = async ({ element, value }) => {
|
||||||
@@ -122,7 +145,7 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
inputsToChange.map(input => changeInputs(input));
|
inputsToChange.map(input => changeInputs(input));
|
||||||
|
|
||||||
wrapper.find('LabelSelect').invoke('onChange')([
|
wrapper.find('LabelSelect').invoke('onChange')([
|
||||||
{ name: 'new label', id: 5 },
|
{ name: 'Label 3', id: 3 },
|
||||||
{ name: 'Label 1', id: 1 },
|
{ name: 'Label 1', id: 1 },
|
||||||
{ name: 'Label 2', id: 2 },
|
{ name: 'Label 2', id: 2 },
|
||||||
]);
|
]);
|
||||||
@@ -148,13 +171,16 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
|
|
||||||
test('webhooks and enable concurrent jobs functions properly', async () => {
|
test('webhooks and enable concurrent jobs functions properly', async () => {
|
||||||
act(() => {
|
act(() => {
|
||||||
wrapper.find('Checkbox[aria-label="Webhooks"]').invoke('onChange')(true, {
|
wrapper.find('Checkbox[aria-label="Enable Webhook"]').invoke('onChange')(
|
||||||
currentTarget: { value: true, type: 'change', checked: true },
|
true,
|
||||||
});
|
{
|
||||||
|
currentTarget: { value: true, type: 'change', checked: true },
|
||||||
|
}
|
||||||
|
);
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('Checkbox[aria-label="Webhooks"]').prop('isChecked')
|
wrapper.find('Checkbox[aria-label="Enable Webhook"]').prop('isChecked')
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
@@ -171,7 +197,7 @@ describe('<WorkflowJobTemplateForm/>', () => {
|
|||||||
);
|
);
|
||||||
expect(WorkflowJobTemplatesAPI.updateWebhookKey).toBeCalledWith('6');
|
expect(WorkflowJobTemplatesAPI.updateWebhookKey).toBeCalledWith('6');
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('TextInputBase[name="webhook_url"]').prop('value')
|
wrapper.find('TextInputBase[aria-label="Webhook URL"]').prop('value')
|
||||||
).toContain('/api/v2/workflow_job_templates/57/gitlab/');
|
).toContain('/api/v2/workflow_job_templates/57/gitlab/');
|
||||||
|
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|||||||
Reference in New Issue
Block a user