diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.test.jsx new file mode 100644 index 0000000000..d09cf92ae1 --- /dev/null +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/InventorySourcesList.test.jsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { InventorySourcesAPI } from '@api'; +import InventorySourcesList from './InventorySourcesList'; + +jest.mock('@api/models/InventorySources'); + +const nodeResource = { + id: 1, + name: 'Test Inventory Source', + unified_job_type: 'workflow_approval', +}; +const onUpdateNodeResource = jest.fn(); + +describe('InventorySourcesList', () => { + let wrapper; + afterEach(() => { + wrapper.unmount(); + }); + test('Row selected when nodeResource id matches row id and clicking new row makes expected callback', async () => { + InventorySourcesAPI.read.mockResolvedValueOnce({ + data: { + count: 2, + results: [ + { + id: 1, + name: 'Test Inventory Source', + type: 'inventory_source', + url: '/api/v2/inventory_sources/1', + }, + { + id: 2, + name: 'Test Inventory Source 2', + type: 'inventory_source', + url: '/api/v2/inventory_sources/2', + }, + ], + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect( + wrapper.find('CheckboxListItem[name="Test Inventory Source"]').props() + .isSelected + ).toBe(true); + expect( + wrapper.find('CheckboxListItem[name="Test Inventory Source 2"]').props() + .isSelected + ).toBe(false); + wrapper + .find('CheckboxListItem[name="Test Inventory Source 2"]') + .simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 2, + name: 'Test Inventory Source 2', + type: 'inventory_source', + url: '/api/v2/inventory_sources/2', + }); + }); + test('Error shown when read() request errors', async () => { + InventorySourcesAPI.read.mockRejectedValue(new Error()); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('ErrorDetail').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.test.jsx new file mode 100644 index 0000000000..d5d8097313 --- /dev/null +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/JobTemplatesList.test.jsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { JobTemplatesAPI } from '@api'; +import JobTemplatesList from './JobTemplatesList'; + +jest.mock('@api/models/JobTemplates'); + +const nodeResource = { + id: 1, + name: 'Test Job Template', + unified_job_type: 'job', +}; +const onUpdateNodeResource = jest.fn(); + +describe('JobTemplatesList', () => { + let wrapper; + afterEach(() => { + wrapper.unmount(); + }); + test('Row selected when nodeResource id matches row id and clicking new row makes expected callback', async () => { + JobTemplatesAPI.read.mockResolvedValueOnce({ + data: { + count: 2, + results: [ + { + id: 1, + name: 'Test Job Template', + type: 'job_template', + url: '/api/v2/job_templates/1', + }, + { + id: 2, + name: 'Test Job Template 2', + type: 'job_template', + url: '/api/v2/job_templates/2', + }, + ], + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect( + wrapper.find('CheckboxListItem[name="Test Job Template"]').props() + .isSelected + ).toBe(true); + expect( + wrapper.find('CheckboxListItem[name="Test Job Template 2"]').props() + .isSelected + ).toBe(false); + wrapper + .find('CheckboxListItem[name="Test Job Template 2"]') + .simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 2, + name: 'Test Job Template 2', + type: 'job_template', + url: '/api/v2/job_templates/2', + }); + }); + test('Error shown when read() request errors', async () => { + JobTemplatesAPI.read.mockRejectedValue(new Error()); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('ErrorDetail').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.jsx new file mode 100644 index 0000000000..c4a1306fb4 --- /dev/null +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/NodeTypeStep.test.jsx @@ -0,0 +1,239 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { + InventorySourcesAPI, + JobTemplatesAPI, + ProjectsAPI, + WorkflowJobTemplatesAPI, +} from '@api'; +import NodeTypeStep from './NodeTypeStep'; + +jest.mock('@api/models/InventorySources'); +jest.mock('@api/models/JobTemplates'); +jest.mock('@api/models/Projects'); +jest.mock('@api/models/WorkflowJobTemplates'); + +const onUpdateDescription = jest.fn(); +const onUpdateName = jest.fn(); +const onUpdateNodeResource = jest.fn(); +const onUpdateNodeType = jest.fn(); +const onUpdateTimeout = jest.fn(); + +describe('NodeTypeStep', () => { + beforeAll(() => { + JobTemplatesAPI.read.mockResolvedValue({ + data: { + count: 1, + results: [ + { + id: 1, + name: 'Test Job Template', + type: 'job_template', + url: '/api/v2/job_templates/1', + }, + ], + }, + }); + ProjectsAPI.read.mockResolvedValue({ + data: { + count: 1, + results: [ + { + id: 1, + name: 'Test Project', + type: 'project', + url: '/api/v2/projects/1', + }, + ], + }, + }); + InventorySourcesAPI.read.mockResolvedValue({ + data: { + count: 1, + results: [ + { + id: 1, + name: 'Test Inventory Source', + type: 'inventory_source', + url: '/api/v2/inventory_sources/1', + }, + ], + }, + }); + WorkflowJobTemplatesAPI.read.mockResolvedValue({ + data: { + count: 1, + results: [ + { + id: 1, + name: 'Test Workflow Job Template', + type: 'workflow_job_template', + url: '/api/v2/workflow_job_templates/1', + }, + ], + }, + }); + }); + afterAll(() => { + jest.clearAllMocks(); + }); + test('It shows the job template list by default', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('value')).toBe('job_template'); + expect(wrapper.find('JobTemplatesList').length).toBe(1); + wrapper.find('DataListRadio').simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 1, + name: 'Test Job Template', + type: 'job_template', + url: '/api/v2/job_templates/1', + }); + }); + test('It shows the project list when node type is project sync', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('value')).toBe('project_sync'); + expect(wrapper.find('ProjectsList').length).toBe(1); + wrapper.find('DataListRadio').simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 1, + name: 'Test Project', + type: 'project', + url: '/api/v2/projects/1', + }); + }); + test('It shows the inventory source list when node type is inventory source sync', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('value')).toBe( + 'inventory_source_sync' + ); + expect(wrapper.find('InventorySourcesList').length).toBe(1); + wrapper.find('DataListRadio').simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 1, + name: 'Test Inventory Source', + type: 'inventory_source', + url: '/api/v2/inventory_sources/1', + }); + }); + test('It shows the workflow job template list when node type is workflow job template', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('value')).toBe( + 'workflow_job_template' + ); + expect(wrapper.find('WorkflowJobTemplatesList').length).toBe(1); + wrapper.find('DataListRadio').simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 1, + name: 'Test Workflow Job Template', + type: 'workflow_job_template', + url: '/api/v2/workflow_job_templates/1', + }); + }); + test('It shows the approval form fields when node type is approval', async () => { + let wrapper; + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('AnsibleSelect').prop('value')).toBe('approval'); + expect(wrapper.find('input#approval-name').length).toBe(1); + expect(wrapper.find('input#approval-description').length).toBe(1); + expect(wrapper.find('input#approval-timeout-minutes').length).toBe(1); + expect(wrapper.find('input#approval-timeout-seconds').length).toBe(1); + + await act(async () => { + wrapper.find('input#approval-name').simulate('change', { + target: { value: 'Test Approval', name: 'name' }, + }); + }); + + expect(onUpdateName).toHaveBeenCalledWith('Test Approval'); + + await act(async () => { + wrapper.find('input#approval-description').simulate('change', { + target: { value: 'Test Approval Description', name: 'description' }, + }); + }); + + expect(onUpdateDescription).toHaveBeenCalledWith( + 'Test Approval Description' + ); + + await act(async () => { + wrapper.find('input#approval-timeout-minutes').simulate('change', { + target: { value: 5, name: 'timeoutMinutes' }, + }); + }); + + expect(onUpdateTimeout).toHaveBeenCalledWith(300); + + await act(async () => { + wrapper.find('input#approval-timeout-seconds').simulate('change', { + target: { value: 30, name: 'timeoutSeconds' }, + }); + }); + + expect(onUpdateTimeout).toHaveBeenCalledWith(330); + }); +}); diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.test.jsx new file mode 100644 index 0000000000..be4b588ce2 --- /dev/null +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/ProjectsList.test.jsx @@ -0,0 +1,77 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { ProjectsAPI } from '@api'; +import ProjectsList from './ProjectsList'; + +jest.mock('@api/models/Projects'); + +const nodeResource = { + id: 1, + name: 'Test Project', + unified_job_type: 'project_update', +}; +const onUpdateNodeResource = jest.fn(); + +describe('ProjectsList', () => { + let wrapper; + afterEach(() => { + wrapper.unmount(); + }); + test('Row selected when nodeResource id matches row id and clicking new row makes expected callback', async () => { + ProjectsAPI.read.mockResolvedValueOnce({ + data: { + count: 2, + results: [ + { + id: 1, + name: 'Test Project', + type: 'project', + url: '/api/v2/projects/1', + }, + { + id: 2, + name: 'Test Project 2', + type: 'project', + url: '/api/v2/projects/2', + }, + ], + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect( + wrapper.find('CheckboxListItem[name="Test Project"]').props().isSelected + ).toBe(true); + expect( + wrapper.find('CheckboxListItem[name="Test Project 2"]').props().isSelected + ).toBe(false); + wrapper.find('CheckboxListItem[name="Test Project 2"]').simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 2, + name: 'Test Project 2', + type: 'project', + url: '/api/v2/projects/2', + }); + }); + test('Error shown when read() request errors', async () => { + ProjectsAPI.read.mockRejectedValue(new Error()); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('ErrorDetail').length).toBe(1); + }); +}); diff --git a/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.test.jsx b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.test.jsx new file mode 100644 index 0000000000..69b63dd7d9 --- /dev/null +++ b/awx/ui_next/src/screens/Template/WorkflowJobTemplateVisualizer/Modals/NodeModals/NodeTypeStep/WorkflowJobTemplatesList.test.jsx @@ -0,0 +1,83 @@ +import React from 'react'; +import { act } from 'react-dom/test-utils'; +import { mountWithContexts } from '@testUtils/enzymeHelpers'; +import { WorkflowJobTemplatesAPI } from '@api'; +import WorkflowJobTemplatesList from './WorkflowJobTemplatesList'; + +jest.mock('@api/models/WorkflowJobTemplates'); + +const nodeResource = { + id: 1, + name: 'Test Workflow Job Template', + unified_job_type: 'workflow_job', +}; +const onUpdateNodeResource = jest.fn(); + +describe('WorkflowJobTemplatesList', () => { + let wrapper; + afterEach(() => { + wrapper.unmount(); + }); + test('Row selected when nodeResource id matches row id and clicking new row makes expected callback', async () => { + WorkflowJobTemplatesAPI.read.mockResolvedValueOnce({ + data: { + count: 2, + results: [ + { + id: 1, + name: 'Test Workflow Job Template', + type: 'workflow_job_template', + url: '/api/v2/workflow_job_templates/1', + }, + { + id: 2, + name: 'Test Workflow Job Template 2', + type: 'workflow_job_template', + url: '/api/v2/workflow_job_templates/2', + }, + ], + }, + }); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect( + wrapper + .find('CheckboxListItem[name="Test Workflow Job Template"]') + .props().isSelected + ).toBe(true); + expect( + wrapper + .find('CheckboxListItem[name="Test Workflow Job Template 2"]') + .props().isSelected + ).toBe(false); + wrapper + .find('CheckboxListItem[name="Test Workflow Job Template 2"]') + .simulate('click'); + expect(onUpdateNodeResource).toHaveBeenCalledWith({ + id: 2, + name: 'Test Workflow Job Template 2', + type: 'workflow_job_template', + url: '/api/v2/workflow_job_templates/2', + }); + }); + test('Error shown when read() request errors', async () => { + WorkflowJobTemplatesAPI.read.mockRejectedValue(new Error()); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + wrapper.update(); + expect(wrapper.find('ErrorDetail').length).toBe(1); + }); +});