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"]')