From 6b3f45bc26ab3e646e920357a5933ec35dde7821 Mon Sep 17 00:00:00 2001 From: mabashian Date: Thu, 19 Jul 2018 16:04:18 -0400 Subject: [PATCH 1/2] Changes copy behavior to reload list rather than navigate to edit form. Shows toast message on successful copy. --- .../templates/templatesList.controller.js | 44 +++++++++++++++---- awx/ui/client/legacy/styles/ansible-ui.less | 11 +++++ .../lib/services/base-string.service.js | 1 + .../list/credentials-list.controller.js | 22 +++++++--- .../list/inventory-list.controller.js | 22 ++++++++-- .../inventory-scripts/list/list.controller.js | 22 +++++++--- .../list.controller.js | 25 +++++++---- .../projects/list/projects-list.controller.js | 22 +++++++--- 8 files changed, 134 insertions(+), 35 deletions(-) diff --git a/awx/ui/client/features/templates/templatesList.controller.js b/awx/ui/client/features/templates/templatesList.controller.js index f2058d0376..e22f146e92 100644 --- a/awx/ui/client/features/templates/templatesList.controller.js +++ b/awx/ui/client/features/templates/templatesList.controller.js @@ -22,7 +22,8 @@ function ListTemplatesController( strings, Wait, qs, - GetBasePath + GetBasePath, + ngToast ) { const vm = this || {}; const [jobTemplate, workflowTemplate] = resolvedModels; @@ -57,7 +58,7 @@ function ListTemplatesController( }; vm.dataset = Dataset.data; vm.templates = Dataset.data.results; - + $scope.$watch('vm.dataset.count', () => { $scope.$emit('updateCount', vm.dataset.count, 'templates'); }); @@ -201,9 +202,21 @@ function ListTemplatesController( jobTemplate .create('get', template.id) .then(model => model.copy()) - .then(({ id }) => { - const params = { job_template_id: id }; - $state.go('templates.editJobTemplate', params, { reload: true }); + .then((copiedJT) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${strings.get('SUCCESSFUL_CREATION', copiedJT.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(createErrorHandler('copy job template', 'POST')) .finally(() => Wait('stop')); @@ -219,9 +232,21 @@ function ListTemplatesController( $('#prompt-modal').modal('hide'); Wait('start'); model.copy() - .then(({ id }) => { - const params = { workflow_job_template_id: id }; - $state.go('templates.editWorkflowJobTemplate', params, { reload: true }); + .then((copiedWFJT) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${strings.get('SUCCESSFUL_CREATION', copiedWFJT.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(createErrorHandler('copy workflow', 'POST')) .finally(() => Wait('stop')); @@ -360,7 +385,8 @@ ListTemplatesController.$inject = [ 'TemplatesStrings', 'Wait', 'QuerySet', - 'GetBasePath' + 'GetBasePath', + 'ngToast' ]; export default ListTemplatesController; diff --git a/awx/ui/client/legacy/styles/ansible-ui.less b/awx/ui/client/legacy/styles/ansible-ui.less index 1717e2a7a6..dcd4a9bcce 100644 --- a/awx/ui/client/legacy/styles/ansible-ui.less +++ b/awx/ui/client/legacy/styles/ansible-ui.less @@ -2349,3 +2349,14 @@ body { margin-top: .3em; margin-bottom: .3em; } + +.Toast-wrapper { + display: flex; + max-width: 250px; +} + +.Toast-icon { + display: flex; + align-items: center; + justify-content: center; +} diff --git a/awx/ui/client/lib/services/base-string.service.js b/awx/ui/client/lib/services/base-string.service.js index 2362339192..649f33a486 100644 --- a/awx/ui/client/lib/services/base-string.service.js +++ b/awx/ui/client/lib/services/base-string.service.js @@ -72,6 +72,7 @@ function BaseStringService (namespace) { this.COPY = t.s('COPY'); this.YES = t.s('YES'); this.CLOSE = t.s('CLOSE'); + this.SUCCESSFUL_CREATION = resource => t.s('{{ resource }} successfully created', { resource }); this.deleteResource = { HEADER: t.s('Delete'), diff --git a/awx/ui/client/src/credentials/list/credentials-list.controller.js b/awx/ui/client/src/credentials/list/credentials-list.controller.js index 1f088dbcdc..37d4bd4441 100644 --- a/awx/ui/client/src/credentials/list/credentials-list.controller.js +++ b/awx/ui/client/src/credentials/list/credentials-list.controller.js @@ -6,10 +6,10 @@ export default ['$scope', 'Rest', 'CredentialList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', '$state', '$filter', 'rbacUiControlService', 'Dataset', 'credentialType', 'i18n', - 'CredentialModel', 'CredentialsStrings', + 'CredentialModel', 'CredentialsStrings', 'ngToast', function($scope, Rest, CredentialList, Prompt, ProcessErrors, GetBasePath, Wait, $state, $filter, rbacUiControlService, Dataset, - credentialType, i18n, Credential, CredentialsStrings) { + credentialType, i18n, Credential, CredentialsStrings, ngToast) { const credential = new Credential(); @@ -93,9 +93,21 @@ export default ['$scope', 'Rest', 'CredentialList', 'Prompt', 'ProcessErrors', ' Wait('start'); new Credential('get', credential.id) .then(model => model.copy()) - .then(({ id }) => { - const params = { credential_id: id }; - $state.go('credentials.edit', params, { reload: true }); + .then((copiedCred) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${CredentialsStrings.get('SUCCESSFUL_CREATION', copiedCred.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(({ data, status }) => { const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; diff --git a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js b/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js index 4a4b5d3e7f..0c085d793e 100644 --- a/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js +++ b/awx/ui/client/src/inventories-hosts/inventories/list/inventory-list.controller.js @@ -13,7 +13,8 @@ function InventoriesList($scope, $filter, Rest, InventoryList, Prompt, ProcessErrors, GetBasePath, Wait, $state, - Dataset, canAdd, i18n, Inventory, InventoryHostsStrings) { + Dataset, canAdd, i18n, Inventory, InventoryHostsStrings, + ngToast) { let inventory = new Inventory(); @@ -82,7 +83,22 @@ function InventoriesList($scope, Wait('start'); new Inventory('get', inventory.id) .then(model => model.copy()) - .then(copy => $scope.editInventory(copy, true)) + .then(copiedInv => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${InventoryHostsStrings.get('SUCCESSFUL_CREATION', copiedInv.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); + }) .catch(({ data, status }) => { const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; ProcessErrors($scope, data, status, null, params); @@ -182,5 +198,5 @@ export default ['$scope', '$filter', 'Rest', 'InventoryList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'Wait', '$state', 'Dataset', 'canAdd', 'i18n', 'InventoryModel', - 'InventoryHostsStrings', InventoriesList + 'InventoryHostsStrings', 'ngToast', InventoriesList ]; diff --git a/awx/ui/client/src/inventory-scripts/list/list.controller.js b/awx/ui/client/src/inventory-scripts/list/list.controller.js index 96c15c31d8..4202a07f5e 100644 --- a/awx/ui/client/src/inventory-scripts/list/list.controller.js +++ b/awx/ui/client/src/inventory-scripts/list/list.controller.js @@ -7,12 +7,12 @@ export default ['$rootScope', '$scope', 'Wait', 'InventoryScriptsList', 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', '$filter', 'Dataset', 'rbacUiControlService', 'InventoryScriptModel', 'InventoryScriptsStrings', - 'i18n', + 'i18n', 'ngToast', function( $rootScope, $scope, Wait, InventoryScriptsList, GetBasePath, Rest, ProcessErrors, Prompt, $state, $filter, Dataset, rbacUiControlService, InventoryScript, InventoryScriptsStrings, - i18n + i18n, ngToast ) { let inventoryScript = new InventoryScript(); var defaultUrl = GetBasePath('inventory_scripts'), @@ -51,9 +51,21 @@ export default ['$rootScope', '$scope', 'Wait', 'InventoryScriptsList', Wait('start'); new InventoryScript('get', inventoryScript.id) .then(model => model.copy()) - .then(({ id }) => { - const params = { inventory_script_id: id }; - $state.go('inventoryScripts.edit', params, { reload: true }); + .then((copiedInvScript) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${InventoryScriptsStrings.get('SUCCESSFUL_CREATION', copiedInvScript.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(({ data, status }) => { const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; diff --git a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js index f471a2aac6..2fd571a740 100644 --- a/awx/ui/client/src/notifications/notification-templates-list/list.controller.js +++ b/awx/ui/client/src/notifications/notification-templates-list/list.controller.js @@ -7,12 +7,12 @@ export default ['$scope', 'Wait', 'NotificationTemplatesList', 'GetBasePath', 'Rest', 'ProcessErrors', 'Prompt', '$state', 'ngToast', '$filter', 'Dataset', 'rbacUiControlService', - 'i18n', 'NotificationTemplate', + 'i18n', 'NotificationTemplate', 'AppStrings', function( $scope, Wait, NotificationTemplatesList, GetBasePath, Rest, ProcessErrors, Prompt, $state, ngToast, $filter, Dataset, rbacUiControlService, - i18n, NotificationTemplate) { + i18n, NotificationTemplate, AppStrings) { var defaultUrl = GetBasePath('notification_templates'), list = NotificationTemplatesList; @@ -92,12 +92,21 @@ Wait('start'); new NotificationTemplate('get', notificationTemplate.id) .then(model => model.copy()) - .then(({ id }) => { - const params = { - notification_template_id: id, - notification_template: this.notification_templates - }; - $state.go('notifications.edit', params, { reload: true }); + .then((copiedNotification) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${AppStrings.get('SUCCESSFUL_CREATION', copiedNotification.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(({ data, status }) => { const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; diff --git a/awx/ui/client/src/projects/list/projects-list.controller.js b/awx/ui/client/src/projects/list/projects-list.controller.js index 79adc91b41..a6136bc39a 100644 --- a/awx/ui/client/src/projects/list/projects-list.controller.js +++ b/awx/ui/client/src/projects/list/projects-list.controller.js @@ -8,11 +8,11 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', 'ProjectList', 'Prompt', 'ProcessErrors', 'GetBasePath', 'ProjectUpdate', 'Wait', 'Empty', 'Find', 'GetProjectIcon', 'GetProjectToolTip', '$filter', '$state', 'rbacUiControlService', 'Dataset', 'i18n', 'QuerySet', 'ProjectModel', - 'ProjectsStrings', + 'ProjectsStrings', 'ngToast', function($scope, $rootScope, $log, Rest, Alert, ProjectList, Prompt, ProcessErrors, GetBasePath, ProjectUpdate, Wait, Empty, Find, GetProjectIcon, GetProjectToolTip, $filter, $state, rbacUiControlService, - Dataset, i18n, qs, Project, ProjectsStrings) { + Dataset, i18n, qs, Project, ProjectsStrings, ngToast) { let project = new Project(); @@ -156,9 +156,21 @@ export default ['$scope', '$rootScope', '$log', 'Rest', 'Alert', Wait('start'); new Project('get', project.id) .then(model => model.copy()) - .then(({ id }) => { - const params = { project_id: id }; - $state.go('projects.edit', params, { reload: true }); + .then((copiedProj) => { + ngToast.success({ + content: ` +
+
+ +
+
+ ${ProjectsStrings.get('SUCCESSFUL_CREATION', copiedProj.name)} +
+
`, + dismissButton: false, + dismissOnTimeout: true + }); + $state.go('.', null, { reload: true }); }) .catch(({ data, status }) => { const params = { hdr: 'Error!', msg: `Call to copy failed. Return status: ${status}` }; From 4937d1f75eaca4a0a2193c545a7e534100ec9f6c Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Fri, 20 Jul 2018 10:02:50 -0400 Subject: [PATCH 2/2] update copy tests --- awx/ui/test/e2e/fixtures.js | 13 +++ .../tests/test-credentials-list-actions.js | 18 ++++ .../tests/test-inventories-list-actions.js | 89 +++++++++++++++---- .../test-inventory-scripts-list-actions.js | 18 ++++ .../tests/test-notifications-list-actions.js | 18 ++++ .../e2e/tests/test-projects-list-actions.js | 18 ++++ .../e2e/tests/test-templates-list-actions.js | 36 ++++++++ 7 files changed, 192 insertions(+), 18 deletions(-) diff --git a/awx/ui/test/e2e/fixtures.js b/awx/ui/test/e2e/fixtures.js index ddc705cdf7..c3e069ac5e 100644 --- a/awx/ui/test/e2e/fixtures.js +++ b/awx/ui/test/e2e/fixtures.js @@ -57,6 +57,18 @@ const getInventory = (namespace = session) => getOrganization(namespace) variables: JSON.stringify({ ansible_connection: 'local' }), }, ['name', 'inventory']).then(() => inventory))); +const getInventoryNoSource = (namespace = session) => getOrganization(namespace) + .then(organization => getOrCreate('/inventories/', { + name: `${namespace}-inventory-nosource`, + description: namespace, + organization: organization.id + }).then(inventory => getOrCreate('/hosts/', { + name: `${namespace}-host`, + description: namespace, + inventory: inventory.id, + variables: JSON.stringify({ ansible_connection: 'local' }), + }, ['name', 'inventory']).then(() => inventory))); + const getHost = (namespace = session) => getInventory(namespace) .then(inventory => getOrCreate('/hosts/', { name: `${namespace}-host`, @@ -365,6 +377,7 @@ module.exports = { getAuditor, getHost, getInventory, + getInventoryNoSource, getInventoryScript, getInventorySource, getInventorySourceSchedule, diff --git a/awx/ui/test/e2e/tests/test-credentials-list-actions.js b/awx/ui/test/e2e/tests/test-credentials-list-actions.js index dd5c274496..c3b0400802 100644 --- a/awx/ui/test/e2e/tests/test-credentials-list-actions.js +++ b/awx/ui/test/e2e/tests/test-credentials-list-actions.js @@ -38,6 +38,24 @@ module.exports = { credentials.waitForElementVisible('div.spinny'); credentials.waitForElementNotVisible('div.spinny'); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + credentials.waitForElementNotPresent(toast); + credentials.expect.element(activityStream).visible; + credentials.expect.element(activityStream).enabled; + credentials.click(activityStream); + credentials.waitForElementVisible('div.spinny'); + credentials.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + credentials.waitForElementVisible('div.spinny'); + credentials.waitForElementNotVisible('div.spinny'); + credentials.expect.element('div[ui-view="edit"] form').visible; credentials.section.edit.expect.element('@title').visible; credentials.section.edit.expect.element('@title').text.contain(data.credential.name); diff --git a/awx/ui/test/e2e/tests/test-inventories-list-actions.js b/awx/ui/test/e2e/tests/test-inventories-list-actions.js index e705daeacf..97eb260a0f 100644 --- a/awx/ui/test/e2e/tests/test-inventories-list-actions.js +++ b/awx/ui/test/e2e/tests/test-inventories-list-actions.js @@ -1,12 +1,19 @@ -import { getInventory } from '../fixtures'; +import { getInventory, getInventoryNoSource } from '../fixtures'; -const data = {}; +let data; module.exports = { before: (client, done) => { - getInventory('test-actions') - .then(obj => { data.inventory = obj; }) - .then(done); + const resources = [ + getInventory('test-actions'), + getInventoryNoSource('test-actions'), + ]; + + Promise.all(resources) + .then(([inventory, inventoryNoSource]) => { + data = { inventory, inventoryNoSource }; + done(); + }); }, 'copy inventory': client => { const inventories = client.page.inventories(); @@ -23,6 +30,63 @@ module.exports = { inventories.section.list.expect.element('smart-search').visible; inventories.section.list.section.search.expect.element('@input').enabled; + inventories.section.list.section.search + .sendKeys('@input', `id:>${data.inventoryNoSource.id - 1} id:<${data.inventoryNoSource.id + 1}`) + .sendKeys('@input', client.Keys.ENTER); + + inventories.waitForElementVisible('div.spinny'); + inventories.waitForElementNotVisible('div.spinny'); + + inventories.expect.element(`#inventories_table tr[id="${data.inventoryNoSource.id}"]`).visible; + inventories.expect.element('i[class*="copy"]').visible; + inventories.expect.element('i[class*="copy"]').enabled; + + inventories.click('i[class*="copy"]'); + inventories.waitForElementVisible('div.spinny'); + inventories.waitForElementNotVisible('div.spinny'); + + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + inventories.waitForElementNotPresent(toast); + inventories.expect.element(activityStream).visible; + inventories.expect.element(activityStream).enabled; + inventories.click(activityStream); + inventories.waitForElementVisible('div.spinny'); + inventories.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + inventories.waitForElementVisible('div.spinny'); + inventories.waitForElementNotVisible('div.spinny'); + + inventories.expect.element('#inventory_form').visible; + inventories.section.editStandardInventory.expect.element('@title').visible; + inventories.section.editStandardInventory.expect.element('@title').text.contain(data.inventoryNoSource.name); + inventories.section.editStandardInventory.expect.element('@title').text.not.equal(data.inventoryNoSource.name); + inventories.expect.element('@save').visible; + inventories.expect.element('@save').enabled; + + client.end(); + }, + 'verify inventories with sources cannot be copied': client => { + const inventories = client.page.inventories(); + + client.useCss(); + client.resizeWindow(1200, 800); + client.login(); + client.waitForAngular(); + + inventories.load(); + inventories.waitForElementVisible('div.spinny'); + inventories.waitForElementNotVisible('div.spinny'); + + inventories.section.list.expect.element('smart-search').visible; + inventories.section.list.section.search.expect.element('@input').enabled; + inventories.section.list.section.search .sendKeys('@input', `id:>${data.inventory.id - 1} id:<${data.inventory.id + 1}`) .sendKeys('@input', client.Keys.ENTER); @@ -31,19 +95,8 @@ module.exports = { inventories.waitForElementNotVisible('div.spinny'); inventories.expect.element(`#inventories_table tr[id="${data.inventory.id}"]`).visible; - inventories.expect.element('i[class*="copy"]').visible; - inventories.expect.element('i[class*="copy"]').enabled; - - inventories.click('i[class*="copy"]'); - inventories.waitForElementVisible('div.spinny'); - inventories.waitForElementNotVisible('div.spinny'); - - inventories.expect.element('#inventory_form').visible; - inventories.section.editStandardInventory.expect.element('@title').visible; - inventories.section.editStandardInventory.expect.element('@title').text.contain(data.inventory.name); - inventories.section.editStandardInventory.expect.element('@title').text.not.equal(data.inventory.name); - inventories.expect.element('@save').visible; - inventories.expect.element('@save').enabled; + inventories.expect.element('#copy-action').visible; + inventories.expect.element('#copy-action[class$="btn-disabled"]').present; client.end(); } diff --git a/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js b/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js index b75bb73516..9e801f2ecc 100644 --- a/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js +++ b/awx/ui/test/e2e/tests/test-inventory-scripts-list-actions.js @@ -38,6 +38,24 @@ module.exports = { inventoryScripts.waitForElementVisible('div.spinny'); inventoryScripts.waitForElementNotVisible('div.spinny'); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + inventoryScripts.waitForElementNotPresent(toast); + inventoryScripts.expect.element(activityStream).visible; + inventoryScripts.expect.element(activityStream).enabled; + inventoryScripts.click(activityStream); + inventoryScripts.waitForElementVisible('div.spinny'); + inventoryScripts.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + inventoryScripts.waitForElementVisible('div.spinny'); + inventoryScripts.waitForElementNotVisible('div.spinny'); + inventoryScripts.expect.element('#inventory_script_form').visible; inventoryScripts.section.edit.expect.element('@title').visible; inventoryScripts.section.edit.expect.element('@title').text.contain(data.inventoryScript.name); diff --git a/awx/ui/test/e2e/tests/test-notifications-list-actions.js b/awx/ui/test/e2e/tests/test-notifications-list-actions.js index 8e126e075d..f87957d3a9 100644 --- a/awx/ui/test/e2e/tests/test-notifications-list-actions.js +++ b/awx/ui/test/e2e/tests/test-notifications-list-actions.js @@ -38,6 +38,24 @@ module.exports = { notifications.waitForElementVisible('div.spinny'); notifications.waitForElementNotVisible('div.spinny'); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + notifications.waitForElementNotPresent(toast); + notifications.expect.element(activityStream).visible; + notifications.expect.element(activityStream).enabled; + notifications.click(activityStream); + notifications.waitForElementVisible('div.spinny'); + notifications.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + notifications.waitForElementVisible('div.spinny'); + notifications.waitForElementNotVisible('div.spinny'); + notifications.expect.element('#notification_template_form').visible; notifications.section.edit.expect.element('@title').visible; notifications.section.edit.expect.element('@title').text.contain(data.notification.name); diff --git a/awx/ui/test/e2e/tests/test-projects-list-actions.js b/awx/ui/test/e2e/tests/test-projects-list-actions.js index 17881ed906..a252160b85 100644 --- a/awx/ui/test/e2e/tests/test-projects-list-actions.js +++ b/awx/ui/test/e2e/tests/test-projects-list-actions.js @@ -39,6 +39,24 @@ module.exports = { projects.waitForElementVisible('div.spinny'); projects.waitForElementNotVisible('div.spinny'); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + projects.waitForElementNotPresent(toast); + projects.expect.element(activityStream).visible; + projects.expect.element(activityStream).enabled; + projects.click(activityStream); + projects.waitForElementVisible('div.spinny'); + projects.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + projects.waitForElementVisible('div.spinny'); + projects.waitForElementNotVisible('div.spinny'); + projects.expect.element('#project_form').visible; projects.section.edit.expect.element('@title').visible; projects.section.edit.expect.element('@title').text.contain(data.project.name); diff --git a/awx/ui/test/e2e/tests/test-templates-list-actions.js b/awx/ui/test/e2e/tests/test-templates-list-actions.js index 93cabeed34..fbebe75d94 100644 --- a/awx/ui/test/e2e/tests/test-templates-list-actions.js +++ b/awx/ui/test/e2e/tests/test-templates-list-actions.js @@ -53,6 +53,24 @@ module.exports = { templates.waitForElementVisible('div.spinny'); templates.waitForElementNotVisible('div.spinny'); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + templates.waitForElementNotPresent(toast); + templates.expect.element(activityStream).visible; + templates.expect.element(activityStream).enabled; + templates.click(activityStream); + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + templates.expect.element('#job_template_form').visible; templates.section.addJobTemplate.expect.element('@title').visible; templates.section.addJobTemplate.expect.element('@title').text.contain(data.template.name); @@ -95,6 +113,24 @@ module.exports = { .waitForElementNotVisible('div.spinny') .waitForAngular(); + const activityStream = 'bread-crumb > div i[class$="icon-activity-stream"]'; + const activityRow = '#activities_table tr td[class*="description-column"] a'; + const toast = 'div[class="Toast-icon"]'; + + templates.waitForElementNotPresent(toast); + templates.expect.element(activityStream).visible; + templates.expect.element(activityStream).enabled; + templates.click(activityStream); + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + client + .waitForElementVisible(activityRow) + .click(activityRow); + + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + templates.expect.element('#workflow_job_template_form').visible; templates.section.editWorkflowJobTemplate.expect.element('@title').visible; templates.section.editWorkflowJobTemplate.expect.element('@title').text.contain(data.workflow.name);