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,