From df069f3874f2cca0718d44799ec1ccf0144f744f Mon Sep 17 00:00:00 2001 From: mabashian Date: Tue, 26 May 2020 08:50:50 -0400 Subject: [PATCH] Adds prop type checking to a few components that were missing it. Adds basic test coverage for credential plugin field and selected components. Adds foundation for credential plugin prompt component tests (more coverage to come in a later commit). --- .../FormField/PasswordField.test.jsx | 23 ----- .../FormField/PasswordInput.test.jsx | 44 ++++++++++ .../CredentialPluginField.test.jsx | 85 +++++++++++++++++++ .../CredentialPluginPrompt.jsx | 6 +- .../CredentialPluginPrompt.test.jsx | 18 ++++ .../CredentialPluginSelected.jsx | 13 +++ .../CredentialPluginSelected.test.jsx | 34 ++++++++ .../shared/data.cyberArkCredential.json | 85 +++++++++++++++++++ 8 files changed, 284 insertions(+), 24 deletions(-) create mode 100644 awx/ui_next/src/components/FormField/PasswordInput.test.jsx create mode 100644 awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginField.test.jsx create mode 100644 awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.test.jsx create mode 100644 awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.test.jsx create mode 100644 awx/ui_next/src/screens/Credential/shared/data.cyberArkCredential.json diff --git a/awx/ui_next/src/components/FormField/PasswordField.test.jsx b/awx/ui_next/src/components/FormField/PasswordField.test.jsx index 2f2ceab52a..e2b40dbd09 100644 --- a/awx/ui_next/src/components/FormField/PasswordField.test.jsx +++ b/awx/ui_next/src/components/FormField/PasswordField.test.jsx @@ -1,7 +1,6 @@ import React from 'react'; import { Formik } from 'formik'; import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; -import { sleep } from '../../../testUtils/testUtils'; import PasswordField from './PasswordField'; describe('PasswordField', () => { @@ -19,26 +18,4 @@ describe('PasswordField', () => { ); expect(wrapper).toHaveLength(1); }); - - test('properly responds to show/hide toggles', async () => { - const wrapper = mountWithContexts( - - {() => ( - - )} - - ); - expect(wrapper.find('input').prop('type')).toBe('password'); - expect(wrapper.find('EyeSlashIcon').length).toBe(1); - expect(wrapper.find('EyeIcon').length).toBe(0); - wrapper.find('button').simulate('click'); - await sleep(1); - expect(wrapper.find('input').prop('type')).toBe('text'); - expect(wrapper.find('EyeSlashIcon').length).toBe(0); - expect(wrapper.find('EyeIcon').length).toBe(1); - }); }); diff --git a/awx/ui_next/src/components/FormField/PasswordInput.test.jsx b/awx/ui_next/src/components/FormField/PasswordInput.test.jsx new file mode 100644 index 0000000000..374ba1a6e8 --- /dev/null +++ b/awx/ui_next/src/components/FormField/PasswordInput.test.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import { Formik } from 'formik'; +import { mountWithContexts } from '../../../testUtils/enzymeHelpers'; +import { sleep } from '../../../testUtils/testUtils'; +import PasswordInput from './PasswordInput'; + +describe('PasswordInput', () => { + test('renders the expected content', () => { + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + expect(wrapper).toHaveLength(1); + }); + + test('properly responds to show/hide toggles', async () => { + const wrapper = mountWithContexts( + + {() => ( + + )} + + ); + expect(wrapper.find('input').prop('type')).toBe('password'); + expect(wrapper.find('EyeSlashIcon').length).toBe(1); + expect(wrapper.find('EyeIcon').length).toBe(0); + wrapper.find('button').simulate('click'); + await sleep(1); + expect(wrapper.find('input').prop('type')).toBe('text'); + expect(wrapper.find('EyeSlashIcon').length).toBe(0); + expect(wrapper.find('EyeIcon').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginField.test.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginField.test.jsx new file mode 100644 index 0000000000..39f77b63b4 --- /dev/null +++ b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginField.test.jsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { Formik } from 'formik'; +import { TextInput } from '@patternfly/react-core'; +import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers'; +import CredentialPluginField from './CredentialPluginField'; + +describe('', () => { + let wrapper; + describe('No plugin configured', () => { + beforeAll(() => { + wrapper = mountWithContexts( + + {() => ( + + + + )} + + ); + }); + afterAll(() => { + wrapper.unmount(); + }); + test('renders the expected content', () => { + expect(wrapper.find('input').length).toBe(1); + expect(wrapper.find('KeyIcon').length).toBe(1); + expect(wrapper.find('CredentialPluginSelected').length).toBe(0); + }); + test('clicking plugin button shows plugin prompt', () => { + expect(wrapper.find('CredentialPluginPrompt').length).toBe(0); + wrapper.find('KeyIcon').simulate('click'); + expect(wrapper.find('CredentialPluginPrompt').length).toBe(1); + }); + }); + describe('Plugin already configured', () => { + beforeAll(() => { + wrapper = mountWithContexts( + + {() => ( + + + + )} + + ); + }); + afterAll(() => { + wrapper.unmount(); + }); + test('renders the expected content', () => { + expect(wrapper.find('CredentialPluginPrompt').length).toBe(0); + expect(wrapper.find('input').length).toBe(0); + expect(wrapper.find('KeyIcon').length).toBe(1); + expect(wrapper.find('CredentialPluginSelected').length).toBe(1); + }); + }); +}); diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.jsx index c2cd65f212..d8a66e8426 100644 --- a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.jsx +++ b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { func } from 'prop-types'; import { Formik, useField } from 'formik'; import { withI18n } from '@lingui/react'; import { t } from '@lingui/macro'; @@ -54,7 +55,10 @@ function CredentialPluginPrompt({ i18n, onClose, onSubmit, initialValues }) { ); } -CredentialPluginPrompt.propTypes = {}; +CredentialPluginPrompt.propTypes = { + onClose: func.isRequired, + onSubmit: func.isRequired, +}; CredentialPluginPrompt.defaultProps = {}; diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.test.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.test.jsx new file mode 100644 index 0000000000..095e203f38 --- /dev/null +++ b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginPrompt/CredentialPluginPrompt.test.jsx @@ -0,0 +1,18 @@ +import React from 'react'; +import { mountWithContexts } from '../../../../../../testUtils/enzymeHelpers'; +import CredentialPluginPrompt from './CredentialPluginPrompt'; + +describe('', () => { + let wrapper; + beforeAll(() => { + wrapper = mountWithContexts( + + ); + }); + afterAll(() => { + wrapper.unmount(); + }); + test('renders the expected content', () => { + expect(wrapper).toHaveLength(1); + }); +}); diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.jsx index 2ea3ca84d0..a7d408d49f 100644 --- a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.jsx +++ b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.jsx @@ -1,10 +1,12 @@ import React from 'react'; +import { func } from 'prop-types'; import { withI18n } from '@lingui/react'; import { t, Trans } from '@lingui/macro'; import styled from 'styled-components'; import { Button, ButtonVariant, Tooltip } from '@patternfly/react-core'; import { KeyIcon } from '@patternfly/react-icons'; import CredentialChip from '../../../../components/CredentialChip'; +import { Credential } from '../../../../types'; const SelectedCredential = styled.div` display: flex; @@ -51,4 +53,15 @@ function CredentialPluginSelected({ ); } +CredentialPluginSelected.propTypes = { + credential: Credential.isRequired, + onEditPlugin: func, + onClearPlugin: func, +}; + +CredentialPluginSelected.defaultProps = { + onEditPlugin: () => {}, + onClearPlugin: () => {}, +}; + export default withI18n()(CredentialPluginSelected); diff --git a/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.test.jsx b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.test.jsx new file mode 100644 index 0000000000..ce69724904 --- /dev/null +++ b/awx/ui_next/src/screens/Credential/shared/CredentialPlugins/CredentialPluginSelected.test.jsx @@ -0,0 +1,34 @@ +import React from 'react'; +import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers'; +import selectedCredential from '../data.cyberArkCredential.json'; +import CredentialPluginSelected from './CredentialPluginSelected'; + +describe('', () => { + let wrapper; + const onClearPlugin = jest.fn(); + const onEditPlugin = jest.fn(); + beforeAll(() => { + wrapper = mountWithContexts( + + ); + }); + afterAll(() => { + wrapper.unmount(); + }); + test('renders the expected content', () => { + expect(wrapper.find('CredentialChip').length).toBe(1); + expect(wrapper.find('KeyIcon').length).toBe(1); + }); + test('clearing plugin calls expected function', () => { + wrapper.find('CredentialChip button').simulate('click'); + expect(onClearPlugin).toBeCalledTimes(1); + }); + test('editing plugin calls expected function', () => { + wrapper.find('KeyIcon').simulate('click'); + expect(onEditPlugin).toBeCalledTimes(1); + }); +}); diff --git a/awx/ui_next/src/screens/Credential/shared/data.cyberArkCredential.json b/awx/ui_next/src/screens/Credential/shared/data.cyberArkCredential.json new file mode 100644 index 0000000000..94b0bbd8fd --- /dev/null +++ b/awx/ui_next/src/screens/Credential/shared/data.cyberArkCredential.json @@ -0,0 +1,85 @@ +{ + "id": 1, + "type": "credential", + "url": "/api/v2/credentials/1/", + "related": { + "named_url": "/api/v2/credentials/CyberArk Conjur Secret Lookup++CyberArk Conjur Secret Lookup+external++/", + "created_by": "/api/v2/users/1/", + "modified_by": "/api/v2/users/1/", + "activity_stream": "/api/v2/credentials/1/activity_stream/", + "access_list": "/api/v2/credentials/1/access_list/", + "object_roles": "/api/v2/credentials/1/object_roles/", + "owner_users": "/api/v2/credentials/1/owner_users/", + "owner_teams": "/api/v2/credentials/1/owner_teams/", + "copy": "/api/v2/credentials/1/copy/", + "input_sources": "/api/v2/credentials/1/input_sources/", + "credential_type": "/api/v2/credential_types/20/", + "user": "/api/v2/users/1/" + }, + "summary_fields": { + "credential_type": { + "id": 20, + "name": "CyberArk Conjur Secret Lookup", + "description": "" + }, + "created_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "modified_by": { + "id": 1, + "username": "admin", + "first_name": "", + "last_name": "" + }, + "object_roles": { + "admin_role": { + "description": "Can manage all aspects of the credential", + "name": "Admin", + "id": 27 + }, + "use_role": { + "description": "Can use the credential in a job template", + "name": "Use", + "id": 28 + }, + "read_role": { + "description": "May view settings for the credential", + "name": "Read", + "id": 29 + } + }, + "user_capabilities": { + "edit": true, + "delete": true, + "copy": true, + "use": true + }, + "owners": [ + { + "id": 1, + "type": "user", + "name": "admin", + "description": " ", + "url": "/api/v2/users/1/" + } + ] + }, + "created": "2020-05-19T12:51:36.956029Z", + "modified": "2020-05-19T12:51:36.956086Z", + "name": "CyberArk Conjur Secret Lookup", + "description": "", + "organization": null, + "credential_type": 20, + "inputs": { + "url": "https://localhost", + "account": "adsf", + "api_key": "$encrypted$", + "username": "adsf" + }, + "kind": "conjur", + "cloud": false, + "kubernetes": false +}