mirror of
https://github.com/ZwareBear/awx.git
synced 2026-05-02 12:51:48 -05:00
365 lines
8.9 KiB
JavaScript
365 lines
8.9 KiB
JavaScript
import React from 'react';
|
|
import { act } from 'react-dom/test-utils';
|
|
import { createMemoryHistory } from 'history';
|
|
import { sleep } from '../../../../testUtils/testUtils';
|
|
import {
|
|
mountWithContexts,
|
|
waitForElement,
|
|
} from '../../../../testUtils/enzymeHelpers';
|
|
import {
|
|
CredentialsAPI,
|
|
CredentialTypesAPI,
|
|
JobTemplatesAPI,
|
|
LabelsAPI,
|
|
ProjectsAPI,
|
|
InventoriesAPI,
|
|
} from '../../../api';
|
|
import JobTemplateEdit from './JobTemplateEdit';
|
|
|
|
jest.mock('../../../api');
|
|
|
|
const mockJobTemplate = {
|
|
allow_callbacks: false,
|
|
allow_simultaneous: false,
|
|
ask_scm_branch_on_launch: false,
|
|
ask_diff_mode_on_launch: false,
|
|
ask_variables_on_launch: false,
|
|
ask_limit_on_launch: false,
|
|
ask_tags_on_launch: false,
|
|
ask_skip_tags_on_launch: false,
|
|
ask_job_type_on_launch: false,
|
|
ask_verbosity_on_launch: false,
|
|
ask_inventory_on_launch: false,
|
|
ask_credential_on_launch: false,
|
|
become_enabled: false,
|
|
description: 'Bar',
|
|
diff_mode: false,
|
|
extra_vars: '---',
|
|
forks: 0,
|
|
host_config_key: '',
|
|
id: 1,
|
|
inventory: 2,
|
|
job_slice_count: 1,
|
|
job_tags: '',
|
|
job_type: 'run',
|
|
limit: '',
|
|
name: 'Foo',
|
|
playbook: 'Baz',
|
|
project: 3,
|
|
scm_branch: '',
|
|
skip_tags: '',
|
|
summary_fields: {
|
|
user_capabilities: {
|
|
edit: true,
|
|
},
|
|
labels: {
|
|
results: [
|
|
{ name: 'Sushi', id: 1 },
|
|
{ name: 'Major', id: 2 },
|
|
],
|
|
},
|
|
inventory: {
|
|
id: 2,
|
|
organization_id: 1,
|
|
},
|
|
credentials: [
|
|
{ id: 1, kind: 'cloud', name: 'Foo' },
|
|
{ id: 2, kind: 'ssh', name: 'Bar' },
|
|
],
|
|
project: {
|
|
id: 3,
|
|
name: 'Boo',
|
|
},
|
|
},
|
|
timeout: 0,
|
|
type: 'job_template',
|
|
use_fact_cache: false,
|
|
verbosity: '0',
|
|
webhook_credential: null,
|
|
webhook_key: 'webhook Key',
|
|
webhook_service: 'gitlab',
|
|
related: {
|
|
webhook_receiver: '/api/v2/workflow_job_templates/57/gitlab/',
|
|
},
|
|
};
|
|
|
|
const mockRelatedCredentials = {
|
|
count: 2,
|
|
next: null,
|
|
previous: null,
|
|
results: [
|
|
{
|
|
id: 1,
|
|
type: 'credential',
|
|
url: '/api/v2/credentials/1/',
|
|
related: {},
|
|
summary_fields: {
|
|
user_capabilities: {
|
|
edit: true,
|
|
delete: true,
|
|
copy: true,
|
|
use: true,
|
|
},
|
|
},
|
|
created: '2016-08-24T20:20:44.411607Z',
|
|
modified: '2019-06-18T16:14:00.109434Z',
|
|
name: 'Test Vault Credential',
|
|
description: 'Credential with access to vaulted data.',
|
|
organization: 1,
|
|
credential_type: 3,
|
|
inputs: { vault_password: '$encrypted$' },
|
|
},
|
|
{
|
|
id: 2,
|
|
type: 'credential',
|
|
url: '/api/v2/credentials/2/',
|
|
related: {},
|
|
summary_fields: {
|
|
user_capabilities: {
|
|
edit: true,
|
|
delete: true,
|
|
copy: true,
|
|
use: true,
|
|
},
|
|
},
|
|
created: '2016-08-24T20:20:44.411607Z',
|
|
modified: '2017-07-11T15:58:39.103659Z',
|
|
name: 'Test Machine Credential',
|
|
description: 'Credential with access to internal machines.',
|
|
organization: 1,
|
|
credential_type: 1,
|
|
inputs: { ssh_key_data: '$encrypted$' },
|
|
},
|
|
],
|
|
};
|
|
|
|
const mockRelatedProjectPlaybooks = [
|
|
'check.yml',
|
|
'debug-50.yml',
|
|
'debug.yml',
|
|
'debug2.yml',
|
|
'debug_extra_vars.yml',
|
|
'dynamic_inventory.yml',
|
|
'environ_test.yml',
|
|
'fail_unless.yml',
|
|
'pass_unless.yml',
|
|
'pause.yml',
|
|
'ping-20.yml',
|
|
'ping.yml',
|
|
'setfact_50.yml',
|
|
'vault.yml',
|
|
];
|
|
|
|
const mockInstanceGroups = [
|
|
{
|
|
id: 1,
|
|
type: 'instance_group',
|
|
url: '/api/v2/instance_groups/1/',
|
|
related: {
|
|
jobs: '/api/v2/instance_groups/1/jobs/',
|
|
instances: '/api/v2/instance_groups/1/instances/',
|
|
},
|
|
name: 'tower',
|
|
capacity: 59,
|
|
committed_capacity: 0,
|
|
consumed_capacity: 0,
|
|
percent_capacity_remaining: 100.0,
|
|
jobs_running: 0,
|
|
jobs_total: 3,
|
|
instances: 1,
|
|
controller: null,
|
|
is_controller: false,
|
|
is_isolated: false,
|
|
policy_instance_percentage: 100,
|
|
policy_instance_minimum: 0,
|
|
policy_instance_list: [],
|
|
},
|
|
];
|
|
|
|
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
|
data: mockRelatedCredentials,
|
|
});
|
|
ProjectsAPI.readPlaybooks.mockResolvedValue({
|
|
data: mockRelatedProjectPlaybooks,
|
|
});
|
|
InventoriesAPI.readOptions.mockResolvedValue({
|
|
data: { actions: { GET: {}, POST: {} } },
|
|
});
|
|
ProjectsAPI.readOptions.mockResolvedValue({
|
|
data: { actions: { GET: {}, POST: {} } },
|
|
});
|
|
LabelsAPI.read.mockResolvedValue({ data: { results: [] } });
|
|
CredentialsAPI.read.mockResolvedValue({
|
|
data: {
|
|
results: [],
|
|
count: 0,
|
|
},
|
|
});
|
|
CredentialTypesAPI.loadAllTypes.mockResolvedValue([]);
|
|
|
|
describe('<JobTemplateEdit />', () => {
|
|
beforeEach(() => {
|
|
LabelsAPI.read.mockResolvedValue({ data: { results: [] } });
|
|
JobTemplatesAPI.readCredentials.mockResolvedValue({
|
|
data: mockRelatedCredentials,
|
|
});
|
|
JobTemplatesAPI.readInstanceGroups.mockReturnValue({
|
|
data: { results: mockInstanceGroups },
|
|
});
|
|
ProjectsAPI.readDetail.mockReturnValue({
|
|
id: 1,
|
|
allow_override: true,
|
|
name: 'foo',
|
|
});
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.clearAllMocks();
|
|
});
|
|
|
|
test('initially renders successfully', async () => {
|
|
let wrapper;
|
|
await act(async () => {
|
|
wrapper = mountWithContexts(
|
|
<JobTemplateEdit template={mockJobTemplate} />
|
|
);
|
|
});
|
|
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
|
});
|
|
|
|
test('handleSubmit should call api update', async () => {
|
|
let wrapper;
|
|
await act(async () => {
|
|
wrapper = mountWithContexts(
|
|
<JobTemplateEdit template={mockJobTemplate} />
|
|
);
|
|
});
|
|
const updatedTemplateData = {
|
|
job_type: 'check',
|
|
name: 'new name',
|
|
inventory: 1,
|
|
};
|
|
const labels = [
|
|
{ id: 3, name: 'Foo' },
|
|
{ id: 4, name: 'Bar' },
|
|
{ id: 5, name: 'Maple' },
|
|
{ id: 6, name: 'Tree' },
|
|
];
|
|
await waitForElement(wrapper, 'EmptyStateBody', el => el.length === 0);
|
|
act(() => {
|
|
wrapper.find('input#template-name').simulate('change', {
|
|
target: { value: 'new name', name: 'name' },
|
|
});
|
|
wrapper.find('AnsibleSelect#template-job-type').prop('onChange')(
|
|
null,
|
|
'check'
|
|
);
|
|
wrapper.find('LabelSelect').invoke('onChange')(labels);
|
|
});
|
|
wrapper.update();
|
|
act(() => {
|
|
wrapper.find('InventoryLookup').invoke('onChange')({
|
|
id: 1,
|
|
organization: 1,
|
|
});
|
|
});
|
|
wrapper.update();
|
|
await act(async () => {
|
|
wrapper.find('button[aria-label="Save"]').simulate('click');
|
|
});
|
|
await sleep(0);
|
|
|
|
const expected = {
|
|
...mockJobTemplate,
|
|
project: mockJobTemplate.project,
|
|
...updatedTemplateData,
|
|
};
|
|
delete expected.summary_fields;
|
|
delete expected.id;
|
|
delete expected.type;
|
|
delete expected.related;
|
|
delete expected.webhook_key;
|
|
delete expected.webhook_url;
|
|
expect(JobTemplatesAPI.update).toHaveBeenCalledWith(1, expected);
|
|
expect(JobTemplatesAPI.disassociateLabel).toHaveBeenCalledTimes(2);
|
|
expect(JobTemplatesAPI.associateLabel).toHaveBeenCalledTimes(4);
|
|
});
|
|
|
|
test('should navigate to job template detail when cancel is clicked', async () => {
|
|
const history = createMemoryHistory({});
|
|
let wrapper;
|
|
await act(async () => {
|
|
wrapper = mountWithContexts(
|
|
<JobTemplateEdit template={mockJobTemplate} />,
|
|
{ context: { router: { history } } }
|
|
);
|
|
});
|
|
const cancelButton = await waitForElement(
|
|
wrapper,
|
|
'button[aria-label="Cancel"]',
|
|
e => e.length === 1
|
|
);
|
|
await act(async () => {
|
|
cancelButton.prop('onClick')();
|
|
});
|
|
expect(history.location.pathname).toEqual(
|
|
'/templates/job_template/1/details'
|
|
);
|
|
});
|
|
test('should not call ProjectsAPI.readPlaybooks if there is no project', async () => {
|
|
const history = createMemoryHistory({});
|
|
const noProjectTemplate = {
|
|
id: 1,
|
|
name: 'Foo',
|
|
description: 'Bar',
|
|
job_type: 'run',
|
|
inventory: 2,
|
|
playbook: 'Baz',
|
|
type: 'job_template',
|
|
forks: 0,
|
|
limit: '',
|
|
verbosity: '0',
|
|
job_slice_count: 1,
|
|
timeout: 0,
|
|
job_tags: '',
|
|
skip_tags: '',
|
|
diff_mode: false,
|
|
allow_callbacks: false,
|
|
allow_simultaneous: false,
|
|
use_fact_cache: false,
|
|
host_config_key: '',
|
|
summary_fields: {
|
|
user_capabilities: {
|
|
edit: true,
|
|
},
|
|
labels: {
|
|
results: [
|
|
{ name: 'Sushi', id: 1 },
|
|
{ name: 'Major', id: 2 },
|
|
],
|
|
},
|
|
inventory: {
|
|
id: 2,
|
|
organization_id: 1,
|
|
},
|
|
credentials: [
|
|
{ id: 1, kind: 'cloud', name: 'Foo' },
|
|
{ id: 2, kind: 'ssh', name: 'Bar' },
|
|
],
|
|
webhook_credential: {
|
|
id: 7,
|
|
name: 'webhook credential',
|
|
kind: 'github_token',
|
|
credential_type_id: 12,
|
|
},
|
|
},
|
|
};
|
|
await act(async () =>
|
|
mountWithContexts(<JobTemplateEdit template={noProjectTemplate} />, {
|
|
context: { router: { history } },
|
|
})
|
|
);
|
|
expect(ProjectsAPI.readPlaybooks).not.toBeCalled();
|
|
});
|
|
});
|