mirror of
https://github.com/ansible/awx.git
synced 2026-01-20 06:01:25 -03:30
Merge pull request #712 from jakemcdermott/gcp-service-file
add input field for gcp service account json file
This commit is contained in:
commit
96c66b1e20
@ -1,4 +1,4 @@
|
||||
function AddCredentialsController (models, $state, strings) {
|
||||
function AddCredentialsController (models, $state, $scope, strings, componentsStrings) {
|
||||
const vm = this || {};
|
||||
|
||||
const { me, credential, credentialType, organization } = models;
|
||||
@ -28,11 +28,27 @@ function AddCredentialsController (models, $state, strings) {
|
||||
vm.form.credential_type._model = credentialType;
|
||||
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
||||
|
||||
const gceFileInputSchema = {
|
||||
id: 'gce_service_account_key',
|
||||
type: 'file',
|
||||
label: strings.get('inputs.GCE_FILE_INPUT_LABEL'),
|
||||
help_text: strings.get('inputs.GCE_FILE_INPUT_HELP_TEXT'),
|
||||
};
|
||||
|
||||
let gceFileInputPreEditValues;
|
||||
|
||||
vm.form.inputs = {
|
||||
_get: () => {
|
||||
credentialType.mergeInputProperties();
|
||||
|
||||
return credentialType.get('inputs.fields');
|
||||
const fields = credentialType.get('inputs.fields');
|
||||
|
||||
if (credentialType.get('name') === 'Google Compute Engine') {
|
||||
fields.splice(2, 0, gceFileInputSchema);
|
||||
$scope.$watch(`vm.form.${gceFileInputSchema.id}._value`, vm.gceOnFileInputChanged);
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
_source: vm.form.credential_type,
|
||||
_reference: 'vm.form.inputs',
|
||||
@ -42,18 +58,66 @@ function AddCredentialsController (models, $state, strings) {
|
||||
vm.form.save = data => {
|
||||
data.user = me.get('id');
|
||||
|
||||
delete data.inputs[gceFileInputSchema.id];
|
||||
|
||||
return credential.request('post', { data });
|
||||
};
|
||||
|
||||
vm.form.onSaveSuccess = res => {
|
||||
$state.go('credentials.edit', { credential_id: res.data.id }, { reload: true });
|
||||
};
|
||||
|
||||
vm.gceOnFileInputChanged = (value, oldValue) => {
|
||||
if (value === oldValue) return;
|
||||
|
||||
const gceFileIsLoaded = !!value;
|
||||
const gceFileInputState = vm.form[gceFileInputSchema.id];
|
||||
const { obj, error } = vm.gceParseFileInput(value);
|
||||
|
||||
gceFileInputState._isValid = !error;
|
||||
gceFileInputState._message = error ? componentsStrings.get('message.INVALID_INPUT') : '';
|
||||
|
||||
vm.form.project._disabled = gceFileIsLoaded;
|
||||
vm.form.username._disabled = gceFileIsLoaded;
|
||||
vm.form.ssh_key_data._disabled = gceFileIsLoaded;
|
||||
vm.form.ssh_key_data._displayHint = !vm.form.ssh_key_data._disabled;
|
||||
|
||||
if (gceFileIsLoaded) {
|
||||
gceFileInputPreEditValues = Object.assign({}, {
|
||||
project: vm.form.project._value,
|
||||
ssh_key_data: vm.form.ssh_key_data._value,
|
||||
username: vm.form.username._value
|
||||
});
|
||||
vm.form.project._value = _.get(obj, 'project_id', '');
|
||||
vm.form.ssh_key_data._value = _.get(obj, 'private_key', '');
|
||||
vm.form.username._value = _.get(obj, 'client_email', '');
|
||||
} else {
|
||||
vm.form.project._value = gceFileInputPreEditValues.project;
|
||||
vm.form.ssh_key_data._value = gceFileInputPreEditValues.ssh_key_data;
|
||||
vm.form.username._value = gceFileInputPreEditValues.username;
|
||||
}
|
||||
};
|
||||
|
||||
vm.gceParseFileInput = value => {
|
||||
let obj;
|
||||
let error;
|
||||
|
||||
try {
|
||||
obj = angular.fromJson(value);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
return { obj, error };
|
||||
};
|
||||
}
|
||||
|
||||
AddCredentialsController.$inject = [
|
||||
'resolvedModels',
|
||||
'$state',
|
||||
'CredentialsStrings'
|
||||
'$scope',
|
||||
'CredentialsStrings',
|
||||
'ComponentsStrings'
|
||||
];
|
||||
|
||||
export default AddCredentialsController;
|
||||
|
||||
@ -14,9 +14,9 @@
|
||||
|
||||
<at-divider></at-divider>
|
||||
|
||||
<at-input-lookup col="4" tab="4" state="vm.form.credential_type"></at-input-lookup>
|
||||
<at-input-lookup col="4" tab="5" state="vm.form.credential_type"></at-input-lookup>
|
||||
|
||||
<at-input-group col="4" tab="5" state="vm.form.inputs">
|
||||
<at-input-group col="4" tab="6" state="vm.form.inputs">
|
||||
{{:: vm.strings.get('inputs.GROUP_TITLE') }}
|
||||
</at-input-group>
|
||||
|
||||
|
||||
@ -17,7 +17,9 @@ function CredentialsStrings (BaseString) {
|
||||
ns.inputs = {
|
||||
GROUP_TITLE: t.s('Type Details'),
|
||||
ORGANIZATION_PLACEHOLDER: t.s('SELECT AN ORGANIZATION'),
|
||||
CREDENTIAL_TYPE_PLACEHOLDER: t.s('SELECT A CREDENTIAL TYPE')
|
||||
CREDENTIAL_TYPE_PLACEHOLDER: t.s('SELECT A CREDENTIAL TYPE'),
|
||||
GCE_FILE_INPUT_LABEL: t.s('Service Account JSON File'),
|
||||
GCE_FILE_INPUT_HELP_TEXT: t.s('Provide account information using Google Compute Engine JSON credentials file.')
|
||||
};
|
||||
|
||||
ns.add = {
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
function EditCredentialsController (models, $state, $scope, strings) {
|
||||
function EditCredentialsController (models, $state, $scope, strings, componentsStrings) {
|
||||
const vm = this || {};
|
||||
|
||||
const { me, credential, credentialType, organization } = models;
|
||||
@ -64,15 +64,35 @@ function EditCredentialsController (models, $state, $scope, strings) {
|
||||
vm.form.credential_type._displayValue = credentialType.get('name');
|
||||
vm.form.credential_type._placeholder = strings.get('inputs.CREDENTIAL_TYPE_PLACEHOLDER');
|
||||
|
||||
const gceFileInputSchema = {
|
||||
id: 'gce_service_account_key',
|
||||
type: 'file',
|
||||
label: strings.get('inputs.GCE_FILE_INPUT_LABEL'),
|
||||
help_text: strings.get('inputs.GCE_FILE_INPUT_HELP_TEXT'),
|
||||
};
|
||||
|
||||
let gceFileInputPreEditValues;
|
||||
|
||||
vm.form.inputs = {
|
||||
_get () {
|
||||
let fields;
|
||||
|
||||
credentialType.mergeInputProperties();
|
||||
|
||||
if (credentialType.get('id') === credential.get('credential_type')) {
|
||||
return credential.assignInputGroupValues(credentialType.get('inputs.fields'));
|
||||
fields = credential.assignInputGroupValues(credentialType.get('inputs.fields'));
|
||||
} else {
|
||||
fields = credentialType.get('inputs.fields');
|
||||
}
|
||||
|
||||
return credentialType.get('inputs.fields');
|
||||
if (credentialType.get('name') === 'Google Compute Engine') {
|
||||
fields.splice(2, 0, gceFileInputSchema);
|
||||
|
||||
$scope.$watch(`vm.form.${gceFileInputSchema.id}._value`, vm.gceOnFileInputChanged);
|
||||
$scope.$watch('vm.form.ssh_key_data._isBeingReplaced', vm.gceOnReplaceKeyChanged);
|
||||
}
|
||||
|
||||
return fields;
|
||||
},
|
||||
_source: vm.form.credential_type,
|
||||
_reference: 'vm.form.inputs',
|
||||
@ -88,19 +108,70 @@ function EditCredentialsController (models, $state, $scope, strings) {
|
||||
data.user = me.get('id');
|
||||
credential.unset('inputs');
|
||||
|
||||
delete data.inputs[gceFileInputSchema.id];
|
||||
|
||||
return credential.request('put', { data });
|
||||
};
|
||||
|
||||
vm.form.onSaveSuccess = () => {
|
||||
$state.go('credentials.edit', { credential_id: credential.get('id') }, { reload: true });
|
||||
};
|
||||
|
||||
vm.gceOnReplaceKeyChanged = value => {
|
||||
vm.form[gceFileInputSchema.id]._disabled = !value;
|
||||
};
|
||||
|
||||
vm.gceOnFileInputChanged = (value, oldValue) => {
|
||||
if (value === oldValue) return;
|
||||
|
||||
const gceFileIsLoaded = !!value;
|
||||
const gceFileInputState = vm.form[gceFileInputSchema.id];
|
||||
const { obj, error } = vm.gceParseFileInput(value);
|
||||
|
||||
gceFileInputState._isValid = !error;
|
||||
gceFileInputState._message = error ? componentsStrings.get('message.INVALID_INPUT') : '';
|
||||
|
||||
vm.form.project._disabled = gceFileIsLoaded;
|
||||
vm.form.username._disabled = gceFileIsLoaded;
|
||||
vm.form.ssh_key_data._disabled = gceFileIsLoaded;
|
||||
vm.form.ssh_key_data._displayHint = !vm.form.ssh_key_data._disabled;
|
||||
|
||||
if (gceFileIsLoaded) {
|
||||
gceFileInputPreEditValues = Object.assign({}, {
|
||||
project: vm.form.project._value,
|
||||
ssh_key_data: vm.form.ssh_key_data._value,
|
||||
username: vm.form.username._value
|
||||
});
|
||||
vm.form.project._value = _.get(obj, 'project_id', '');
|
||||
vm.form.ssh_key_data._value = _.get(obj, 'private_key', '');
|
||||
vm.form.username._value = _.get(obj, 'client_email', '');
|
||||
} else {
|
||||
vm.form.project._value = gceFileInputPreEditValues.project;
|
||||
vm.form.ssh_key_data._value = gceFileInputPreEditValues.ssh_key_data;
|
||||
vm.form.username._value = gceFileInputPreEditValues.username;
|
||||
}
|
||||
};
|
||||
|
||||
vm.gceParseFileInput = value => {
|
||||
let obj;
|
||||
let error;
|
||||
|
||||
try {
|
||||
obj = angular.fromJson(value);
|
||||
} catch (err) {
|
||||
error = err;
|
||||
}
|
||||
|
||||
return { obj, error };
|
||||
};
|
||||
}
|
||||
|
||||
EditCredentialsController.$inject = [
|
||||
'resolvedModels',
|
||||
'$state',
|
||||
'$scope',
|
||||
'CredentialsStrings'
|
||||
'CredentialsStrings',
|
||||
'ComponentsStrings'
|
||||
];
|
||||
|
||||
export default EditCredentialsController;
|
||||
|
||||
@ -16,6 +16,10 @@ function ComponentsStrings (BaseString) {
|
||||
INVALID_INPUT: t.s('Invalid input for this type.')
|
||||
};
|
||||
|
||||
ns.file = {
|
||||
PLACEHOLDER: t.s('CHOOSE A FILE')
|
||||
};
|
||||
|
||||
ns.form = {
|
||||
SUBMISSION_ERROR_TITLE: t.s('Unable to Submit'),
|
||||
SUBMISSION_ERROR_MESSAGE: t.s('Unexpected server error. View the console for more information'),
|
||||
|
||||
@ -38,6 +38,10 @@ function AtFormController (eventService, strings) {
|
||||
component.category = category;
|
||||
component.form = vm.state;
|
||||
|
||||
if (category === 'input') {
|
||||
scope.state[component.state.id] = component.state;
|
||||
}
|
||||
|
||||
vm.components.push(component);
|
||||
};
|
||||
|
||||
@ -189,6 +193,7 @@ function AtFormController (eventService, strings) {
|
||||
for (let j = 0; j < vm.components.length; j++) {
|
||||
if (components[i] === vm.components[j].state) {
|
||||
vm.components.splice(j, 1);
|
||||
delete scope.state[components[i].id];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import divider from '~components/utility/divider.directive';
|
||||
import form from '~components/form/form.directive';
|
||||
import formAction from '~components/form/action.directive';
|
||||
import inputCheckbox from '~components/input/checkbox.directive';
|
||||
import inputFile from '~components/input/file.directive';
|
||||
import inputGroup from '~components/input/group.directive';
|
||||
import inputLabel from '~components/input/label.directive';
|
||||
import inputLookup from '~components/input/lookup.directive';
|
||||
@ -41,6 +42,7 @@ angular
|
||||
.directive('atForm', form)
|
||||
.directive('atFormAction', formAction)
|
||||
.directive('atInputCheckbox', inputCheckbox)
|
||||
.directive('atInputFile', inputFile)
|
||||
.directive('atInputGroup', inputGroup)
|
||||
.directive('atInputLabel', inputLabel)
|
||||
.directive('atInputLookup', inputLookup)
|
||||
|
||||
@ -15,6 +15,10 @@
|
||||
border-color: @at-color-input-focus;
|
||||
}
|
||||
|
||||
&[readonly] {
|
||||
background: @at-color-input-readonly;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
background: @at-color-input-disabled;
|
||||
}
|
||||
|
||||
@ -85,9 +85,7 @@ function BaseInputController (strings) {
|
||||
vm.updateValidationState(result);
|
||||
};
|
||||
|
||||
vm.toggleRevertReplace = () => {
|
||||
scope.state._isBeingReplaced = !scope.state._isBeingReplaced;
|
||||
|
||||
vm.onRevertReplaceToggle = () => {
|
||||
if (!scope.state._isBeingReplaced) {
|
||||
scope.state._buttonText = vm.strings.get('REPLACE');
|
||||
scope.state._disabled = true;
|
||||
|
||||
94
awx/ui/client/lib/components/input/file.directive.js
Normal file
94
awx/ui/client/lib/components/input/file.directive.js
Normal file
@ -0,0 +1,94 @@
|
||||
const templateUrl = require('~components/input/file.partial.html');
|
||||
|
||||
function atInputFileLink (scope, element, attrs, controllers) {
|
||||
const formController = controllers[0];
|
||||
const inputController = controllers[1];
|
||||
|
||||
if (scope.tab === '1') {
|
||||
element.find('input')[0].focus();
|
||||
}
|
||||
|
||||
inputController.init(scope, element, formController);
|
||||
}
|
||||
|
||||
function AtInputFileController (baseInputController, eventService) {
|
||||
const vm = this || {};
|
||||
|
||||
let input;
|
||||
let scope;
|
||||
|
||||
vm.init = (_scope_, element, form) => {
|
||||
baseInputController.call(vm, 'input', _scope_, element, form);
|
||||
|
||||
scope = _scope_;
|
||||
input = element.find('input')[0]; // eslint-disable-line prefer-destructuring
|
||||
|
||||
vm.listeners = vm.setFileListeners(input);
|
||||
|
||||
vm.check();
|
||||
};
|
||||
|
||||
vm.onButtonClick = () => {
|
||||
if (scope.state._value) {
|
||||
vm.removeFile();
|
||||
} else {
|
||||
input.click();
|
||||
}
|
||||
};
|
||||
|
||||
vm.setFileListeners = inputEl => eventService.addListeners([
|
||||
[inputEl, 'change', event => vm.handleFileChangeEvent(inputEl, event)]
|
||||
]);
|
||||
|
||||
vm.handleFileChangeEvent = (element, event) => {
|
||||
if (element.files.length > 0) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = () => vm.readFile(reader, event);
|
||||
reader.readAsText(element.files[0]);
|
||||
} else {
|
||||
scope.$apply(vm.removeFile);
|
||||
}
|
||||
};
|
||||
|
||||
vm.readFile = (reader, event) => {
|
||||
scope.$apply(() => {
|
||||
scope.state._value = reader.result;
|
||||
scope.state._displayValue = event.target.files[0].name;
|
||||
|
||||
vm.check();
|
||||
});
|
||||
};
|
||||
|
||||
vm.removeFile = () => {
|
||||
delete scope.state._value;
|
||||
delete scope.state._displayValue;
|
||||
|
||||
input.value = '';
|
||||
};
|
||||
}
|
||||
|
||||
AtInputFileController.$inject = [
|
||||
'BaseInputController',
|
||||
'EventService'
|
||||
];
|
||||
|
||||
function atInputFile () {
|
||||
return {
|
||||
restrict: 'E',
|
||||
transclude: true,
|
||||
replace: true,
|
||||
require: ['^^atForm', 'atInputFile'],
|
||||
templateUrl,
|
||||
controller: AtInputFileController,
|
||||
controllerAs: 'vm',
|
||||
link: atInputFileLink,
|
||||
scope: {
|
||||
state: '=',
|
||||
col: '@',
|
||||
tab: '@'
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default atInputFile;
|
||||
25
awx/ui/client/lib/components/input/file.partial.html
Normal file
25
awx/ui/client/lib/components/input/file.partial.html
Normal file
@ -0,0 +1,25 @@
|
||||
<div class="col-sm-{{::col}} at-InputContainer">
|
||||
<div class="form-group at-u-flat">
|
||||
<at-input-label></at-input-label>
|
||||
<input class="at-InputFile--hidden" type="file"/>
|
||||
<div class="input-group">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn at-ButtonHollow--default at-Input-button"
|
||||
ng-disabled="state._disabled || form.disabled"
|
||||
ng-click="vm.onButtonClick()">
|
||||
<i class="fa fa-folder-open" ng-if="!state._value"></i>
|
||||
<i class="fa fa-trash" ng-if="state._value"></i>
|
||||
</button>
|
||||
</span>
|
||||
<input class="form-control at-Input"
|
||||
type="text"
|
||||
ng-class="{ 'at-Input--rejected': state._rejected }"
|
||||
ng-model="state._displayValue"
|
||||
ng-attr-tabindex="{{ tab || undefined }}"
|
||||
ng-attr-placeholder="{{ state._disabled ? '' : vm.strings.get('file.PLACEHOLDER') }}"
|
||||
ng-disabled="state._disabled || form.disabled"
|
||||
readonly/>
|
||||
</div>
|
||||
<at-input-message></at-input-message>
|
||||
</div>
|
||||
</div>
|
||||
@ -99,6 +99,8 @@ function AtInputGroupController ($scope, $compile) {
|
||||
config._component = 'at-input-number';
|
||||
} else if (input.type === 'boolean') {
|
||||
config._component = 'at-input-checkbox';
|
||||
} else if (input.type === 'file') {
|
||||
config._component = 'at-input-file';
|
||||
} else if (input.choices) {
|
||||
config._component = 'at-input-select';
|
||||
config._format = 'array';
|
||||
|
||||
@ -14,10 +14,14 @@ function atInputTextLink (scope, element, attrs, controllers) {
|
||||
function AtInputTextController (baseInputController) {
|
||||
const vm = this || {};
|
||||
|
||||
vm.init = (scope, element, form) => {
|
||||
baseInputController.call(vm, 'input', scope, element, form);
|
||||
let scope;
|
||||
|
||||
vm.init = (_scope_, element, form) => {
|
||||
baseInputController.call(vm, 'input', _scope_, element, form);
|
||||
scope = _scope_;
|
||||
|
||||
vm.check();
|
||||
scope.$watch('state._value', () => vm.check());
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@ -8,7 +8,6 @@
|
||||
ng-attr-maxlength="{{ state.max_length || undefined }}"
|
||||
ng-attr-tabindex="{{ tab || undefined }}"
|
||||
ng-attr-placeholder="{{::state._placeholder || undefined }}"
|
||||
ng-change="vm.check()"
|
||||
ng-disabled="state._disabled || form.disabled" />
|
||||
|
||||
<at-input-message></at-input-message>
|
||||
|
||||
@ -21,6 +21,7 @@ function AtInputTextareaSecretController (baseInputController, eventService) {
|
||||
baseInputController.call(vm, 'input', _scope_, element, form);
|
||||
|
||||
scope = _scope_;
|
||||
|
||||
[textarea] = element.find('textarea');
|
||||
|
||||
if (scope.state.format === 'ssh_private_key') {
|
||||
@ -38,10 +39,15 @@ function AtInputTextareaSecretController (baseInputController, eventService) {
|
||||
}
|
||||
|
||||
vm.check();
|
||||
|
||||
scope.$watch('state[state._activeModel]', () => vm.check());
|
||||
scope.$watch('state._isBeingReplaced', () => vm.onIsBeingReplacedChanged());
|
||||
};
|
||||
|
||||
vm.toggle = () => {
|
||||
vm.toggleRevertReplace();
|
||||
vm.onIsBeingReplacedChanged = () => {
|
||||
if (!scope.state._touched) return;
|
||||
|
||||
vm.onRevertReplaceToggle();
|
||||
|
||||
if (scope.state._isBeingReplaced) {
|
||||
scope.state._placeholder = '';
|
||||
@ -50,7 +56,10 @@ function AtInputTextareaSecretController (baseInputController, eventService) {
|
||||
} else {
|
||||
scope.state._displayHint = false;
|
||||
scope.state._placeholder = vm.strings.get('ENCRYPTED');
|
||||
eventService.remove(vm.listeners);
|
||||
|
||||
if (vm.listeners) {
|
||||
eventService.remove(vm.listeners);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -6,11 +6,12 @@
|
||||
<div ng-if="state._edit" class="input-group-btn at-InputGroup-button">
|
||||
<button class="btn at-ButtonHollow--white at-Input-button--fixed-md"
|
||||
ng-disabled="!state._enableToggle && (state._disabled || form.disabled)"
|
||||
ng-click="vm.toggle()">
|
||||
ng-click="state._isBeingReplaced = !state._isBeingReplaced">
|
||||
{{ state._buttonText }}
|
||||
</button>
|
||||
</div>
|
||||
<input ng-show="ssh"
|
||||
ng-disabled="state._disabled || form.disabled"
|
||||
class="at-InputFile--hidden"
|
||||
ng-class="{'at-InputFile--drag': drag }"
|
||||
type="file"
|
||||
@ -22,7 +23,6 @@
|
||||
ng-attr-maxlength="{{ state.max_length || undefined }}"
|
||||
ng-attr-tabindex="{{ tab || undefined }}"
|
||||
ng-attr-placeholder="{{state._placeholder || undefined }}"
|
||||
ng-change="vm.check()"
|
||||
ng-disabled="state._disabled || form.disabled" />
|
||||
</textarea>
|
||||
</div>
|
||||
|
||||
@ -22,8 +22,8 @@ function AtModalController (eventService, strings) {
|
||||
vm.strings = strings;
|
||||
|
||||
vm.init = (scope, el) => {
|
||||
[overlay] = el;
|
||||
[modal] = el.find('.at-Modal-window');
|
||||
overlay = el[0]; // eslint-disable-line prefer-destructuring
|
||||
modal = el.find('.at-Modal-window')[0]; // eslint-disable-line prefer-destructuring
|
||||
|
||||
vm.modal = scope[scope.ns].modal;
|
||||
vm.modal.show = vm.show;
|
||||
|
||||
@ -131,6 +131,8 @@
|
||||
@at-color-input-button: @at-gray-light-3x;
|
||||
@at-color-input-button-hover: @at-gray-light-2x;
|
||||
@at-color-input-disabled: @at-gray-light;
|
||||
@at-color-input-readonly: @at-color-input-background;
|
||||
|
||||
@at-color-input-error: @at-color-error;
|
||||
@at-color-input-focus: @at-color-info;
|
||||
@at-color-input-hint: @at-gray-dark-4x;
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
module.exports = {
|
||||
rules: {
|
||||
'no-unused-expressions': 'off'
|
||||
'no-unused-expressions': 'off',
|
||||
'no-unused-vars': 'off',
|
||||
}
|
||||
};
|
||||
|
||||
@ -1,5 +1,7 @@
|
||||
import uuid from 'uuid';
|
||||
|
||||
import { AWX_E2E_PASSWORD } from './settings';
|
||||
|
||||
import {
|
||||
all,
|
||||
get,
|
||||
@ -231,7 +233,7 @@ const getAuditor = (namespace = session) => getOrganization(namespace)
|
||||
email: 'null@ansible.com',
|
||||
is_superuser: false,
|
||||
is_system_auditor: true,
|
||||
password: 'password'
|
||||
password: AWX_E2E_PASSWORD
|
||||
}));
|
||||
|
||||
const getUser = (namespace = session) => getOrganization(namespace)
|
||||
@ -243,7 +245,7 @@ const getUser = (namespace = session) => getOrganization(namespace)
|
||||
email: 'null@ansible.com',
|
||||
is_superuser: false,
|
||||
is_system_auditor: false,
|
||||
password: 'password'
|
||||
password: AWX_E2E_PASSWORD
|
||||
}));
|
||||
|
||||
const getJobTemplateAdmin = (namespace = session) => {
|
||||
@ -259,7 +261,7 @@ const getJobTemplateAdmin = (namespace = session) => {
|
||||
email: 'null@ansible.com',
|
||||
is_superuser: false,
|
||||
is_system_auditor: false,
|
||||
password: 'password'
|
||||
password: AWX_E2E_PASSWORD
|
||||
}));
|
||||
|
||||
const assignRolePromise = Promise.all([userPromise, rolePromise])
|
||||
|
||||
@ -67,6 +67,7 @@ const gce = createFormSection({
|
||||
email: 'Service Account Email Address',
|
||||
project: 'Project',
|
||||
sshKeyData: 'RSA Private Key',
|
||||
serviceAccountFile: 'Service Account JSON File'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@ -12,7 +12,7 @@ const inputContainerElements = {
|
||||
popover: '.at-Popover-container',
|
||||
yaml: 'input[type="radio", value="yaml"]',
|
||||
json: 'input[type="radio", value="json"]',
|
||||
revert: 'a[class~="reset"]',
|
||||
reset: 'a[class~="reset"]',
|
||||
down: 'span[class^="fa-angle-down"]',
|
||||
up: 'span[class^="fa-angle-up"]',
|
||||
prompt: {
|
||||
@ -34,6 +34,14 @@ const inputContainerElements = {
|
||||
off: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='off']`
|
||||
},
|
||||
replace: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='replace']`
|
||||
},
|
||||
revert: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='revert']`
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
12
awx/ui/test/e2e/tests/gce.alt.json
Normal file
12
awx/ui/test/e2e/tests/gce.alt.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "test321",
|
||||
"private_key_id": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\nBBBBBBBBBBBBBBBBBBBBBBBB\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "test321.iam.gserviceaccount.com",
|
||||
"client_id": "321987654321987654321",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test321%40test.iam.gserviceaccount.com"
|
||||
}
|
||||
1
awx/ui/test/e2e/tests/gce.invalid.json
Normal file
1
awx/ui/test/e2e/tests/gce.invalid.json
Normal file
@ -0,0 +1 @@
|
||||
invalid
|
||||
12
awx/ui/test/e2e/tests/gce.json
Normal file
12
awx/ui/test/e2e/tests/gce.json
Normal file
@ -0,0 +1,12 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "test123",
|
||||
"private_key_id": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\nAAAAAAAAAAAAAAAAAAAAAAAA\n-----END PRIVATE KEY-----\n",
|
||||
"client_email": "test123.iam.gserviceaccount.com",
|
||||
"client_id": "123456789123456789123",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test123%40test.iam.gserviceaccount.com"
|
||||
}
|
||||
11
awx/ui/test/e2e/tests/gce.missing.json
Normal file
11
awx/ui/test/e2e/tests/gce.missing.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"type": "service_account",
|
||||
"project_id": "test654",
|
||||
"private_key_id": "cccccccccccccccccccccccccccccccccccccccc",
|
||||
"private_key": "-----BEGIN PRIVATE KEY-----\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC\nCCCCCCCCCCCCCCCCCCCCCCCC\n-----END PRIVATE KEY-----\n",
|
||||
"client_id": "654321987654321987654",
|
||||
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
|
||||
"token_uri": "https://accounts.google.com/o/oauth2/token",
|
||||
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
|
||||
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/test654%40test.iam.gserviceaccount.com"
|
||||
}
|
||||
@ -63,7 +63,7 @@ module.exports = {
|
||||
inventories = client.page.inventories();
|
||||
teams = client.page.teams();
|
||||
|
||||
client.login(data.auditor.username, data.auditor.password);
|
||||
client.login(data.auditor.username);
|
||||
client.waitForAngular();
|
||||
|
||||
done();
|
||||
|
||||
269
awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js
Normal file
269
awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js
Normal file
@ -0,0 +1,269 @@
|
||||
import path from 'path';
|
||||
import uuid from 'uuid';
|
||||
|
||||
const GCE_SERVICE_ACCOUNT_FILE = path.resolve(__dirname, 'gce.json');
|
||||
const GCE_SERVICE_ACCOUNT_FILE_ALT = path.resolve(__dirname, 'gce.alt.json');
|
||||
const GCE_SERVICE_ACCOUNT_FILE_INVALID = path.resolve(__dirname, 'gce.invalid.json');
|
||||
const GCE_SERVICE_ACCOUNT_FILE_MISSING = path.resolve(__dirname, 'gce.missing.json');
|
||||
|
||||
let credentials;
|
||||
|
||||
module.exports = {
|
||||
before: (client, done) => {
|
||||
credentials = client.page.credentials();
|
||||
|
||||
client.login();
|
||||
client.waitForAngular();
|
||||
|
||||
credentials.section.navigation
|
||||
.waitForElementVisible('@credentials')
|
||||
.click('@credentials');
|
||||
|
||||
credentials
|
||||
.waitForElementVisible('div.spinny')
|
||||
.waitForElementNotVisible('div.spinny');
|
||||
|
||||
credentials.section.list
|
||||
.waitForElementVisible('@add')
|
||||
.click('@add');
|
||||
|
||||
credentials.section.add.section.details
|
||||
.waitForElementVisible('@save')
|
||||
.setValue('@name', `credential-${uuid().substr(0, 8)}`)
|
||||
.setValue('@type', 'Google Compute Engine', done);
|
||||
},
|
||||
'expected fields are initially visible and enabled': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
details.expect.element('@name').visible;
|
||||
details.expect.element('@description').visible;
|
||||
details.expect.element('@organization').visible;
|
||||
details.expect.element('@type').visible;
|
||||
|
||||
gce.expect.element('@email').visible;
|
||||
gce.expect.element('@sshKeyData').visible;
|
||||
gce.expect.element('@project').visible;
|
||||
gce.expect.element('@serviceAccountFile').visible;
|
||||
|
||||
details.expect.element('@name').enabled;
|
||||
details.expect.element('@description').enabled;
|
||||
details.expect.element('@organization').enabled;
|
||||
details.expect.element('@type').enabled;
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present;
|
||||
},
|
||||
'select valid credential file': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.setValue('form input[type="file"]', GCE_SERVICE_ACCOUNT_FILE);
|
||||
|
||||
gce.expect.element('@email').not.enabled;
|
||||
gce.expect.element('@sshKeyData').not.enabled;
|
||||
gce.expect.element('@project').not.enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present;
|
||||
},
|
||||
'deselect valid credential file': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.click('form i[class*="trash"]');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present;
|
||||
|
||||
gce.section.email.expect.element('@error').visible;
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
},
|
||||
'select credential file with missing field': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.setValue('form input[type="file"]', GCE_SERVICE_ACCOUNT_FILE_MISSING);
|
||||
|
||||
gce.expect.element('@email').not.enabled;
|
||||
gce.expect.element('@sshKeyData').not.enabled;
|
||||
gce.expect.element('@project').not.enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present;
|
||||
|
||||
gce.section.email.expect.element('@error').visible;
|
||||
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
gce.section.sshKeyData.expect.element('@error').not.present;
|
||||
},
|
||||
'deselect credential file with missing field': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.click('form i[class*="trash"]');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present;
|
||||
|
||||
gce.section.email.expect.element('@error').visible;
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
},
|
||||
'select invalid credential file': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.setValue('form input[type="file"]', GCE_SERVICE_ACCOUNT_FILE_INVALID);
|
||||
|
||||
gce.expect.element('@email').not.enabled;
|
||||
gce.expect.element('@sshKeyData').not.enabled;
|
||||
gce.expect.element('@project').not.enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present;
|
||||
|
||||
gce.section.email.expect.element('@error').visible;
|
||||
gce.section.serviceAccountFile.expect.element('@error').visible;
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
},
|
||||
'deselect invalid credential file': client => {
|
||||
const { details } = credentials.section.add.section;
|
||||
const { gce } = details.section;
|
||||
|
||||
gce.section.serviceAccountFile.click('form i[class*="trash"]');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').visible;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').enabled;
|
||||
gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').not.present;
|
||||
|
||||
gce.section.email.expect.element('@error').visible;
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
},
|
||||
'save valid credential file': client => {
|
||||
const add = credentials.section.add.section.details;
|
||||
const edit = credentials.section.edit.section.details;
|
||||
|
||||
add.section.gce.section.serviceAccountFile.setValue('form input[type="file"]', GCE_SERVICE_ACCOUNT_FILE);
|
||||
|
||||
add.section.gce.expect.element('@email').not.enabled;
|
||||
add.section.gce.expect.element('@sshKeyData').not.enabled;
|
||||
add.section.gce.expect.element('@project').not.enabled;
|
||||
add.section.gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
add.section.gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').visible;
|
||||
add.section.gce.section.serviceAccountFile.expect.element('form i[class*="trash"]').enabled;
|
||||
add.section.gce.section.serviceAccountFile.expect.element('form i[class*="folder"]').not.present;
|
||||
|
||||
add.click('@save');
|
||||
|
||||
credentials
|
||||
.waitForElementVisible('div.spinny')
|
||||
.waitForElementNotVisible('div.spinny');
|
||||
|
||||
edit.section.gce.expect.element('@email').enabled;
|
||||
edit.section.gce.expect.element('@project').enabled;
|
||||
|
||||
edit.section.gce.expect.element('@serviceAccountFile').not.enabled;
|
||||
edit.section.gce.expect.element('@sshKeyData').not.enabled;
|
||||
},
|
||||
'select and deselect credential file when replacing private key': client => {
|
||||
const { gce } = credentials.section.edit.section.details.section;
|
||||
|
||||
gce.section.sshKeyData.waitForElementVisible('@replace');
|
||||
gce.section.sshKeyData.click('@replace');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.email.expect.element('@error').not.present;
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
|
||||
gce.section.serviceAccountFile.setValue('form input[type="file"]', GCE_SERVICE_ACCOUNT_FILE_ALT);
|
||||
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.expect.element('@email').not.enabled;
|
||||
gce.expect.element('@sshKeyData').not.enabled;
|
||||
gce.expect.element('@project').not.enabled;
|
||||
|
||||
gce.section.email.expect.element('@error').not.present;
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.sshKeyData.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
|
||||
gce.section.sshKeyData.expect.element('@replace').not.present;
|
||||
gce.section.sshKeyData.expect.element('@revert').present;
|
||||
gce.section.sshKeyData.expect.element('@revert').not.enabled;
|
||||
|
||||
gce.section.serviceAccountFile.click('form i[class*="trash"]');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@sshKeyData').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
gce.expect.element('@serviceAccountFile').enabled;
|
||||
|
||||
gce.section.sshKeyData.expect.element('@error').visible;
|
||||
|
||||
gce.section.email.expect.element('@error').not.present;
|
||||
gce.section.project.expect.element('@error').not.present;
|
||||
gce.section.serviceAccountFile.expect.element('@error').not.present;
|
||||
|
||||
gce.section.sshKeyData.expect.element('@revert').enabled;
|
||||
|
||||
gce.section.sshKeyData.click('@revert');
|
||||
|
||||
gce.expect.element('@email').enabled;
|
||||
gce.expect.element('@project').enabled;
|
||||
|
||||
gce.expect.element('@serviceAccountFile').not.enabled;
|
||||
gce.expect.element('@sshKeyData').not.enabled;
|
||||
|
||||
client.end();
|
||||
}
|
||||
};
|
||||
61
awx/ui/test/unit/components/file.unit.js
Normal file
61
awx/ui/test/unit/components/file.unit.js
Normal file
@ -0,0 +1,61 @@
|
||||
describe('Components | Input | File', () => {
|
||||
let $scope;
|
||||
let element;
|
||||
let state;
|
||||
let controller;
|
||||
|
||||
const getMockFileEvent = file => ({ target: { files: [file] } });
|
||||
|
||||
beforeEach(() => {
|
||||
angular.mock.module('at.lib.services');
|
||||
angular.mock.module('at.lib.components');
|
||||
});
|
||||
|
||||
describe('AtInputFileController', () => {
|
||||
beforeEach(angular.mock.inject(($rootScope, $compile) => {
|
||||
const component = '<at-input-file id="unit" state="vm.form.unit"></at-input-file>';
|
||||
const dom = angular.element(`<at-form state="vm.form">${component}</at-form>`);
|
||||
|
||||
$scope = $rootScope.$new();
|
||||
$scope.vm = { form: { disabled: false, unit: {} } };
|
||||
|
||||
$compile(dom)($scope);
|
||||
$scope.$digest();
|
||||
|
||||
element = dom.find('#unit');
|
||||
state = $scope.vm.form.unit;
|
||||
controller = element.controller('atInputFile');
|
||||
}));
|
||||
|
||||
it('should initialize without a value by default', () => {
|
||||
expect(state._value).not.toBeDefined();
|
||||
expect(state._displayValue).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should update display value with file name when file is read', () => {
|
||||
const name = 'notavirus.exe';
|
||||
const reader = { result: 'AAAAAAA' };
|
||||
|
||||
controller.check = jasmine.createSpy('check');
|
||||
|
||||
controller.readFile(reader, getMockFileEvent({ name }));
|
||||
|
||||
$scope.$digest();
|
||||
|
||||
expect(state._value).toBeDefined();
|
||||
expect(state._displayValue).toEqual(name);
|
||||
|
||||
expect(controller.check).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should notify handler on file input change event', () => {
|
||||
controller.handleFileChangeEvent = jasmine.createSpy('handleFileChangeEvent');
|
||||
|
||||
element.find('input')[0].dispatchEvent(new Event('change'));
|
||||
|
||||
$scope.$digest();
|
||||
|
||||
expect(controller.handleFileChangeEvent).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -2,6 +2,7 @@
|
||||
import 'angular-mocks';
|
||||
|
||||
// Import tests
|
||||
import './file.unit';
|
||||
import './layout.unit';
|
||||
import './side-nav.unit';
|
||||
import './side-nav-item.unit';
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user