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).

This commit is contained in:
mabashian 2020-05-26 08:50:50 -04:00
parent e927680cc2
commit df069f3874
8 changed files with 284 additions and 24 deletions

View File

@ -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(
<Formik
initialValues={{
password: '',
}}
>
{() => (
<PasswordField id="test-password" name="password" label="Password" />
)}
</Formik>
);
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);
});
});

View File

@ -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(
<Formik
initialValues={{
password: '',
}}
>
{() => (
<PasswordInput id="test-password" name="password" label="Password" />
)}
</Formik>
);
expect(wrapper).toHaveLength(1);
});
test('properly responds to show/hide toggles', async () => {
const wrapper = mountWithContexts(
<Formik
initialValues={{
password: '',
}}
>
{() => (
<PasswordInput id="test-password" name="password" label="Password" />
)}
</Formik>
);
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);
});
});

View File

@ -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('<CredentialPluginField />', () => {
let wrapper;
describe('No plugin configured', () => {
beforeAll(() => {
wrapper = mountWithContexts(
<Formik
initialValues={{
inputs: {
username: '',
},
}}
>
{() => (
<CredentialPluginField
id="credential-username"
name="inputs.username"
label="Username"
>
<TextInput id="credential-username" />
</CredentialPluginField>
)}
</Formik>
);
});
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(
<Formik
initialValues={{
inputs: {
username: {
credential: {
id: 1,
name: 'CyberArk Cred',
cloud: false,
credential_type_id: 20,
kind: 'conjur',
},
},
},
}}
>
{() => (
<CredentialPluginField
id="credential-username"
name="inputs.username"
label="Username"
>
<TextInput id="credential-username" />
</CredentialPluginField>
)}
</Formik>
);
});
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);
});
});
});

View File

@ -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 = {};

View File

@ -0,0 +1,18 @@
import React from 'react';
import { mountWithContexts } from '../../../../../../testUtils/enzymeHelpers';
import CredentialPluginPrompt from './CredentialPluginPrompt';
describe('<CredentialPluginPrompt />', () => {
let wrapper;
beforeAll(() => {
wrapper = mountWithContexts(
<CredentialPluginPrompt onClose={jest.fn()} onSubmit={jest.fn()} />
);
});
afterAll(() => {
wrapper.unmount();
});
test('renders the expected content', () => {
expect(wrapper).toHaveLength(1);
});
});

View File

@ -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);

View File

@ -0,0 +1,34 @@
import React from 'react';
import { mountWithContexts } from '../../../../../testUtils/enzymeHelpers';
import selectedCredential from '../data.cyberArkCredential.json';
import CredentialPluginSelected from './CredentialPluginSelected';
describe('<CredentialPluginSelected />', () => {
let wrapper;
const onClearPlugin = jest.fn();
const onEditPlugin = jest.fn();
beforeAll(() => {
wrapper = mountWithContexts(
<CredentialPluginSelected
credential={selectedCredential}
onClearPlugin={onClearPlugin}
onEditPlugin={onEditPlugin}
/>
);
});
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);
});
});

View File

@ -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
}