From afc1f856684b3584e30589af79ec199045478236 Mon Sep 17 00:00:00 2001 From: Marliana Lara Date: Thu, 23 Jan 2020 13:59:20 -0500 Subject: [PATCH] Update job template detail unit tests --- .../JobTemplateDetail.test.jsx | 234 ++++++++---------- .../Template/JobTemplateDetail/index.js | 5 +- .../Template/shared/data.job_template.json | 28 ++- 3 files changed, 128 insertions(+), 139 deletions(-) diff --git a/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx b/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx index 7ae6b0319c..6be3c3af47 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx +++ b/awx/ui_next/src/screens/Template/JobTemplateDetail/JobTemplateDetail.test.jsx @@ -1,161 +1,141 @@ import React from 'react'; +import { act } from 'react-dom/test-utils'; import { mountWithContexts, waitForElement } from '@testUtils/enzymeHelpers'; -import JobTemplateDetail, { _JobTemplateDetail } from './JobTemplateDetail'; +import JobTemplateDetail from './JobTemplateDetail'; import { JobTemplatesAPI } from '@api'; +import mockTemplate from '../shared/data.job_template.json'; jest.mock('@api'); +const mockInstanceGroups = { + count: 5, + data: { + results: [{ id: 1, name: 'IG1' }, { id: 2, name: 'IG2' }], + }, +}; + describe('', () => { - const template = { - forks: 1, - host_config_key: 'ssh', - name: 'Temp 1', - job_type: 'run', - inventory: 1, - limit: '1', - project: 7, - playbook: '', - id: 1, - verbosity: 1, - summary_fields: { - user_capabilities: { edit: true }, - created_by: { id: 1, username: 'Joe' }, - modified_by: { id: 1, username: 'Joe' }, - credentials: [ - { id: 1, kind: 'ssh', name: 'Credential 1' }, - { id: 2, kind: 'awx', name: 'Credential 2' }, - ], - inventory: { name: 'Inventory' }, - project: { name: 'Project' }, - }, - created: '2020-04-25T01:23:45.678901Z', - modified: '2020-04-25T01:23:45.678901Z', - }; + let wrapper; - const mockInstanceGroups = { - count: 5, - data: { - results: [{ id: 1, name: 'IG1' }, { id: 2, name: 'IG2' }], - }, - }; - - const readInstanceGroups = jest.spyOn( - _JobTemplateDetail.prototype, - 'readInstanceGroups' - ); - - beforeEach(() => { + beforeEach(async () => { JobTemplatesAPI.readInstanceGroups.mockResolvedValue(mockInstanceGroups); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); }); afterEach(() => { jest.clearAllMocks(); }); - test('Can load with missing summary fields', async () => { - const mockTemplate = { ...template }; - mockTemplate.summary_fields = { user_capabilities: {} }; - - const wrapper = mountWithContexts( - - ); + test('should render successfully with missing summary fields', async () => { + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentLoading', el => el.length === 0); await waitForElement( wrapper, - 'Detail[label="Description"]', + 'Detail[label="Name"]', el => el.length === 1 ); }); - test('When component mounts API is called to get instance groups', async done => { - const wrapper = mountWithContexts( - - ); - await waitForElement( - wrapper, - 'JobTemplateDetail', - el => el.state('hasContentLoading') === true - ); - expect(readInstanceGroups).toHaveBeenCalled(); - await waitForElement( - wrapper, - 'JobTemplateDetail', - el => el.state('hasContentLoading') === false - ); + test('should request instance groups from api', async () => { expect(JobTemplatesAPI.readInstanceGroups).toHaveBeenCalledTimes(1); - done(); }); - test('Edit button is absent when user does not have edit privilege', async done => { - const regularUser = { - forks: 1, - host_config_key: 'ssh', - name: 'Temp 1', - job_tags: 'cookies,pizza', - job_type: 'run', - inventory: 1, - limit: '1', - project: 7, - playbook: '', - id: 1, - verbosity: 0, - created_by: 'Alex', - skip_tags: 'coffe,tea', - summary_fields: { - user_capabilities: { edit: false }, - created_by: { id: 1, username: 'Joe' }, - modified_by: { id: 1, username: 'Joe' }, - inventory: { name: 'Inventory' }, - project: { name: 'Project' }, - labels: { count: 1, results: [{ name: 'Label', id: 1 }] }, - }, - created: '2020-04-25T01:23:45.678901Z', - modified: '2020-04-25T01:23:45.678901Z', - }; - const wrapper = mountWithContexts( - - ); - const jobTemplateDetail = wrapper.find('JobTemplateDetail'); - const editButton = jobTemplateDetail.find('button[aria-label="Edit"]'); - - jobTemplateDetail.setState({ - instanceGroups: mockInstanceGroups, - hasContentLoading: false, - contentError: false, + test('should hide edit button for users without edit permission', async () => { + JobTemplatesAPI.readInstanceGroups.mockResolvedValue({ data: {} }); + await act(async () => { + wrapper = mountWithContexts( + + ); }); - expect(editButton.length).toBe(0); - done(); + expect(wrapper.find('button[aria-label="Edit"]').length).toBe(0); }); - test('should render CredentialChip', () => { - template.summary_fields.credentials = [{ id: 1, name: 'cred', kind: null }]; - const wrapper = mountWithContexts( - - ); - wrapper.find('JobTemplateDetail').setState({ - instanceGroups: mockInstanceGroups, - hasContentLoading: false, - contentError: false, + test('should render credential chips', () => { + const chips = wrapper.find('CredentialChip'); + expect(chips).toHaveLength(2); + chips.forEach((chip, id) => { + expect(chip.prop('credential')).toEqual( + mockTemplate.summary_fields.credentials[id] + ); }); - - const chip = wrapper.find('CredentialChip'); - expect(chip).toHaveLength(1); - expect(chip.prop('credential')).toEqual( - template.summary_fields.credentials[0] - ); }); + test('should render SCM_Branch', async () => { - const mockTemplate = { ...template }; - mockTemplate.scm_branch = 'Foo branch'; - - const wrapper = mountWithContexts( - - ); - await waitForElement( - wrapper, - 'JobTemplateDetail', - el => el.state('hasContentLoading') === false - ); const SCMBranch = wrapper.find('Detail[label="SCM Branch"]'); expect(SCMBranch.prop('value')).toBe('Foo branch'); }); + + test('should show content error for failed instance group fetch', async () => { + JobTemplatesAPI.readInstanceGroups.mockImplementationOnce(() => + Promise.reject(new Error()) + ); + await act(async () => { + wrapper = mountWithContexts( + + ); + }); + await waitForElement(wrapper, 'ContentError', el => el.length === 1); + }); + + test('expected api calls are made for delete', async () => { + await act(async () => { + wrapper.find('DeleteButton').invoke('onConfirm')(); + }); + expect(JobTemplatesAPI.destroy).toHaveBeenCalledTimes(1); + }); + + test('Error dialog shown for failed deletion', async () => { + JobTemplatesAPI.destroy.mockImplementationOnce(() => + Promise.reject(new Error()) + ); + await act(async () => { + wrapper.find('DeleteButton').invoke('onConfirm')(); + }); + await waitForElement( + wrapper, + 'Modal[title="Error!"]', + el => el.length === 1 + ); + await act(async () => { + wrapper.find('Modal[title="Error!"]').invoke('onClose')(); + }); + await waitForElement( + wrapper, + 'Modal[title="Error!"]', + el => el.length === 0 + ); + }); }); diff --git a/awx/ui_next/src/screens/Template/JobTemplateDetail/index.js b/awx/ui_next/src/screens/Template/JobTemplateDetail/index.js index fedf6e28d5..c07a99c058 100644 --- a/awx/ui_next/src/screens/Template/JobTemplateDetail/index.js +++ b/awx/ui_next/src/screens/Template/JobTemplateDetail/index.js @@ -1,4 +1 @@ -import JobTemplateDetail from './JobTemplateDetail'; - -export { JobTemplateDetail as _JobTemplateDetail }; -export default JobTemplateDetail; +export { default } from './JobTemplateDetail'; diff --git a/awx/ui_next/src/screens/Template/shared/data.job_template.json b/awx/ui_next/src/screens/Template/shared/data.job_template.json index a8f9da56a7..2fc2e460d7 100644 --- a/awx/ui_next/src/screens/Template/shared/data.job_template.json +++ b/awx/ui_next/src/screens/Template/shared/data.job_template.json @@ -101,9 +101,14 @@ "copy": true }, "labels": { - "count": 0, - "results": [] - }, + "count": 1, + "results": [ + { + "id": 91, + "name": "L_91o2" + } + ] + }, "survey": { "title": "", "description": "" @@ -117,7 +122,14 @@ } ], "extra_credentials": [], - "credentials": [] + "credentials": [ + { + "id": 1, "kind": "ssh" , "name": "Credential 1" + }, + { + "id": 2, "kind": "awx" , "name": "Credential 2" + } + ] }, "created": "2019-09-30T16:18:34.564820Z", "modified": "2019-10-01T14:47:31.818431Z", @@ -127,17 +139,17 @@ "inventory": 1, "project": 6, "playbook": "ping.yml", - "scm_branch": "", + "scm_branch": "Foo branch", "forks": 0, "limit": "", "verbosity": 0, "extra_vars": "", - "job_tags": "", + "job_tags": "T_100,T_200", "force_handlers": false, - "skip_tags": "", + "skip_tags": "S_100,S_200", "start_at_task": "", "timeout": 0, - "use_fact_cache": false, + "use_fact_cache": true, "last_job_run": "2019-10-01T14:34:35.142483Z", "last_job_failed": false, "next_job_run": null,