mirror of
https://github.com/ansible/awx.git
synced 2026-01-11 10:00:01 -03:30
adds test for new webhook component
This commit is contained in:
parent
6e648cf72f
commit
222fecc5f6
@ -45,7 +45,7 @@ function Template({ i18n, me, setBreadcrumb }) {
|
||||
role_level: 'notification_admin_role',
|
||||
}),
|
||||
]);
|
||||
if (data?.related?.webhook_key) {
|
||||
if (data.webhook_service && data?.related?.webhook_key) {
|
||||
const {
|
||||
data: { webhook_key },
|
||||
} = await JobTemplatesAPI.readWebhookKey(templateId);
|
||||
|
||||
@ -40,7 +40,7 @@ import {
|
||||
import { JobTemplatesAPI, ProjectsAPI } from '@api';
|
||||
import LabelSelect from './LabelSelect';
|
||||
import PlaybookSelect from './PlaybookSelect';
|
||||
import WebhookSubForm from './WebhooksSubForm';
|
||||
import WebhookSubForm from './WebhookSubForm';
|
||||
|
||||
const { origin } = document.location;
|
||||
|
||||
@ -94,10 +94,6 @@ function JobTemplateForm({
|
||||
);
|
||||
const [jobTagsField, , jobTagsHelpers] = useField('job_tags');
|
||||
const [skipTagsField, , skipTagsHelpers] = useField('skip_tags');
|
||||
const webhookService = useField('webhook_service');
|
||||
const webhookUrl = useField('webhook_url');
|
||||
const webhookKey = useField('webhook_key');
|
||||
const webhookCredential = useField('webhook_credential');
|
||||
|
||||
const {
|
||||
request: fetchProject,
|
||||
@ -189,19 +185,11 @@ function JobTemplateForm({
|
||||
callbackUrl = `${origin}${path}`;
|
||||
}
|
||||
|
||||
if (
|
||||
instanceGroupLoading ||
|
||||
hasProjectLoading
|
||||
// credentialContentLoading
|
||||
) {
|
||||
if (instanceGroupLoading || hasProjectLoading) {
|
||||
return <ContentLoading />;
|
||||
}
|
||||
|
||||
if (
|
||||
instanceGroupError ||
|
||||
projectContentError
|
||||
// credentialContentError
|
||||
) {
|
||||
if (instanceGroupError || projectContentError) {
|
||||
return <ContentError error={contentError} />;
|
||||
}
|
||||
|
||||
@ -530,23 +518,9 @@ function JobTemplateForm({
|
||||
</span>
|
||||
}
|
||||
id="wfjt-enabled-webhooks"
|
||||
isChecked={
|
||||
Boolean(webhookService[0].value) || enableWebhooks
|
||||
}
|
||||
isChecked={enableWebhooks}
|
||||
onChange={checked => {
|
||||
setEnableWebhooks(checked);
|
||||
webhookService[2].setValue(
|
||||
!checked ? '' : webhookService[1].initialValue
|
||||
);
|
||||
webhookUrl[2].setValue(
|
||||
!checked ? '' : webhookUrl[1].initialValue
|
||||
);
|
||||
webhookKey[2].setValue(
|
||||
!checked ? '' : webhookKey[1].initialValue
|
||||
);
|
||||
webhookCredential[2].setValue(
|
||||
!checked ? null : webhookCredential[1].initialValue
|
||||
);
|
||||
}}
|
||||
/>
|
||||
<CheckboxField
|
||||
@ -624,7 +598,7 @@ JobTemplateForm.defaultProps = {
|
||||
};
|
||||
|
||||
const FormikApp = withFormik({
|
||||
mapPropsToValues({ template = {} }) {
|
||||
mapPropsToValues({ template = {}, i18n }) {
|
||||
const {
|
||||
summary_fields = {
|
||||
labels: { results: [] },
|
||||
@ -671,8 +645,10 @@ const FormikApp = withFormik({
|
||||
webhook_service: template.webhook_service || '',
|
||||
webhook_url: template?.related?.webhook_receiver
|
||||
? `${origin}${template.related.webhook_receiver}`
|
||||
: '',
|
||||
webhook_key: template.webhook_key || '',
|
||||
: i18n._(t`a new webhook url will be generated on save.`).toUpperCase(),
|
||||
webhook_key:
|
||||
template.webhook_key ||
|
||||
i18n._(t`a new webhook key will be generated on save.`).toUpperCase(),
|
||||
webhook_credential: template?.summary_fields?.webhook_credential || null,
|
||||
};
|
||||
},
|
||||
|
||||
@ -292,6 +292,49 @@ describe('<JobTemplateForm />', () => {
|
||||
);
|
||||
});
|
||||
|
||||
test('webhooks should render properly, without data', async () => {
|
||||
let wrapper;
|
||||
const history = createMemoryHistory({
|
||||
initialEntries: ['/templates/job_template/1/edit'],
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<Route
|
||||
path="/templates/job_template/:id/edit"
|
||||
component={() => (
|
||||
<JobTemplateForm
|
||||
template={{
|
||||
...mockData,
|
||||
webhook_credential: null,
|
||||
webhook_key: '',
|
||||
webhook_service: 'github',
|
||||
related: { webhook_receiver: '' },
|
||||
}}
|
||||
handleSubmit={jest.fn()}
|
||||
handleCancel={jest.fn()}
|
||||
/>
|
||||
)}
|
||||
/>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: history.location,
|
||||
match: { params: { id: 1 } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
expect(
|
||||
wrapper.find('TextInputBase#template-webhook_key').prop('value')
|
||||
).toBe('A NEW WEBHOOK KEY WILL BE GENERATED ON SAVE.');
|
||||
expect(
|
||||
wrapper.find('Button[aria-label="Update webhook key"]').prop('isDisabled')
|
||||
).toBe(true);
|
||||
});
|
||||
test('should call handleSubmit when Submit button is clicked', async () => {
|
||||
const handleSubmit = jest.fn();
|
||||
let wrapper;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useCallback, useState } from 'react';
|
||||
import React, { useEffect, useCallback } from 'react';
|
||||
import { SyncAltIcon } from '@patternfly/react-icons';
|
||||
import { useParams, useRouteMatch } from 'react-router-dom';
|
||||
import { useParams, useLocation } from 'react-router-dom';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import {
|
||||
@ -20,9 +20,8 @@ import { FieldTooltip } from '@components/FormField';
|
||||
import { JobTemplatesAPI, CredentialTypesAPI } from '@api';
|
||||
|
||||
function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
const [contentError, setContentError] = useState(null);
|
||||
const jtAddMatch = useRouteMatch('/templates/job_template/add');
|
||||
const { id } = useParams();
|
||||
const { id, templateType } = useParams();
|
||||
const { pathname } = useLocation();
|
||||
|
||||
const { origin } = document.location;
|
||||
|
||||
@ -32,7 +31,9 @@ function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
webhookServiceHelpers,
|
||||
] = useField('webhook_service');
|
||||
|
||||
const [webhookUrlField, , webhookUrlHelpers] = useField('webhook_url');
|
||||
const [webhookUrlField, webhookUrlMeta, webhookUrlHelpers] = useField(
|
||||
'webhook_url'
|
||||
);
|
||||
const [webhookKeyField, webhookKeyMeta, webhookKeyHelpers] = useField(
|
||||
'webhook_key'
|
||||
);
|
||||
@ -65,17 +66,37 @@ function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
loadCredentialType();
|
||||
}, [loadCredentialType]);
|
||||
|
||||
const changeWebhookKey = async () => {
|
||||
try {
|
||||
useEffect(() => {
|
||||
if (enableWebhooks) {
|
||||
webhookServiceHelpers.setValue(webhookServiceMeta.initialValue);
|
||||
webhookUrlHelpers.setValue(webhookUrlMeta.initialValue);
|
||||
webhookKeyHelpers.setValue(webhookKeyMeta.initialValue);
|
||||
webhookCredentialHelpers.setValue(webhookCredentialMeta.initialValue);
|
||||
} else {
|
||||
webhookServiceHelpers.setValue('');
|
||||
webhookUrlHelpers.setValue('');
|
||||
webhookKeyHelpers.setValue('');
|
||||
webhookCredentialHelpers.setValue(null);
|
||||
}
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [enableWebhooks]);
|
||||
|
||||
const { request: fetchWebhookKey, error: webhookKeyError } = useRequest(
|
||||
useCallback(async () => {
|
||||
const {
|
||||
data: { webhook_key: key },
|
||||
} = await JobTemplatesAPI.updateWebhookKey(id);
|
||||
webhookKeyHelpers.setValue(key);
|
||||
} catch (err) {
|
||||
setContentError(err);
|
||||
}
|
||||
};
|
||||
}, [webhookKeyHelpers, id])
|
||||
);
|
||||
|
||||
const changeWebhookKey = async () => {
|
||||
await fetchWebhookKey();
|
||||
};
|
||||
const isUpdateKeyDisabled =
|
||||
pathname.endsWith('/add') ||
|
||||
webhookKeyMeta.initialValue ===
|
||||
'A NEW WEBHOOK KEY WILL BE GENERATED ON SAVE.';
|
||||
const webhookServiceOptions = [
|
||||
{
|
||||
value: '',
|
||||
@ -97,7 +118,7 @@ function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
},
|
||||
];
|
||||
|
||||
if (error || contentError) {
|
||||
if (error || webhookKeyError) {
|
||||
return <ContentError error={error} />;
|
||||
}
|
||||
if (isLoading) {
|
||||
@ -120,7 +141,11 @@ function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
onChange={(event, val) => {
|
||||
webhookServiceHelpers.setValue(val);
|
||||
webhookUrlHelpers.setValue(
|
||||
`${origin}/api/v2/job_templates/${id}/${val}/`
|
||||
pathname.endsWith('/add')
|
||||
? i18n
|
||||
._(t`a new webhook url will be generated on save.`)
|
||||
.toUpperCase()
|
||||
: `${origin}/api/v2/${templateType}s/${id}/${val}/`
|
||||
);
|
||||
if (val === webhookServiceMeta.initialValue || val === '') {
|
||||
webhookKeyHelpers.setValue(webhookKeyMeta.initialValue);
|
||||
@ -138,53 +163,53 @@ function WebhookSubForm({ i18n, enableWebhooks }) {
|
||||
}}
|
||||
/>
|
||||
</FormGroup>
|
||||
{!jtAddMatch && (
|
||||
<>
|
||||
<FormGroup
|
||||
type="text"
|
||||
fieldId="jt-webhookURL"
|
||||
label={i18n._(t`Webhook URL`)}
|
||||
name="webhook_url"
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(
|
||||
t`Webhook services can launch jobs with this workflow job template by making a POST request to this URL.`
|
||||
)}
|
||||
/>
|
||||
<>
|
||||
<FormGroup
|
||||
type="text"
|
||||
fieldId="jt-webhookURL"
|
||||
label={i18n._(t`Webhook URL`)}
|
||||
name="webhook_url"
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(
|
||||
t`Webhook services can launch jobs with this workflow job template by making a POST request to this URL.`
|
||||
)}
|
||||
/>
|
||||
<TextInput
|
||||
id="t-webhookURL"
|
||||
aria-label={i18n._(t`Webhook URL`)}
|
||||
value={webhookUrlField.value}
|
||||
isReadOnly
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={i18n._(t`Webhook Key`)}
|
||||
fieldId="template-webhook_key"
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(
|
||||
t`Webhook services can use this as a shared secret.`
|
||||
)}
|
||||
/>
|
||||
<InputGroup>
|
||||
<TextInput
|
||||
id="t-webhookURL"
|
||||
aria-label={i18n._(t`Webhook URL`)}
|
||||
value={webhookUrlField.value}
|
||||
id="template-webhook_key"
|
||||
isReadOnly
|
||||
aria-label="wfjt-webhook-key"
|
||||
value={webhookKeyField.value}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormGroup
|
||||
label={i18n._(t`Webhook Key`)}
|
||||
fieldId="template-webhook_key"
|
||||
>
|
||||
<FieldTooltip
|
||||
content={i18n._(
|
||||
t`Webhook services can use this as a shared secret.`
|
||||
)}
|
||||
/>
|
||||
<InputGroup>
|
||||
<TextInput
|
||||
id="template-webhook_key"
|
||||
isReadOnly
|
||||
aria-label="wfjt-webhook-key"
|
||||
value={webhookKeyField.value}
|
||||
/>
|
||||
<Button
|
||||
variant="tertiary"
|
||||
aria-label={i18n._(t`Update webhook key`)}
|
||||
onClick={changeWebhookKey}
|
||||
>
|
||||
<SyncAltIcon />
|
||||
</Button>
|
||||
</InputGroup>
|
||||
</FormGroup>
|
||||
</>
|
||||
)}
|
||||
<Button
|
||||
isDisabled={isUpdateKeyDisabled}
|
||||
variant="tertiary"
|
||||
aria-label={i18n._(t`Update webhook key`)}
|
||||
onClick={changeWebhookKey}
|
||||
>
|
||||
<SyncAltIcon />
|
||||
</Button>
|
||||
</InputGroup>
|
||||
</FormGroup>
|
||||
</>
|
||||
|
||||
{credTypeId && (
|
||||
<CredentialLookup
|
||||
label={i18n._(t`Webhook Credential`)}
|
||||
124
awx/ui_next/src/screens/Template/shared/WebhookSubForm.test.jsx
Normal file
124
awx/ui_next/src/screens/Template/shared/WebhookSubForm.test.jsx
Normal file
@ -0,0 +1,124 @@
|
||||
import React from 'react';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { Route } from 'react-router-dom';
|
||||
import { createMemoryHistory } from 'history';
|
||||
|
||||
import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers';
|
||||
import { CredentialsAPI } from '@api';
|
||||
import { Formik } from 'formik';
|
||||
|
||||
import WebhookSubForm from './WebhookSubForm';
|
||||
|
||||
jest.mock('@api');
|
||||
|
||||
describe('<WebhooksSubForm />', () => {
|
||||
let wrapper;
|
||||
let history;
|
||||
const initialValues = {
|
||||
webhook_url: '/api/v2/job_templates/51/github/',
|
||||
webhook_credential: { id: 1, name: 'Github credential' },
|
||||
webhook_service: 'github',
|
||||
webhook_key: 'webhook key',
|
||||
};
|
||||
beforeEach(async () => {
|
||||
history = createMemoryHistory({
|
||||
initialEntries: ['templates/job_template/51/edit'],
|
||||
});
|
||||
CredentialsAPI.read.mockResolvedValue({
|
||||
data: { results: [{ id: 12, name: 'Github credential' }] },
|
||||
});
|
||||
await act(async () => {
|
||||
wrapper = mountWithContexts(
|
||||
<Route path="templates/:templateType/:id/edit">
|
||||
<Formik initialValues={initialValues}>
|
||||
<WebhookSubForm enableWebhooks />
|
||||
</Formik>
|
||||
</Route>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: { pathname: 'templates/job_template/51/edit' },
|
||||
match: { params: { id: 51, templateType: 'job_template' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
test('mounts properly', () => {
|
||||
expect(wrapper.length).toBe(1);
|
||||
});
|
||||
test('should render initial values properly', () => {
|
||||
waitForElement(wrapper, 'Lookup__ChipHolder', el => el.lenth > 0);
|
||||
expect(wrapper.find('AnsibleSelect').prop('value')).toBe('github');
|
||||
expect(
|
||||
wrapper.find('TextInputBase[aria-label="Webhook URL"]').prop('value')
|
||||
).toContain('/api/v2/job_templates/51/github/');
|
||||
expect(
|
||||
wrapper.find('TextInputBase[aria-label="wfjt-webhook-key"]').prop('value')
|
||||
).toBe('webhook key');
|
||||
expect(
|
||||
wrapper
|
||||
.find('Chip')
|
||||
.find('span')
|
||||
.text()
|
||||
).toBe('Github credential');
|
||||
});
|
||||
test('should make other credential type available', async () => {
|
||||
CredentialsAPI.read.mockResolvedValue({
|
||||
data: { results: [{ id: 13, name: 'GitLab credential' }] },
|
||||
});
|
||||
await act(async () =>
|
||||
wrapper.find('AnsibleSelect').prop('onChange')({}, 'gitlab')
|
||||
);
|
||||
expect(CredentialsAPI.read).toHaveBeenCalledWith({
|
||||
namespace: 'gitlab_token',
|
||||
});
|
||||
wrapper.update();
|
||||
expect(
|
||||
wrapper.find('TextInputBase[aria-label="Webhook URL"]').prop('value')
|
||||
).toContain('/api/v2/job_templates/51/gitlab/');
|
||||
expect(
|
||||
wrapper.find('TextInputBase[aria-label="wfjt-webhook-key"]').prop('value')
|
||||
).toBe('A NEW WEBHOOK KEY WILL BE GENERATED ON SAVE.');
|
||||
});
|
||||
test('should have disabled button to update webhook key', async () => {
|
||||
let newWrapper;
|
||||
await act(async () => {
|
||||
newWrapper = mountWithContexts(
|
||||
<Route path="templates/:templateType/:id/edit">
|
||||
<Formik
|
||||
initialValues={{
|
||||
...initialValues,
|
||||
webhook_key: 'A NEW WEBHOOK KEY WILL BE GENERATED ON SAVE.',
|
||||
}}
|
||||
>
|
||||
<WebhookSubForm enableWebhooks />
|
||||
</Formik>
|
||||
</Route>,
|
||||
{
|
||||
context: {
|
||||
router: {
|
||||
history,
|
||||
route: {
|
||||
location: { pathname: 'templates/job_template/51/edit' },
|
||||
match: { params: { id: 51, templateType: 'job_template' } },
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
});
|
||||
expect(
|
||||
newWrapper
|
||||
.find("Button[aria-label='Update webhook key']")
|
||||
.prop('isDisabled')
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user