mirror of
https://github.com/ansible/awx.git
synced 2026-05-11 19:37:38 -02:30
Hook up Test button on Metadata step in credential plugin wizard
This commit is contained in:
@@ -13,6 +13,8 @@ import CredentialPluginPrompt from './CredentialPluginPrompt';
|
|||||||
jest.mock('../../../../../../api/models/Credentials');
|
jest.mock('../../../../../../api/models/Credentials');
|
||||||
jest.mock('../../../../../../api/models/CredentialTypes');
|
jest.mock('../../../../../../api/models/CredentialTypes');
|
||||||
|
|
||||||
|
CredentialsAPI.test.mockResolvedValue({});
|
||||||
|
|
||||||
CredentialsAPI.read.mockResolvedValue({
|
CredentialsAPI.read.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
count: 3,
|
count: 3,
|
||||||
@@ -234,5 +236,13 @@ describe('<CredentialPluginPrompt />', () => {
|
|||||||
wrapper.find('input#credential-secret_version').prop('value')
|
wrapper.find('input#credential-secret_version').prop('value')
|
||||||
).toBe('9000');
|
).toBe('9000');
|
||||||
});
|
});
|
||||||
|
test('clicking Test button makes correct call', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('Button#credential-plugin-test').simulate('click');
|
||||||
|
});
|
||||||
|
expect(CredentialsAPI.test).toHaveBeenCalledWith(1, {
|
||||||
|
metadata: { secret_path: '/foo/bar', secret_version: '9000' },
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import FormField from '../../../../../../components/FormField';
|
|||||||
import { FormFullWidthLayout } from '../../../../../../components/FormLayout';
|
import { FormFullWidthLayout } from '../../../../../../components/FormLayout';
|
||||||
import useRequest from '../../../../../../util/useRequest';
|
import useRequest from '../../../../../../util/useRequest';
|
||||||
import { required } from '../../../../../../util/validators';
|
import { required } from '../../../../../../util/validators';
|
||||||
|
import { CredentialPluginTestAlert } from '..';
|
||||||
|
|
||||||
const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
|
const QuestionCircleIcon = styled(PFQuestionCircleIcon)`
|
||||||
margin-left: 10px;
|
margin-left: 10px;
|
||||||
@@ -27,6 +28,21 @@ function MetadataStep({ i18n }) {
|
|||||||
const [selectedCredential] = useField('credential');
|
const [selectedCredential] = useField('credential');
|
||||||
const [inputValues] = useField('inputs');
|
const [inputValues] = useField('inputs');
|
||||||
|
|
||||||
|
const {
|
||||||
|
result: testPluginSuccess,
|
||||||
|
error: testPluginError,
|
||||||
|
request: testPluginMetadata,
|
||||||
|
} = useRequest(
|
||||||
|
useCallback(
|
||||||
|
async (credential, metadata) =>
|
||||||
|
CredentialsAPI.test(credential.id, {
|
||||||
|
metadata,
|
||||||
|
}),
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
null
|
||||||
|
);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
result: fields,
|
result: fields,
|
||||||
error,
|
error,
|
||||||
@@ -65,10 +81,6 @@ function MetadataStep({ i18n }) {
|
|||||||
fetchMetadataOptions();
|
fetchMetadataOptions();
|
||||||
}, [fetchMetadataOptions]);
|
}, [fetchMetadataOptions]);
|
||||||
|
|
||||||
const testMetadata = () => {
|
|
||||||
// https://github.com/ansible/awx/issues/7126
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
return <ContentLoading />;
|
return <ContentLoading />;
|
||||||
}
|
}
|
||||||
@@ -143,13 +155,21 @@ function MetadataStep({ i18n }) {
|
|||||||
position="right"
|
position="right"
|
||||||
>
|
>
|
||||||
<TestButton
|
<TestButton
|
||||||
|
id="credential-plugin-test"
|
||||||
variant="primary"
|
variant="primary"
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={() => testMetadata()}
|
onClick={() =>
|
||||||
|
testPluginMetadata(selectedCredential.value, inputValues.value)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
{i18n._(t`Test`)}
|
{i18n._(t`Test`)}
|
||||||
</TestButton>
|
</TestButton>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
<CredentialPluginTestAlert
|
||||||
|
credentialName={selectedCredential.value.name}
|
||||||
|
successResponse={testPluginSuccess}
|
||||||
|
errorResponse={testPluginError}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,82 @@
|
|||||||
|
import React, { useEffect, useState } from 'react';
|
||||||
|
import { withI18n } from '@lingui/react';
|
||||||
|
import { t } from '@lingui/macro';
|
||||||
|
import {
|
||||||
|
Alert,
|
||||||
|
AlertActionCloseButton,
|
||||||
|
AlertGroup,
|
||||||
|
} from '@patternfly/react-core';
|
||||||
|
|
||||||
|
function CredentialPluginTestAlert({
|
||||||
|
i18n,
|
||||||
|
credentialName,
|
||||||
|
successResponse,
|
||||||
|
errorResponse,
|
||||||
|
}) {
|
||||||
|
const [testMessage, setTestMessage] = useState('');
|
||||||
|
const [testVariant, setTestVariant] = useState(false);
|
||||||
|
useEffect(() => {
|
||||||
|
if (errorResponse) {
|
||||||
|
if (errorResponse?.response?.data?.inputs) {
|
||||||
|
if (errorResponse.response.data.inputs.startsWith('HTTP')) {
|
||||||
|
const [
|
||||||
|
errorCode,
|
||||||
|
errorStr,
|
||||||
|
] = errorResponse.response.data.inputs.split('\n');
|
||||||
|
try {
|
||||||
|
const errorJSON = JSON.parse(errorStr);
|
||||||
|
setTestMessage(
|
||||||
|
`${errorCode}${
|
||||||
|
errorJSON?.errors[0] ? `: ${errorJSON.errors[0]}` : ''
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
setTestMessage(errorResponse.response.data.inputs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTestMessage(errorResponse.response.data.inputs);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
setTestMessage(
|
||||||
|
i18n._(
|
||||||
|
t`Something went wrong with the request to test this credential and metadata.`
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
setTestVariant('danger');
|
||||||
|
} else if (successResponse) {
|
||||||
|
setTestMessage(i18n._(t`Test passed`));
|
||||||
|
setTestVariant('success');
|
||||||
|
}
|
||||||
|
}, [i18n, successResponse, errorResponse]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<AlertGroup isToast>
|
||||||
|
{testMessage && testVariant && (
|
||||||
|
<Alert
|
||||||
|
title={
|
||||||
|
<>
|
||||||
|
<b id="credential-plugin-test-name">{credentialName}</b>
|
||||||
|
<p id="credential-plugin-test-message">{testMessage}</p>
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
variant={testVariant}
|
||||||
|
action={
|
||||||
|
<AlertActionCloseButton
|
||||||
|
onClose={() => {
|
||||||
|
setTestMessage(null);
|
||||||
|
setTestVariant(null);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</AlertGroup>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
CredentialPluginTestAlert.propTypes = {};
|
||||||
|
|
||||||
|
CredentialPluginTestAlert.defaultProps = {};
|
||||||
|
|
||||||
|
export default withI18n()(CredentialPluginTestAlert);
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers';
|
||||||
|
import CredentialPluginTestAlert from './CredentialPluginTestAlert';
|
||||||
|
|
||||||
|
describe('<CredentialPluginTestAlert />', () => {
|
||||||
|
let wrapper;
|
||||||
|
afterEach(() => {
|
||||||
|
wrapper.unmount();
|
||||||
|
});
|
||||||
|
test('renders expected content when test is successful', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<CredentialPluginTestAlert
|
||||||
|
credentialName="Foobar"
|
||||||
|
successResponse={{}}
|
||||||
|
errorResponse={null}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('b#credential-plugin-test-name').text()).toBe('Foobar');
|
||||||
|
expect(wrapper.find('p#credential-plugin-test-message').text()).toBe(
|
||||||
|
'Test passed'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test('renders expected content when test fails with the expected return string formatting', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<CredentialPluginTestAlert
|
||||||
|
credentialName="Foobar"
|
||||||
|
successResponse={null}
|
||||||
|
errorResponse={{
|
||||||
|
response: {
|
||||||
|
data: {
|
||||||
|
inputs: `HTTP 404
|
||||||
|
{"errors":["not found"]}
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('b#credential-plugin-test-name').text()).toBe('Foobar');
|
||||||
|
expect(wrapper.find('p#credential-plugin-test-message').text()).toBe(
|
||||||
|
'HTTP 404: not found'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
test('renders expected content when test fails without the expected return string formatting', () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<CredentialPluginTestAlert
|
||||||
|
credentialName="Foobar"
|
||||||
|
successResponse={null}
|
||||||
|
errorResponse={{
|
||||||
|
response: {
|
||||||
|
data: {
|
||||||
|
inputs: 'usernamee is not present at /secret/foo/bar/baz',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
expect(wrapper.find('b#credential-plugin-test-name').text()).toBe('Foobar');
|
||||||
|
expect(wrapper.find('p#credential-plugin-test-message').text()).toBe(
|
||||||
|
'usernamee is not present at /secret/foo/bar/baz'
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -39,6 +39,7 @@ export default function useRequest(makeRequest, initialValue) {
|
|||||||
async (...args) => {
|
async (...args) => {
|
||||||
setIsLoading(true);
|
setIsLoading(true);
|
||||||
if (isMounted.current) {
|
if (isMounted.current) {
|
||||||
|
setResult(initialValue);
|
||||||
setError(null);
|
setError(null);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
@@ -56,6 +57,7 @@ export default function useRequest(makeRequest, initialValue) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/* eslint-disable-next-line react-hooks/exhaustive-deps */
|
||||||
[makeRequest]
|
[makeRequest]
|
||||||
),
|
),
|
||||||
setValue: setResult,
|
setValue: setResult,
|
||||||
|
|||||||
@@ -96,6 +96,37 @@ describe('useRequest hooks', () => {
|
|||||||
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
|
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should reset error/result on each request', async () => {
|
||||||
|
const error = new Error('error');
|
||||||
|
const makeRequest = throwError => {
|
||||||
|
if (throwError) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
|
||||||
|
return { data: 'foo' };
|
||||||
|
};
|
||||||
|
const wrapper = mount(<Test makeRequest={makeRequest} />);
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('TestInner').invoke('request')(true);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('TestInner').prop('result')).toEqual({});
|
||||||
|
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('TestInner').invoke('request')();
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('TestInner').prop('result')).toEqual({ data: 'foo' });
|
||||||
|
expect(wrapper.find('TestInner').prop('error')).toEqual(null);
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('TestInner').invoke('request')(true);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(wrapper.find('TestInner').prop('result')).toEqual({});
|
||||||
|
expect(wrapper.find('TestInner').prop('error')).toEqual(error);
|
||||||
|
});
|
||||||
|
|
||||||
test('should not update state after unmount', async () => {
|
test('should not update state after unmount', async () => {
|
||||||
const makeRequest = jest.fn();
|
const makeRequest = jest.fn();
|
||||||
let resolve;
|
let resolve;
|
||||||
|
|||||||
Reference in New Issue
Block a user