mirror of
https://github.com/ansible/awx.git
synced 2026-03-11 14:39:30 -02:30
adds tests
This commit is contained in:
@@ -70,56 +70,55 @@ function DeleteButton({
|
|||||||
>
|
>
|
||||||
{children || i18n._(t`Delete`)}
|
{children || i18n._(t`Delete`)}
|
||||||
</Button>
|
</Button>
|
||||||
{!deleteMessageError && (
|
|
||||||
<AlertModal
|
<AlertModal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
title={modalTitle}
|
title={modalTitle}
|
||||||
variant="danger"
|
variant="danger"
|
||||||
onClose={() => toggleModal(false)}
|
onClose={() => toggleModal(false)}
|
||||||
actions={[
|
actions={[
|
||||||
<Button
|
<Button
|
||||||
ouiaId="delete-modal-confirm"
|
ouiaId="delete-modal-confirm"
|
||||||
key="delete"
|
key="delete"
|
||||||
variant="danger"
|
variant="danger"
|
||||||
aria-label={i18n._(t`Confirm Delete`)}
|
aria-label={i18n._(t`Confirm Delete`)}
|
||||||
isDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
onClick={onConfirm}
|
onClick={onConfirm}
|
||||||
>
|
>
|
||||||
{i18n._(t`Delete`)}
|
{i18n._(t`Delete`)}
|
||||||
</Button>,
|
</Button>,
|
||||||
<Button
|
<Button
|
||||||
ouiaId="delete-modal-cancel"
|
ouiaId="delete-modal-cancel"
|
||||||
key="cancel"
|
key="cancel"
|
||||||
variant="link"
|
variant="link"
|
||||||
aria-label={i18n._(t`Cancel`)}
|
aria-label={i18n._(t`Cancel`)}
|
||||||
onClick={() => toggleModal(false)}
|
onClick={() => toggleModal(false)}
|
||||||
>
|
>
|
||||||
{i18n._(t`Cancel`)}
|
{i18n._(t`Cancel`)}
|
||||||
</Button>,
|
</Button>,
|
||||||
]}
|
]}
|
||||||
>
|
>
|
||||||
{i18n._(t`Are you sure you want to delete:`)}
|
{i18n._(t`Are you sure you want to delete:`)}
|
||||||
<br />
|
<br />
|
||||||
<strong>{name}</strong>
|
<strong>{name}</strong>
|
||||||
{Object.values(deleteDetails).length > 0 && (
|
{Object.values(deleteDetails).length > 0 && (
|
||||||
<WarningMessage
|
<WarningMessage
|
||||||
variant="warning"
|
variant="warning"
|
||||||
isInline
|
isInline
|
||||||
title={
|
title={
|
||||||
<div>
|
<div>
|
||||||
<div aria-label={deleteMessage}>{deleteMessage}</div>
|
<div aria-label={deleteMessage}>{deleteMessage}</div>
|
||||||
<br />
|
<br />
|
||||||
{Object.entries(deleteDetails).map(([key, value]) => (
|
{Object.entries(deleteDetails).map(([key, value]) => (
|
||||||
<DetailsWrapper aria-label={`${key}: ${value}`} key={key}>
|
<DetailsWrapper aria-label={`${key}: ${value}`} key={key}>
|
||||||
<span>{key}</span> <Badge>{value}</Badge>
|
<span>{key}</span> <Badge>{value}</Badge>
|
||||||
</DetailsWrapper>
|
</DetailsWrapper>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</AlertModal>
|
</AlertModal>
|
||||||
)}
|
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,7 +38,6 @@ describe('<DeleteButton />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
// expect(wrapper.find('Modal')).toHaveLength(0);
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('button').prop('onClick')();
|
wrapper.find('button').prop('onClick')();
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -112,7 +112,11 @@ function ToolbarDeleteButton({
|
|||||||
};
|
};
|
||||||
|
|
||||||
const toggleModal = async isOpen => {
|
const toggleModal = async isOpen => {
|
||||||
if (itemsToDelete.length === 1 && deleteDetailsRequests?.length > 0) {
|
if (
|
||||||
|
isOpen &&
|
||||||
|
itemsToDelete.length === 1 &&
|
||||||
|
deleteDetailsRequests?.length > 0
|
||||||
|
) {
|
||||||
const { results, error } = await getRelatedResourceDeleteCounts(
|
const { results, error } = await getRelatedResourceDeleteCounts(
|
||||||
deleteDetailsRequests
|
deleteDetailsRequests
|
||||||
);
|
);
|
||||||
@@ -195,7 +199,7 @@ function ToolbarDeleteButton({
|
|||||||
variant="secondary"
|
variant="secondary"
|
||||||
aria-label={i18n._(t`Delete`)}
|
aria-label={i18n._(t`Delete`)}
|
||||||
onClick={() => toggleModal(true)}
|
onClick={() => toggleModal(true)}
|
||||||
isAriaDisabled={isDisabled}
|
isDisabled={isDisabled}
|
||||||
>
|
>
|
||||||
{i18n._(t`Delete`)}
|
{i18n._(t`Delete`)}
|
||||||
</Button>
|
</Button>
|
||||||
@@ -203,7 +207,7 @@ function ToolbarDeleteButton({
|
|||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{isModalOpen && !deleteMessageError && (
|
{isModalOpen && (
|
||||||
<AlertModal
|
<AlertModal
|
||||||
variant="danger"
|
variant="danger"
|
||||||
title={modalTitle}
|
title={modalTitle}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ describe('<ToolbarDeleteButton />', () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
deleteDetailsRequests = [
|
deleteDetailsRequests = [
|
||||||
{
|
{
|
||||||
label: 'job',
|
label: 'Workflow Job Template Node',
|
||||||
request: CredentialsAPI.read.mockResolvedValue({ data: { count: 1 } }),
|
request: CredentialsAPI.read.mockResolvedValue({ data: { count: 1 } }),
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
@@ -62,10 +62,55 @@ describe('<ToolbarDeleteButton />', () => {
|
|||||||
wrapper.find('button').prop('onClick')();
|
wrapper.find('button').prop('onClick')();
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, 'Modal', el => el.length > 0);
|
await waitForElement(wrapper, 'Modal', el => el.length > 0);
|
||||||
|
expect(CredentialsAPI.read).toBeCalled();
|
||||||
expect(wrapper.find('Modal')).toHaveLength(1);
|
expect(wrapper.find('Modal')).toHaveLength(1);
|
||||||
|
expect(
|
||||||
|
wrapper.find('span[aria-label="Workflow Job Template Node: 1"]')
|
||||||
|
).toHaveLength(1);
|
||||||
expect(wrapper.find('div[aria-label="Delete this?"]')).toHaveLength(1);
|
expect(wrapper.find('div[aria-label="Delete this?"]')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should open delete error modal', async () => {
|
||||||
|
const request = [
|
||||||
|
{
|
||||||
|
label: 'Workflow Job Template Node',
|
||||||
|
request: CredentialsAPI.read.mockRejectedValue(
|
||||||
|
new Error({
|
||||||
|
response: {
|
||||||
|
config: {
|
||||||
|
method: 'get',
|
||||||
|
url: '/api/v2/credentals',
|
||||||
|
},
|
||||||
|
data: 'An error occurred',
|
||||||
|
status: 403,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
),
|
||||||
|
},
|
||||||
|
];
|
||||||
|
let wrapper;
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<ToolbarDeleteButton
|
||||||
|
onDelete={() => {}}
|
||||||
|
itemsToDelete={[itemA]}
|
||||||
|
deleteDetailsRequests={request}
|
||||||
|
deleteMessage="Delete this?"
|
||||||
|
warningMessage="Are you sure to want to delete this"
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(wrapper.find('Modal')).toHaveLength(0);
|
||||||
|
await act(async () => wrapper.find('button').simulate('click'));
|
||||||
|
await waitForElement(wrapper, 'Modal', el => el.length > 0);
|
||||||
|
expect(CredentialsAPI.read).toBeCalled();
|
||||||
|
|
||||||
|
wrapper.update();
|
||||||
|
|
||||||
|
expect(wrapper.find('AlertModal[title="Error!"]')).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('should invoke onDelete prop', () => {
|
test('should invoke onDelete prop', () => {
|
||||||
const onDelete = jest.fn();
|
const onDelete = jest.fn();
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Delete"
|
aria-label="Delete"
|
||||||
isAriaDisabled={true}
|
isDisabled={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
@@ -92,20 +92,19 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
|||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
aria-label="Delete"
|
aria-label="Delete"
|
||||||
isAriaDisabled={true}
|
isDisabled={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
aria-disabled={true}
|
aria-disabled={true}
|
||||||
aria-label="Delete"
|
aria-label="Delete"
|
||||||
className="pf-c-button pf-m-secondary pf-m-aria-disabled"
|
className="pf-c-button pf-m-secondary pf-m-disabled"
|
||||||
data-ouia-component-id="OUIA-Generated-Button-secondary-1"
|
data-ouia-component-id="OUIA-Generated-Button-secondary-1"
|
||||||
data-ouia-component-type="PF4/Button"
|
data-ouia-component-type="PF4/Button"
|
||||||
data-ouia-safe={true}
|
data-ouia-safe={true}
|
||||||
disabled={false}
|
disabled={true}
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
onKeyPress={[Function]}
|
|
||||||
role={null}
|
role={null}
|
||||||
tabIndex={null}
|
tabIndex={null}
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -119,7 +119,7 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
title="Remove Team Access"
|
title="Remove Team Access"
|
||||||
titleIconVariant={null}
|
titleIconVariant={null}
|
||||||
titleLabel=""
|
titleLabel=""
|
||||||
variant="small"
|
variant="medium"
|
||||||
>
|
>
|
||||||
<Portal
|
<Portal
|
||||||
containerInfo={
|
containerInfo={
|
||||||
@@ -135,8 +135,8 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
aria-label="Alert modal"
|
aria-label="Alert modal"
|
||||||
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
class="pf-c-modal-box pf-m-sm"
|
class="pf-c-modal-box pf-m-md"
|
||||||
data-ouia-component-id="OUIA-Generated-Modal-small-1"
|
data-ouia-component-id="OUIA-Generated-Modal-medium-1"
|
||||||
data-ouia-component-type="PF4/ModalContent"
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
data-ouia-safe="true"
|
data-ouia-safe="true"
|
||||||
id="pf-modal-part-0"
|
id="pf-modal-part-0"
|
||||||
@@ -277,13 +277,13 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
isOpen={true}
|
isOpen={true}
|
||||||
labelId="pf-modal-part-1"
|
labelId="pf-modal-part-1"
|
||||||
onClose={[Function]}
|
onClose={[Function]}
|
||||||
ouiaId="OUIA-Generated-Modal-small-1"
|
ouiaId="OUIA-Generated-Modal-medium-1"
|
||||||
ouiaSafe={true}
|
ouiaSafe={true}
|
||||||
showClose={true}
|
showClose={true}
|
||||||
title="Remove Team Access"
|
title="Remove Team Access"
|
||||||
titleIconVariant={null}
|
titleIconVariant={null}
|
||||||
titleLabel=""
|
titleLabel=""
|
||||||
variant="small"
|
variant="medium"
|
||||||
>
|
>
|
||||||
<Backdrop>
|
<Backdrop>
|
||||||
<div
|
<div
|
||||||
@@ -308,20 +308,20 @@ exports[`<DeleteRoleConfirmationModal /> should render initially 1`] = `
|
|||||||
aria-label="Alert modal"
|
aria-label="Alert modal"
|
||||||
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
||||||
className=""
|
className=""
|
||||||
data-ouia-component-id="OUIA-Generated-Modal-small-1"
|
data-ouia-component-id="OUIA-Generated-Modal-medium-1"
|
||||||
data-ouia-component-type="PF4/ModalContent"
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
data-ouia-safe={true}
|
data-ouia-safe={true}
|
||||||
id="pf-modal-part-0"
|
id="pf-modal-part-0"
|
||||||
style={Object {}}
|
style={Object {}}
|
||||||
variant="small"
|
variant="medium"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
aria-describedby="pf-modal-part-2"
|
aria-describedby="pf-modal-part-2"
|
||||||
aria-label="Alert modal"
|
aria-label="Alert modal"
|
||||||
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
aria-labelledby="pf-modal-part-0 alert-modal-header-label pf-modal-part-1"
|
||||||
aria-modal="true"
|
aria-modal="true"
|
||||||
className="pf-c-modal-box pf-m-sm"
|
className="pf-c-modal-box pf-m-md"
|
||||||
data-ouia-component-id="OUIA-Generated-Modal-small-1"
|
data-ouia-component-id="OUIA-Generated-Modal-medium-1"
|
||||||
data-ouia-component-type="PF4/ModalContent"
|
data-ouia-component-type="PF4/ModalContent"
|
||||||
data-ouia-safe={true}
|
data-ouia-safe={true}
|
||||||
id="pf-modal-part-0"
|
id="pf-modal-part-0"
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { getQSConfig, parseQueryString } from '../../util/qs';
|
|||||||
import useWsTemplates from '../../util/useWsTemplates';
|
import useWsTemplates from '../../util/useWsTemplates';
|
||||||
import AddDropDownButton from '../AddDropDownButton';
|
import AddDropDownButton from '../AddDropDownButton';
|
||||||
import TemplateListItem from './TemplateListItem';
|
import TemplateListItem from './TemplateListItem';
|
||||||
import { deleteRequests } from '../../util/getDeleteDetails';
|
import { relatedResourceDeleteRequests } from '../../util/getRelatedResourceDeleteDetails';
|
||||||
|
|
||||||
function TemplateList({ defaultParams, i18n }) {
|
function TemplateList({ defaultParams, i18n }) {
|
||||||
// The type value in const qsConfig below does not have a space between job_template and
|
// The type value in const qsConfig below does not have a space between job_template and
|
||||||
@@ -169,7 +169,10 @@ function TemplateList({ defaultParams, i18n }) {
|
|||||||
<AddDropDownButton key="add" dropdownItems={addDropDownButton} />
|
<AddDropDownButton key="add" dropdownItems={addDropDownButton} />
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteDetailsRequests = deleteRequests.template(selected[0], i18n);
|
const deleteDetailsRequests = relatedResourceDeleteRequests.template(
|
||||||
|
selected[0],
|
||||||
|
i18n
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<Fragment>
|
||||||
|
|||||||
@@ -65,6 +65,12 @@ describe('<CredentialDetail />', () => {
|
|||||||
expect(wrapper.find('CredentialDetail').length).toBe(1);
|
expect(wrapper.find('CredentialDetail').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(4);
|
||||||
|
});
|
||||||
|
|
||||||
test('should render details', () => {
|
test('should render details', () => {
|
||||||
expectDetailToMatch(wrapper, 'Name', mockCredential.name);
|
expectDetailToMatch(wrapper, 'Name', mockCredential.name);
|
||||||
expectDetailToMatch(wrapper, 'Description', mockCredential.description);
|
expectDetailToMatch(wrapper, 'Description', mockCredential.description);
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ describe('<CredentialList />', () => {
|
|||||||
expect(wrapper.find('CredentialList').length).toBe(1);
|
expect(wrapper.find('CredentialList').length).toBe(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(4);
|
||||||
|
});
|
||||||
|
|
||||||
test('should fetch credentials from api and render the in the list', () => {
|
test('should fetch credentials from api and render the in the list', () => {
|
||||||
expect(CredentialsAPI.read).toHaveBeenCalled();
|
expect(CredentialsAPI.read).toHaveBeenCalled();
|
||||||
expect(wrapper.find('CredentialListItem').length).toBe(5);
|
expect(wrapper.find('CredentialListItem').length).toBe(5);
|
||||||
|
|||||||
@@ -92,6 +92,12 @@ describe('<CredentialTypeDetails/>', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('expected api call is made for delete', async () => {
|
test('expected api call is made for delete', async () => {
|
||||||
const history = createMemoryHistory({
|
const history = createMemoryHistory({
|
||||||
initialEntries: ['/credential_types/42/details'],
|
initialEntries: ['/credential_types/42/details'],
|
||||||
|
|||||||
@@ -6,10 +6,11 @@ import {
|
|||||||
waitForElement,
|
waitForElement,
|
||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
|
|
||||||
import { CredentialTypesAPI } from '../../../api';
|
import { CredentialTypesAPI, CredentialsAPI } from '../../../api';
|
||||||
import CredentialTypeList from './CredentialTypeList';
|
import CredentialTypeList from './CredentialTypeList';
|
||||||
|
|
||||||
jest.mock('../../../api/models/CredentialTypes');
|
jest.mock('../../../api/models/CredentialTypes');
|
||||||
|
jest.mock('../../../api/models/Credentials');
|
||||||
|
|
||||||
const credentialTypes = {
|
const credentialTypes = {
|
||||||
data: {
|
data: {
|
||||||
@@ -49,6 +50,12 @@ describe('<CredentialTypeList', () => {
|
|||||||
await waitForElement(wrapper, 'CredentialTypeList', el => el.length > 0);
|
await waitForElement(wrapper, 'CredentialTypeList', el => el.length > 0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('should have data fetched and render 2 rows', async () => {
|
test('should have data fetched and render 2 rows', async () => {
|
||||||
CredentialTypesAPI.read.mockResolvedValue(credentialTypes);
|
CredentialTypesAPI.read.mockResolvedValue(credentialTypes);
|
||||||
CredentialTypesAPI.readOptions.mockResolvedValue(options);
|
CredentialTypesAPI.readOptions.mockResolvedValue(options);
|
||||||
@@ -65,6 +72,7 @@ describe('<CredentialTypeList', () => {
|
|||||||
test('should delete item successfully', async () => {
|
test('should delete item successfully', async () => {
|
||||||
CredentialTypesAPI.read.mockResolvedValue(credentialTypes);
|
CredentialTypesAPI.read.mockResolvedValue(credentialTypes);
|
||||||
CredentialTypesAPI.readOptions.mockResolvedValue(options);
|
CredentialTypesAPI.readOptions.mockResolvedValue(options);
|
||||||
|
CredentialsAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<CredentialTypeList />);
|
wrapper = mountWithContexts(<CredentialTypeList />);
|
||||||
|
|||||||
@@ -105,6 +105,18 @@ describe('<InventoryDetail />', () => {
|
|||||||
expect(dates.at(1).prop('date')).toEqual(mockInventory.modified);
|
expect(dates.at(1).prop('date')).toEqual(mockInventory.modified);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
let wrapper;
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<InventoryDetail inventory={mockInventory} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
test('should load instance groups', async () => {
|
test('should load instance groups', async () => {
|
||||||
InventoriesAPI.readInstanceGroups.mockResolvedValue({
|
InventoriesAPI.readInstanceGroups.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
|
|||||||
@@ -1,11 +1,17 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { InventoriesAPI } from '../../../api';
|
import {
|
||||||
|
InventoriesAPI,
|
||||||
|
JobTemplatesAPI,
|
||||||
|
WorkflowJobTemplatesAPI,
|
||||||
|
} from '../../../api';
|
||||||
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
||||||
|
|
||||||
import InventoryList from './InventoryList';
|
import InventoryList from './InventoryList';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api/models/Inventories');
|
||||||
|
jest.mock('../../../api/models/JobTemplates');
|
||||||
|
jest.mock('../../../api/models/WorkflowJobTemplates');
|
||||||
|
|
||||||
const mockInventories = [
|
const mockInventories = [
|
||||||
{
|
{
|
||||||
@@ -136,6 +142,8 @@ describe('<InventoryList />', () => {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
JobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
WorkflowJobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
debug = global.console.debug; // eslint-disable-line prefer-destructuring
|
debug = global.console.debug; // eslint-disable-line prefer-destructuring
|
||||||
global.console.debug = () => {};
|
global.console.debug = () => {};
|
||||||
});
|
});
|
||||||
@@ -155,6 +163,16 @@ describe('<InventoryList />', () => {
|
|||||||
expect(wrapper.find('InventoryListItem')).toHaveLength(3);
|
expect(wrapper.find('InventoryListItem')).toHaveLength(3);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
let wrapper;
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<InventoryList />);
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(2);
|
||||||
|
});
|
||||||
|
|
||||||
test('should select inventory when checked', async () => {
|
test('should select inventory when checked', async () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
|||||||
@@ -7,9 +7,20 @@ import {
|
|||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import InventorySourceDetail from './InventorySourceDetail';
|
import InventorySourceDetail from './InventorySourceDetail';
|
||||||
import mockInvSource from '../shared/data.inventory_source.json';
|
import mockInvSource from '../shared/data.inventory_source.json';
|
||||||
import { InventorySourcesAPI } from '../../../api';
|
import {
|
||||||
|
InventorySourcesAPI,
|
||||||
|
InventoriesAPI,
|
||||||
|
WorkflowJobTemplateNodesAPI,
|
||||||
|
} from '../../../api';
|
||||||
|
|
||||||
jest.mock('../../../api/models/InventorySources');
|
jest.mock('../../../api/models/InventorySources');
|
||||||
|
jest.mock('../../../api/models/Inventories');
|
||||||
|
jest.mock('../../../api/models/WorkflowJobTemplateNodes');
|
||||||
|
|
||||||
|
InventoriesAPI.updateSources.mockResolvedValue({
|
||||||
|
data: [{ inventory_source: 1 }],
|
||||||
|
});
|
||||||
|
WorkflowJobTemplateNodesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
InventorySourcesAPI.readOptions.mockResolvedValue({
|
InventorySourcesAPI.readOptions.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
actions: {
|
actions: {
|
||||||
@@ -101,6 +112,17 @@ describe('InventorySourceDetail', () => {
|
|||||||
expect(wrapper.find('InventorySourceSyncButton')).toHaveLength(1);
|
expect(wrapper.find('InventorySourceSyncButton')).toHaveLength(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<InventorySourceDetail inventorySource={mockInvSource} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('should hide expected action buttons for users without permissions', async () => {
|
test('should hide expected action buttons for users without permissions', async () => {
|
||||||
const userCapabilities = {
|
const userCapabilities = {
|
||||||
edit: false,
|
edit: false,
|
||||||
|
|||||||
@@ -2,7 +2,11 @@ import React from 'react';
|
|||||||
import { Route } from 'react-router-dom';
|
import { Route } from 'react-router-dom';
|
||||||
import { createMemoryHistory } from 'history';
|
import { createMemoryHistory } from 'history';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { InventoriesAPI, InventorySourcesAPI } from '../../../api';
|
import {
|
||||||
|
InventoriesAPI,
|
||||||
|
InventorySourcesAPI,
|
||||||
|
WorkflowJobTemplateNodesAPI,
|
||||||
|
} from '../../../api';
|
||||||
import {
|
import {
|
||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
@@ -13,6 +17,7 @@ import InventorySourceList from './InventorySourceList';
|
|||||||
jest.mock('../../../api/models/InventorySources');
|
jest.mock('../../../api/models/InventorySources');
|
||||||
jest.mock('../../../api/models/Inventories');
|
jest.mock('../../../api/models/Inventories');
|
||||||
jest.mock('../../../api/models/InventoryUpdates');
|
jest.mock('../../../api/models/InventoryUpdates');
|
||||||
|
jest.mock('../../../api/models/WorkflowJobTemplateNodes');
|
||||||
|
|
||||||
const sources = {
|
const sources = {
|
||||||
data: {
|
data: {
|
||||||
@@ -60,6 +65,10 @@ describe('<InventorySourceList />', () => {
|
|||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
debug = global.console.debug; // eslint-disable-line prefer-destructuring
|
debug = global.console.debug; // eslint-disable-line prefer-destructuring
|
||||||
global.console.debug = () => {};
|
global.console.debug = () => {};
|
||||||
|
InventoriesAPI.updateSources.mockResolvedValue({
|
||||||
|
data: [{ inventory_source: 1 }],
|
||||||
|
});
|
||||||
|
WorkflowJobTemplateNodesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
InventoriesAPI.readSources.mockResolvedValue(sources);
|
InventoriesAPI.readSources.mockResolvedValue(sources);
|
||||||
InventorySourcesAPI.readOptions.mockResolvedValue({
|
InventorySourcesAPI.readOptions.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -119,6 +128,12 @@ describe('<InventorySourceList />', () => {
|
|||||||
expect(InventorySourcesAPI.readOptions).toHaveBeenCalled();
|
expect(InventorySourcesAPI.readOptions).toHaveBeenCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('source data should render properly', async () => {
|
test('source data should render properly', async () => {
|
||||||
await waitForElement(wrapper, 'InventorySourceList', el => el.length > 0);
|
await waitForElement(wrapper, 'InventorySourceList', el => el.length > 0);
|
||||||
expect(
|
expect(
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ describe('<JobDetail />', () => {
|
|||||||
wrapper.update();
|
wrapper.update();
|
||||||
const modal = wrapper.find('Modal');
|
const modal = wrapper.find('Modal');
|
||||||
expect(modal.length).toBe(1);
|
expect(modal.length).toBe(1);
|
||||||
modal.find('button[aria-label="Delete"]').simulate('click');
|
modal.find('button[aria-label="Confirm Delete"]').simulate('click');
|
||||||
expect(JobsAPI.destroy).toHaveBeenCalledTimes(1);
|
expect(JobsAPI.destroy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -138,7 +138,7 @@ describe('<JobDetail />', () => {
|
|||||||
const modal = wrapper.find('Modal');
|
const modal = wrapper.find('Modal');
|
||||||
expect(modal.length).toBe(1);
|
expect(modal.length).toBe(1);
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
modal.find('button[aria-label="Delete"]').simulate('click');
|
modal.find('button[aria-label="Confirm Delete"]').simulate('click');
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
|
|||||||
@@ -188,9 +188,19 @@ describe('<JobOutput />', () => {
|
|||||||
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
wrapper = mountWithContexts(<JobOutput job={mockJob} />);
|
||||||
});
|
});
|
||||||
await waitForElement(wrapper, 'JobEvent', el => el.length > 0);
|
await waitForElement(wrapper, 'JobEvent', el => el.length > 0);
|
||||||
await act(async () => {
|
await act(async () =>
|
||||||
wrapper.find('DeleteButton').invoke('onConfirm')();
|
wrapper.find('button[aria-label="Delete"]').simulate('click')
|
||||||
});
|
);
|
||||||
|
await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'Modal',
|
||||||
|
el => el.props().isOpen === true && el.props().title === 'Delete Job'
|
||||||
|
);
|
||||||
|
await act(async () =>
|
||||||
|
wrapper
|
||||||
|
.find('Modal button[aria-label="Confirm Delete"]')
|
||||||
|
.simulate('click')
|
||||||
|
);
|
||||||
expect(JobsAPI.destroy).toHaveBeenCalledTimes(1);
|
expect(JobsAPI.destroy).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { OrganizationsAPI } from '../../../api';
|
import { OrganizationsAPI, CredentialsAPI } from '../../../api';
|
||||||
import {
|
import {
|
||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
@@ -44,6 +44,8 @@ describe('<OrganizationDetail />', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
CredentialsAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
|
||||||
OrganizationsAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups);
|
OrganizationsAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -64,6 +66,20 @@ describe('<OrganizationDetail />', () => {
|
|||||||
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
expect(OrganizationsAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
let component;
|
||||||
|
await act(async () => {
|
||||||
|
component = mountWithContexts(
|
||||||
|
<OrganizationDetail organization={mockOrganization} />
|
||||||
|
);
|
||||||
|
});
|
||||||
|
await waitForElement(component, 'ContentLoading', el => el.length === 0);
|
||||||
|
|
||||||
|
expect(
|
||||||
|
component.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('should render the expected instance group', async () => {
|
test('should render the expected instance group', async () => {
|
||||||
let component;
|
let component;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import { OrganizationsAPI } from '../../../api';
|
import { OrganizationsAPI, CredentialsAPI } from '../../../api';
|
||||||
import {
|
import {
|
||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
@@ -70,6 +70,7 @@ const mockOrganizations = {
|
|||||||
describe('<OrganizationsList />', () => {
|
describe('<OrganizationsList />', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
CredentialsAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
OrganizationsAPI.read.mockResolvedValue(mockOrganizations);
|
OrganizationsAPI.read.mockResolvedValue(mockOrganizations);
|
||||||
OrganizationsAPI.readOptions.mockResolvedValue({
|
OrganizationsAPI.readOptions.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
@@ -90,6 +91,20 @@ describe('<OrganizationsList />', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<OrganizationsList />);
|
||||||
|
});
|
||||||
|
await waitForElement(
|
||||||
|
wrapper,
|
||||||
|
'OrganizationsList',
|
||||||
|
el => el.find('ContentLoading').length === 0
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('Items are rendered after loading', async () => {
|
test('Items are rendered after loading', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<OrganizationsList />);
|
wrapper = mountWithContexts(<OrganizationsList />);
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ import {
|
|||||||
mountWithContexts,
|
mountWithContexts,
|
||||||
waitForElement,
|
waitForElement,
|
||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import { ProjectsAPI } from '../../../api';
|
import {
|
||||||
|
ProjectsAPI,
|
||||||
|
JobTemplatesAPI,
|
||||||
|
WorkflowJobTemplatesAPI,
|
||||||
|
InventorySourcesAPI,
|
||||||
|
} from '../../../api';
|
||||||
import ProjectDetail from './ProjectDetail';
|
import ProjectDetail from './ProjectDetail';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api');
|
||||||
@@ -147,6 +152,27 @@ describe('<ProjectDetail />', () => {
|
|||||||
expect(wrapper.find('Detail[label="Options"]').length).toBe(0);
|
expect(wrapper.find('Detail[label="Options"]').length).toBe(0);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', () => {
|
||||||
|
JobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
WorkflowJobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
InventorySourcesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
const mockOptions = {
|
||||||
|
scm_type: '',
|
||||||
|
scm_clean: false,
|
||||||
|
scm_delete_on_update: false,
|
||||||
|
scm_update_on_launch: false,
|
||||||
|
allow_override: false,
|
||||||
|
created: '',
|
||||||
|
modified: '',
|
||||||
|
};
|
||||||
|
const wrapper = mountWithContexts(
|
||||||
|
<ProjectDetail project={{ ...mockProject, ...mockOptions }} />
|
||||||
|
);
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
test('should render with missing summary fields', async () => {
|
test('should render with missing summary fields', async () => {
|
||||||
const wrapper = mountWithContexts(
|
const wrapper = mountWithContexts(
|
||||||
<ProjectDetail project={{ ...mockProject, summary_fields: {} }} />
|
<ProjectDetail project={{ ...mockProject, summary_fields: {} }} />
|
||||||
|
|||||||
@@ -1,7 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import { act } from 'react-dom/test-utils';
|
||||||
import { ProjectsAPI } from '../../../api';
|
import {
|
||||||
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
ProjectsAPI,
|
||||||
|
JobTemplatesAPI,
|
||||||
|
WorkflowJobTemplatesAPI,
|
||||||
|
InventorySourcesAPI,
|
||||||
|
} from '../../../api';
|
||||||
|
import {
|
||||||
|
mountWithContexts,
|
||||||
|
waitForElement,
|
||||||
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import ProjectList from './ProjectList';
|
import ProjectList from './ProjectList';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api');
|
||||||
@@ -83,6 +91,9 @@ const mockProjects = [
|
|||||||
|
|
||||||
describe('<ProjectList />', () => {
|
describe('<ProjectList />', () => {
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
JobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
WorkflowJobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
InventorySourcesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
ProjectsAPI.read.mockResolvedValue({
|
ProjectsAPI.read.mockResolvedValue({
|
||||||
data: {
|
data: {
|
||||||
count: mockProjects.length,
|
count: mockProjects.length,
|
||||||
@@ -138,6 +149,17 @@ describe('<ProjectList />', () => {
|
|||||||
).toEqual(true);
|
).toEqual(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
let wrapper;
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(<ProjectList />);
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
expect(
|
||||||
|
wrapper.find('ToolbarDeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(3);
|
||||||
|
});
|
||||||
|
|
||||||
test('should select all', async () => {
|
test('should select all', async () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
@@ -177,10 +199,11 @@ describe('<ProjectList />', () => {
|
|||||||
.at(2)
|
.at(2)
|
||||||
.invoke('onSelect')();
|
.invoke('onSelect')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
|
||||||
|
|
||||||
expect(wrapper.find('ToolbarDeleteButton button').prop('disabled')).toEqual(
|
waitForElement(
|
||||||
true
|
wrapper,
|
||||||
|
'ToolbarDeleteButton button',
|
||||||
|
el => el.prop('disabled') === true
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import {
|
|||||||
waitForElement,
|
waitForElement,
|
||||||
} from '../../../../testUtils/enzymeHelpers';
|
} from '../../../../testUtils/enzymeHelpers';
|
||||||
import JobTemplateDetail from './JobTemplateDetail';
|
import JobTemplateDetail from './JobTemplateDetail';
|
||||||
import { JobTemplatesAPI } from '../../../api';
|
import { JobTemplatesAPI, WorkflowJobTemplateNodesAPI } from '../../../api';
|
||||||
import mockTemplate from '../shared/data.job_template.json';
|
import mockTemplate from '../shared/data.job_template.json';
|
||||||
|
|
||||||
jest.mock('../../../api');
|
jest.mock('../../../api');
|
||||||
@@ -25,6 +25,7 @@ describe('<JobTemplateDetail />', () => {
|
|||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
JobTemplatesAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups);
|
JobTemplatesAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups);
|
||||||
|
WorkflowJobTemplateNodesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<JobTemplateDetail template={mockTemplate} />
|
<JobTemplateDetail template={mockTemplate} />
|
||||||
@@ -56,6 +57,23 @@ describe('<JobTemplateDetail />', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
await act(async () => {
|
||||||
|
wrapper = mountWithContexts(
|
||||||
|
<JobTemplateDetail
|
||||||
|
template={{
|
||||||
|
...mockTemplate,
|
||||||
|
become_enabled: true,
|
||||||
|
summary_fields: { user_capabilities: { delete: true } },
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('should request instance groups from api', async () => {
|
test('should request instance groups from api', async () => {
|
||||||
expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalledTimes(1);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -5,6 +5,9 @@ import { act } from 'react-dom/test-utils';
|
|||||||
|
|
||||||
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
import { mountWithContexts } from '../../../../testUtils/enzymeHelpers';
|
||||||
import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail';
|
import WorkflowJobTemplateDetail from './WorkflowJobTemplateDetail';
|
||||||
|
import { WorkflowJobTemplateNodesAPI } from '../../../api';
|
||||||
|
|
||||||
|
jest.mock('../../../api');
|
||||||
|
|
||||||
describe('<WorkflowJobTemplateDetail/>', () => {
|
describe('<WorkflowJobTemplateDetail/>', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
@@ -50,6 +53,7 @@ describe('<WorkflowJobTemplateDetail/>', () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
|
WorkflowJobTemplateNodesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
history = createMemoryHistory({
|
history = createMemoryHistory({
|
||||||
initialEntries: ['/templates/workflow_job_template/1/details'],
|
initialEntries: ['/templates/workflow_job_template/1/details'],
|
||||||
});
|
});
|
||||||
@@ -86,6 +90,7 @@ describe('<WorkflowJobTemplateDetail/>', () => {
|
|||||||
|
|
||||||
afterEach(() => {
|
afterEach(() => {
|
||||||
wrapper.unmount();
|
wrapper.unmount();
|
||||||
|
jest.clearAllMocks();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('renders successfully', () => {
|
test('renders successfully', () => {
|
||||||
@@ -163,6 +168,12 @@ describe('<WorkflowJobTemplateDetail/>', () => {
|
|||||||
).toBe('Demo EE');
|
).toBe('Demo EE');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('should have proper number of delete detail requests', async () => {
|
||||||
|
expect(
|
||||||
|
wrapper.find('DeleteButton').prop('deleteDetailsRequests')
|
||||||
|
).toHaveLength(1);
|
||||||
|
});
|
||||||
|
|
||||||
test('link out resource have the correct url', () => {
|
test('link out resource have the correct url', () => {
|
||||||
const inventory = wrapper.find('Detail[label="Inventory"]').find('Link');
|
const inventory = wrapper.find('Detail[label="Inventory"]').find('Link');
|
||||||
const organization = wrapper
|
const organization = wrapper
|
||||||
|
|||||||
@@ -1,128 +0,0 @@
|
|||||||
import { t } from '@lingui/macro';
|
|
||||||
|
|
||||||
import {
|
|
||||||
CredentialsAPI,
|
|
||||||
InventoriesAPI,
|
|
||||||
InventorySourcesAPI,
|
|
||||||
JobTemplatesAPI,
|
|
||||||
ProjectsAPI,
|
|
||||||
WorkflowJobTemplateNodesAPI,
|
|
||||||
WorkflowJobTemplatesAPI,
|
|
||||||
} from '../api';
|
|
||||||
|
|
||||||
export default async function getDeleteDetails(requests) {
|
|
||||||
const results = {};
|
|
||||||
let error = null;
|
|
||||||
let hasCount = false;
|
|
||||||
|
|
||||||
try {
|
|
||||||
await Promise.all(
|
|
||||||
requests.map(async ({ request, label }) => {
|
|
||||||
const {
|
|
||||||
data: { count },
|
|
||||||
} = await request();
|
|
||||||
if (count > 0) {
|
|
||||||
results[label] = count;
|
|
||||||
hasCount = true;
|
|
||||||
}
|
|
||||||
})
|
|
||||||
);
|
|
||||||
} catch (err) {
|
|
||||||
error = err;
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
results: hasCount && results,
|
|
||||||
error,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export const deleteRequests = {
|
|
||||||
credential: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
JobTemplatesAPI.read({
|
|
||||||
credentials: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Job Templates`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () => ProjectsAPI.read({ credentials: selected.id }),
|
|
||||||
label: i18n._(t`Projects`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () =>
|
|
||||||
InventoriesAPI.read({
|
|
||||||
insights_credential: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Inventories`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () =>
|
|
||||||
InventorySourcesAPI.read({
|
|
||||||
credentials__id: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Inventory Sources`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
template: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
WorkflowJobTemplateNodesAPI.read({
|
|
||||||
unified_job_template: selected.id,
|
|
||||||
}),
|
|
||||||
label: [i18n._(t`Workflow Job Template Node`)],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
credentialType: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
CredentialsAPI.read({
|
|
||||||
credential_type__id: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Credentials`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
inventory: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
JobTemplatesAPI.read({
|
|
||||||
inventory: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Job Templates`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () => WorkflowJobTemplatesAPI.read({ inventory: selected.id }),
|
|
||||||
label: i18n._(t`Workflow Job Template`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
inventorySource: (inventoryId, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () => {
|
|
||||||
try {
|
|
||||||
const { data } = await InventoriesAPI.updateSources(inventoryId);
|
|
||||||
return WorkflowJobTemplateNodesAPI.read({
|
|
||||||
unified_job_template: data[0].inventory_source,
|
|
||||||
});
|
|
||||||
} catch (err) {
|
|
||||||
throw new Error(err);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
label: i18n._(t`Workflow Job Template Node`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
organization: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
CredentialsAPI.read({
|
|
||||||
organization: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Credential`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
};
|
|
||||||
144
awx/ui_next/src/util/getRelatedResouceDeleteDetails.test.js
Normal file
144
awx/ui_next/src/util/getRelatedResouceDeleteDetails.test.js
Normal file
@@ -0,0 +1,144 @@
|
|||||||
|
import {
|
||||||
|
getRelatedResourceDeleteCounts,
|
||||||
|
relatedResourceDeleteRequests,
|
||||||
|
} from './getRelatedResourceDeleteDetails';
|
||||||
|
import {
|
||||||
|
InventoriesAPI,
|
||||||
|
InventorySourcesAPI,
|
||||||
|
JobTemplatesAPI,
|
||||||
|
ProjectsAPI,
|
||||||
|
WorkflowJobTemplatesAPI,
|
||||||
|
WorkflowJobTemplateNodesAPI,
|
||||||
|
CredentialsAPI,
|
||||||
|
} from '../api';
|
||||||
|
|
||||||
|
jest.mock('../api/models/Credentials');
|
||||||
|
jest.mock('../api/models/Inventories');
|
||||||
|
jest.mock('../api/models/InventorySources');
|
||||||
|
jest.mock('../api/models/JobTemplates');
|
||||||
|
jest.mock('../api/models/Projects');
|
||||||
|
jest.mock('../api/models/WorkflowJobTemplates');
|
||||||
|
jest.mock('../api/models/WorkflowJobTemplateNodes');
|
||||||
|
|
||||||
|
const i18n = {
|
||||||
|
_: key => {
|
||||||
|
if (key.values) {
|
||||||
|
Object.entries(key.values).forEach(([k, v]) => {
|
||||||
|
key.id = key.id.replace(new RegExp(`\\{${k}\\}`), v);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return key.id;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('delete details', () => {
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for credentials list', () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.credential({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(InventoriesAPI.read).toBeCalledWith({
|
||||||
|
insights_credential: 1,
|
||||||
|
});
|
||||||
|
expect(InventorySourcesAPI.read).toBeCalledWith({
|
||||||
|
credentials__id: 1,
|
||||||
|
});
|
||||||
|
expect(JobTemplatesAPI.read).toBeCalledWith({ credentials: 1 });
|
||||||
|
expect(ProjectsAPI.read).toBeCalledWith({ credentials: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for projects list', () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.project({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(WorkflowJobTemplatesAPI.read).toBeCalledWith({
|
||||||
|
credentials: 1,
|
||||||
|
});
|
||||||
|
expect(InventorySourcesAPI.read).toBeCalledWith({
|
||||||
|
credentials__id: 1,
|
||||||
|
});
|
||||||
|
expect(JobTemplatesAPI.read).toBeCalledWith({ credentials: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for templates list', () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.template({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(WorkflowJobTemplateNodesAPI.read).toBeCalledWith({
|
||||||
|
unified_job_template: 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for credential type list', () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.credentialType({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(CredentialsAPI.read).toBeCalledWith({
|
||||||
|
credential_type__id: 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for inventory list', () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.inventory({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(JobTemplatesAPI.read).toBeCalledWith({ inventory: 1 });
|
||||||
|
expect(WorkflowJobTemplatesAPI.read).toBeCalledWith({
|
||||||
|
inventory: 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for inventory source list', async () => {
|
||||||
|
InventoriesAPI.updateSources.mockResolvedValue({
|
||||||
|
data: [{ inventory_source: 2 }],
|
||||||
|
});
|
||||||
|
await getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.inventorySource(1, i18n)
|
||||||
|
);
|
||||||
|
expect(InventoriesAPI.updateSources).toBeCalledWith(1);
|
||||||
|
expect(WorkflowJobTemplateNodesAPI.read).toBeCalledWith({
|
||||||
|
unified_job_template: 2,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call api for organization list', async () => {
|
||||||
|
getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.organization({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(CredentialsAPI.read).toBeCalledWith({ organization: 1 });
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should call return error for inventory source list', async () => {
|
||||||
|
InventoriesAPI.updateSources.mockRejectedValue({
|
||||||
|
response: {
|
||||||
|
config: {
|
||||||
|
method: 'post',
|
||||||
|
url: '/api/v2/inventories/1/ad_hoc_commands',
|
||||||
|
},
|
||||||
|
data: 'An error occurred',
|
||||||
|
status: 403,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const { error } = await getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.inventorySource(1, i18n)
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(InventoriesAPI.updateSources).toBeCalledWith(1);
|
||||||
|
expect(error).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
test('should return proper results', async () => {
|
||||||
|
JobTemplatesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
ProjectsAPI.read.mockResolvedValue({ data: { count: 2 } });
|
||||||
|
InventoriesAPI.read.mockResolvedValue({ data: { count: 3 } });
|
||||||
|
InventorySourcesAPI.read.mockResolvedValue({ data: { count: 0 } });
|
||||||
|
|
||||||
|
const { results } = await getRelatedResourceDeleteCounts(
|
||||||
|
relatedResourceDeleteRequests.credential({ id: 1 }, i18n)
|
||||||
|
);
|
||||||
|
expect(results).toEqual({ Projects: 2, Inventories: 3 });
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -21,6 +21,7 @@ export async function getRelatedResourceDeleteCounts(requests) {
|
|||||||
const {
|
const {
|
||||||
data: { count },
|
data: { count },
|
||||||
} = await request();
|
} = await request();
|
||||||
|
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
results[label] = count;
|
results[label] = count;
|
||||||
hasCount = true;
|
hasCount = true;
|
||||||
@@ -40,7 +41,7 @@ export async function getRelatedResourceDeleteCounts(requests) {
|
|||||||
export const relatedResourceDeleteRequests = {
|
export const relatedResourceDeleteRequests = {
|
||||||
credential: (selected, i18n) => [
|
credential: (selected, i18n) => [
|
||||||
{
|
{
|
||||||
request: async () =>
|
request: () =>
|
||||||
JobTemplatesAPI.read({
|
JobTemplatesAPI.read({
|
||||||
credentials: selected.id,
|
credentials: selected.id,
|
||||||
}),
|
}),
|
||||||
@@ -66,37 +67,6 @@ export const relatedResourceDeleteRequests = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
project: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
JobTemplatesAPI.read({
|
|
||||||
credentials: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Job Templates`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () => WorkflowJobTemplatesAPI.read({ credentials: selected.id }),
|
|
||||||
label: i18n._(t`Workflow Job Templates`),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
request: () =>
|
|
||||||
InventorySourcesAPI.read({
|
|
||||||
credentials__id: selected.id,
|
|
||||||
}),
|
|
||||||
label: i18n._(t`Inventory Sources`),
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
template: (selected, i18n) => [
|
|
||||||
{
|
|
||||||
request: async () =>
|
|
||||||
WorkflowJobTemplateNodesAPI.read({
|
|
||||||
unified_job_template: selected.id,
|
|
||||||
}),
|
|
||||||
label: [i18n._(t`Workflow Job Template Node`)],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
|
|
||||||
credentialType: (selected, i18n) => [
|
credentialType: (selected, i18n) => [
|
||||||
{
|
{
|
||||||
request: async () =>
|
request: async () =>
|
||||||
@@ -137,6 +107,37 @@ export const relatedResourceDeleteRequests = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|
||||||
|
project: (selected, i18n) => [
|
||||||
|
{
|
||||||
|
request: () =>
|
||||||
|
JobTemplatesAPI.read({
|
||||||
|
credentials: selected.id,
|
||||||
|
}),
|
||||||
|
label: i18n._(t`Job Templates`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
request: () => WorkflowJobTemplatesAPI.read({ credentials: selected.id }),
|
||||||
|
label: i18n._(t`Workflow Job Templates`),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
request: () =>
|
||||||
|
InventorySourcesAPI.read({
|
||||||
|
credentials__id: selected.id,
|
||||||
|
}),
|
||||||
|
label: i18n._(t`Inventory Sources`),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
|
template: (selected, i18n) => [
|
||||||
|
{
|
||||||
|
request: async () =>
|
||||||
|
WorkflowJobTemplateNodesAPI.read({
|
||||||
|
unified_job_template: selected.id,
|
||||||
|
}),
|
||||||
|
label: [i18n._(t`Workflow Job Template Node`)],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
|
||||||
organization: (selected, i18n) => [
|
organization: (selected, i18n) => [
|
||||||
{
|
{
|
||||||
request: async () =>
|
request: async () =>
|
||||||
|
|||||||
Reference in New Issue
Block a user