diff --git a/awx/ui/client/features/credentials/add-edit-credentials.controller.js b/awx/ui/client/features/credentials/add-edit-credentials.controller.js index 78056d8ec5..c2cdd70ebc 100644 --- a/awx/ui/client/features/credentials/add-edit-credentials.controller.js +++ b/awx/ui/client/features/credentials/add-edit-credentials.controller.js @@ -141,7 +141,9 @@ function AddEditCredentialsController ( if (credentialType.get('name') === 'Google Compute Engine') { fields.splice(2, 0, gceFileInputSchema); $scope.$watch(`vm.form.${gceFileInputSchema.id}._value`, gceOnFileInputChanged); - $scope.$watch('vm.form.ssh_key_data._isBeingReplaced', gceOnReplaceKeyChanged); + if (mode === 'edit') { + $scope.$watch('vm.form.ssh_key_data._isBeingReplaced', gceOnReplaceKeyChanged); + } } vm.inputSources.initialItems = credential.get('related.input_sources.results'); @@ -587,9 +589,24 @@ function AddEditCredentialsController ( ssh_key_data: vm.form.ssh_key_data._value, username: vm.form.username._value }); + + vm.form.project.asTag = false; vm.form.project._value = _.get(obj, 'project_id', ''); + vm.inputSources.changedInputFields.push('project'); + vm.inputSources.items = vm.inputSources.items + .filter(({ input_field_name }) => input_field_name !== 'project'); + + vm.form.ssh_key_data.asTag = false; vm.form.ssh_key_data._value = _.get(obj, 'private_key', ''); + vm.inputSources.changedInputFields.push('ssh_key_data'); + vm.inputSources.items = vm.inputSources.items + .filter(({ input_field_name }) => input_field_name !== 'ssh_key_data'); + + vm.form.username.asTag = false; vm.form.username._value = _.get(obj, 'client_email', ''); + vm.inputSources.changedInputFields.push('username'); + vm.inputSources.items = vm.inputSources.items + .filter(({ input_field_name }) => input_field_name !== 'username'); } else { vm.form.project._value = gceFileInputPreEditValues.project; vm.form.ssh_key_data._value = gceFileInputPreEditValues.ssh_key_data; diff --git a/awx/ui/client/lib/components/input/textarea-secret.partial.html b/awx/ui/client/lib/components/input/textarea-secret.partial.html index 61f3f376c3..2fd5c3773c 100644 --- a/awx/ui/client/lib/components/input/textarea-secret.partial.html +++ b/awx/ui/client/lib/components/input/textarea-secret.partial.html @@ -20,7 +20,7 @@ name="files" />
diff --git a/awx/ui/test/e2e/objects/sections/createFormSection.js b/awx/ui/test/e2e/objects/sections/createFormSection.js index 97e4b73394..d1c40a0dd5 100644 --- a/awx/ui/test/e2e/objects/sections/createFormSection.js +++ b/awx/ui/test/e2e/objects/sections/createFormSection.js @@ -21,11 +21,11 @@ const inputContainerElements = { }, show: { locateStrategy: 'xpath', - selector: `.//button[${normalized}='show']` + selector: './/i[contains(@class, "fa fa-eye")]' }, hide: { locateStrategy: 'xpath', - selector: `.//button[${normalized}='hide']` + selector: './/i[contains(@class, "fa fa-eye-slash")]' }, on: { locateStrategy: 'xpath', @@ -37,11 +37,11 @@ const inputContainerElements = { }, replace: { locateStrategy: 'xpath', - selector: `.//button[${normalized}='replace']` + selector: './/i[contains(@class, "fa fa-undo")]' }, revert: { locateStrategy: 'xpath', - selector: `.//button[${normalized}='revert']` + selector: './/i[contains(@class, "fa fa-undo fa-flip-horizontal")]' } }; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js index 9e4238cd6a..8aac716e4e 100644 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js +++ b/awx/ui/test/e2e/tests/test-credentials-add-edit-custom.js @@ -146,19 +146,19 @@ module.exports = { const input = `@${f.id}`; group.expect.element('@show').visible; - group.expect.element('@hide').not.present; + group.expect.element('@hide').not.visible; type.setValue(input, 'SECRET'); type.expect.element(input).text.equal(''); group.click('@show'); - group.expect.element('@show').not.present; + group.expect.element('@show').not.visible; group.expect.element('@hide').visible; type.expect.element(input).value.contain('SECRET'); group.click('@hide'); group.expect.element('@show').visible; - group.expect.element('@hide').not.present; + group.expect.element('@hide').not.visible; type.expect.element(input).text.equal(''); }); }, diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js index cdf871c36a..725fcfdcde 100644 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js +++ b/awx/ui/test/e2e/tests/test-credentials-add-edit-gce-file.js @@ -216,14 +216,22 @@ module.exports = { edit.section.gce.expect.element('@sshKeyData').not.enabled; }, 'select and deselect credential file when replacing private key': client => { + const taggedTextArea = '.at-InputTaggedTextarea'; + const textArea = '.at-InputTextarea'; + const replace = 'button i[class="fa fa-undo"]'; + const revert = 'button i[class="fa fa-undo fa-flip-horizontal"]'; const { gce } = credentials.section.edit.section.details.section; - gce.section.sshKeyData.waitForElementVisible('@replace'); - gce.section.sshKeyData.click('@replace'); + gce.waitForElementVisible(replace); + // eslint-disable-next-line prefer-arrow-callback + client.execute(function clickReplace (selector) { + document.querySelector(selector).click(); + }, [replace]); gce.expect.element('@email').enabled; gce.expect.element('@project').enabled; - gce.expect.element('@sshKeyData').enabled; + gce.expect.element(textArea).enabled; + gce.expect.element(taggedTextArea).not.present; gce.expect.element('@serviceAccountFile').enabled; gce.section.sshKeyData.expect.element('@error').visible; @@ -247,10 +255,9 @@ module.exports = { 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.expect.element(replace).not.present; + gce.expect.element(revert).present; + gce.expect.element('.input-group-append button').not.enabled; gce.section.serviceAccountFile.click('form i[class*="trash"]'); gce.expect.element('@email').enabled; @@ -264,9 +271,11 @@ module.exports = { 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('.input-group-append button').enabled; + // eslint-disable-next-line prefer-arrow-callback + client.execute(function clickRevert (selector) { + document.querySelector(selector).click(); + }, [revert]); gce.expect.element('@email').enabled; gce.expect.element('@project').enabled; diff --git a/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js b/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js index ce04aac0fe..34279e8217 100644 --- a/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js +++ b/awx/ui/test/e2e/tests/test-credentials-add-edit-machine.js @@ -173,13 +173,13 @@ module.exports = { machine.section.password.expect.element('@replace').visible; machine.section.password.expect.element('@replace').enabled; - machine.section.password.expect.element('@revert').not.present; + machine.section.password.expect.element('@revert').not.visible; machine.expect.element('@password').not.enabled; machine.section.password.click('@replace'); - machine.section.password.expect.element('@replace').not.present; + machine.section.password.expect.element('@replace').not.visible; machine.section.password.expect.element('@revert').visible; machine.expect.element('@password').enabled; diff --git a/awx/ui/test/e2e/tests/test-form-error-handling.js b/awx/ui/test/e2e/tests/test-form-error-handling.js index a283e9f304..559292f20b 100644 --- a/awx/ui/test/e2e/tests/test-form-error-handling.js +++ b/awx/ui/test/e2e/tests/test-form-error-handling.js @@ -5,6 +5,7 @@ import { } from '../fixtures'; import { + AWX_E2E_TIMEOUT_MEDIUM, AWX_E2E_TIMEOUT_SHORT } from '../settings'; @@ -23,16 +24,19 @@ module.exports = { Promise.all(resources) .then(([jt, jt2]) => { data = { jt, jt2 }; + // We login and load the test page *after* data setup is finished. + // This helps avoid flakiness due to unpredictable spinners, etc. + // caused by first-time project syncs when creating the job templates. + client + .login() + .waitForAngular() + .resizeWindow(1200, 1000) + .useXpath() + .findThenClick(templatesNavTab) + .findThenClick('//*[@id="button-add"]') + .findThenClick('//a[@ui-sref="templates.addJobTemplate"]'); done(); }); - client - .login() - .waitForAngular() - .resizeWindow(1200, 1000) - .useXpath() - .findThenClick(templatesNavTab) - .findThenClick('//*[@id="button-add"]') - .findThenClick('//a[@ui-sref="templates.addJobTemplate"]'); }, 'Test max character limit when creating a job template': client => { client @@ -49,18 +53,21 @@ module.exports = { '//input[@name="project_name"]', ['test-form-error-handling-project', client.Keys.ENTER] ) - - // clicked twice to make the element an active field - .findThenClick('//*[@id="select2-playbook-select-container"]') + // After the test sets a value for the project, a few seconds are + // needed while the UI fetches the playbooks names with a network + // call. There's no obvious dom element here to poll, so we wait a + // reasonably safe amount of time for the form to settle down + // before proceeding. + .pause(AWX_E2E_TIMEOUT_MEDIUM) + .waitForElementNotVisible('//*[contains(@class, "spinny")]') .findThenClick('//*[@id="select2-playbook-select-container"]') .findThenClick('//li[text()="hello_world.yml"]') .findThenClick('//*[@id="job_template_save_btn"]') .findThenClick('//*[@id="alert_ok_btn"]'); client.expect.element('//div[@id="job_template_name_group"]' + - '//div[@id="job_template-name-api-error"]').to.be.visible.before(AWX_E2E_TIMEOUT_SHORT); + '//div[@id="job_template-name-api-error"]').to.be.visible; }, - 'Test duplicate template name handling when creating a job template': client => { client .waitForElementNotVisible('//*[@id="alert_ok_btn"]')