From b02677a8d08e5fa4549f1cd3c46368c011234002 Mon Sep 17 00:00:00 2001 From: Daniel Sami Date: Tue, 9 Oct 2018 16:32:24 -0400 Subject: [PATCH 1/4] Initial commit for UI tests for always nodes --- awx/ui/test/e2e/commands/findThenClick.js | 7 +++ .../e2e/tests/test-workflow-visualizer.js | 53 +++++++++++++++++++ 2 files changed, 60 insertions(+) create mode 100644 awx/ui/test/e2e/commands/findThenClick.js create mode 100644 awx/ui/test/e2e/tests/test-workflow-visualizer.js diff --git a/awx/ui/test/e2e/commands/findThenClick.js b/awx/ui/test/e2e/commands/findThenClick.js new file mode 100644 index 0000000000..908f1a190b --- /dev/null +++ b/awx/ui/test/e2e/commands/findThenClick.js @@ -0,0 +1,7 @@ +exports.command = function findThenClick (selector) { + this + .waitForElementPresent(selector) + .moveToElement(selector, 0, 0) + .click(selector); + return this; +}; diff --git a/awx/ui/test/e2e/tests/test-workflow-visualizer.js b/awx/ui/test/e2e/tests/test-workflow-visualizer.js new file mode 100644 index 0000000000..497de1b52b --- /dev/null +++ b/awx/ui/test/e2e/tests/test-workflow-visualizer.js @@ -0,0 +1,53 @@ +import { + getInventorySource, + getJobTemplate, + getProject, + getWorkflowTemplate +} from '../fixtures'; + +let data; +const workflowTemplateNavTab = "//at-side-nav-item[contains(@name, 'TEMPLATES')]"; +const workflowSelector = "//a[contains(text(), 'test-actions-workflow-template')]"; +const workflowVisualizerBtn = "//button[contains(@id, 'workflow_job_template_workflow_visualizer_btn')]"; + +const rootNode = "//*[@id='node-2']"; +const childNode = ""; +const leafNode = "//g[contains(@id, 'node-1')]"; +const project = "//td[contains(text(), 'test-actions-project')]"; +const edgeTypeDropdown = "//span[contains(@id, 'select2-workflow_node_edge-container')]"; +const alwaysDropdown = "//*[@id='select2-workflow_node_edge-result-elm7-always']" +const successDropdown = "//*[@id='select2-workflow_node_edge-result-veyc-success']" +const failureDropdown = "//*[@id='select2-workflow_node_edge-result-xitr-failure']" + +module.exports = { + before: (client, done) => { + const resources = [ + getInventorySource('test-actions'), + getJobTemplate('test-actions'), + getProject('test-actions'), + getWorkflowTemplate('test-actions'), + ]; + + Promise.all(resources) + .then(([source, template, project, workflow]) => { + data = { source, template, project, workflow }; + done(); + }); + client + .login() + .waitForAngular() + .resizeWindow(1200, 1000) + .useXpath() + .findThenClick(workflowTemplateNavTab) + .pause(1000) + .findThenClick(workflowSelector) + .findThenClick(workflowVisualizerBtn); + }, + 'verify that workflow visualizer root node can only be set to always': client => { + client + .useXpath() + .findThenClick(rootNode) + .findThenClick(project) + .findThenClick(edgeTypeDropdown); + }, +}; From 8fceaf88108dc52f298a7e88c74e94d86220b6c9 Mon Sep 17 00:00:00 2001 From: Daniel Sami Date: Thu, 11 Oct 2018 12:14:00 -0400 Subject: [PATCH 2/4] Tests for UI workflow always nodes --- awx/ui/test/e2e/commands/findThenClick.js | 9 +- .../e2e/tests/test-workflow-visualizer.js | 95 +++++++++++++++++-- 2 files changed, 90 insertions(+), 14 deletions(-) diff --git a/awx/ui/test/e2e/commands/findThenClick.js b/awx/ui/test/e2e/commands/findThenClick.js index 908f1a190b..178cf3a784 100644 --- a/awx/ui/test/e2e/commands/findThenClick.js +++ b/awx/ui/test/e2e/commands/findThenClick.js @@ -1,7 +1,8 @@ exports.command = function findThenClick (selector) { - this - .waitForElementPresent(selector) - .moveToElement(selector, 0, 0) - .click(selector); + this.waitForElementPresent(selector, function() { + this.moveToElement(selector, 0, 0, function() { + this.click(selector); + }); + }); return this; }; diff --git a/awx/ui/test/e2e/tests/test-workflow-visualizer.js b/awx/ui/test/e2e/tests/test-workflow-visualizer.js index 497de1b52b..67e7053d49 100644 --- a/awx/ui/test/e2e/tests/test-workflow-visualizer.js +++ b/awx/ui/test/e2e/tests/test-workflow-visualizer.js @@ -11,13 +11,23 @@ const workflowSelector = "//a[contains(text(), 'test-actions-workflow-template') const workflowVisualizerBtn = "//button[contains(@id, 'workflow_job_template_workflow_visualizer_btn')]"; const rootNode = "//*[@id='node-2']"; -const childNode = ""; -const leafNode = "//g[contains(@id, 'node-1')]"; -const project = "//td[contains(text(), 'test-actions-project')]"; -const edgeTypeDropdown = "//span[contains(@id, 'select2-workflow_node_edge-container')]"; -const alwaysDropdown = "//*[@id='select2-workflow_node_edge-result-elm7-always']" -const successDropdown = "//*[@id='select2-workflow_node_edge-result-veyc-success']" -const failureDropdown = "//*[@id='select2-workflow_node_edge-result-xitr-failure']" +const childNode = "//*[@id='node-3']"; +const newChildNode = "//*[@id='node-5']"; +const leafNode = "//*[@id='node-6']"; +const nodeAdd = "//*[contains(@class, 'nodeAddCross')]"; +const nodeRemove = "//*[contains(@class, 'nodeRemoveCross')]"; + +//one of the jobs or projects or inventories +const testActionsProject = "//td[contains(text(), 'test-actions-project')]"; +const testActionsJob = "//td[contains(text(), 'test-actions-job')]"; + +// dropdown bar which lets you select edge type +const edgeTypeDropdownBar = "//span[contains(@id, 'select2-workflow_node_edge-container')]"; +const alwaysDropdown = "//li[contains(@id, 'select2-workflow_node_edge') and text()='Always']"; +const successDropdown = "//li[contains(@id, 'select2-workflow_node_edge') and text()='On Success']"; +const failureDropdown = "//li[contains(@id, 'select2-workflow_node_edge') and text()='On Failure']"; +const selectButton = "//*[@id='workflow_maker_select_btn']"; +const deleteConfirmation = "//button[@ng-click='confirmDeleteNode()']"; module.exports = { before: (client, done) => { @@ -39,7 +49,7 @@ module.exports = { .resizeWindow(1200, 1000) .useXpath() .findThenClick(workflowTemplateNavTab) - .pause(1000) + .pause(1500) .findThenClick(workflowSelector) .findThenClick(workflowVisualizerBtn); }, @@ -47,7 +57,72 @@ module.exports = { client .useXpath() .findThenClick(rootNode) - .findThenClick(project) - .findThenClick(edgeTypeDropdown); + .findThenClick(testActionsProject) + .findThenClick(edgeTypeDropdownBar) + .waitForElementNotPresent(successDropdown) + .waitForElementNotPresent(failureDropdown) + .waitForElementPresent(alwaysDropdown); }, + 'verify that a non-root node can be set to always/success/failure': client => { + client + .useXpath() + .findThenClick(childNode) + .pause(1000) + .findThenClick(edgeTypeDropdownBar) + .waitForElementPresent(successDropdown) + .waitForElementPresent(failureDropdown) + .waitForElementPresent(alwaysDropdown) + .findThenClick(edgeTypeDropdownBar); + }, + 'verify that a sibling node can be any edge type': client => { + client + .useXpath() + .moveToElement(childNode, 0, 0, function() { + client.pause(500); + // Concatenating the xpaths lets us click the proper node + client.click(childNode+nodeAdd); + }) + .pause(1000) + .findThenClick(testActionsJob) + .pause(1000) + .findThenClick(edgeTypeDropdownBar) + .waitForElementPresent(successDropdown) + .waitForElementPresent(failureDropdown) + .waitForElementPresent(alwaysDropdown) + .findThenClick(alwaysDropdown) + .click(selectButton); + }, + 'Verify node-shifting behavior upon deletion': client => { + client + .findThenClick(newChildNode) + .pause(1000) + .findThenClick(edgeTypeDropdownBar) + .findThenClick(successDropdown) + .click(selectButton) + .moveToElement(newChildNode, 0, 0, function() { + client.pause(500); + client.click(newChildNode+nodeAdd); + }) + .pause(1000) + .findThenClick(testActionsJob) + .pause(1000) + .findThenClick(edgeTypeDropdownBar) + .waitForElementPresent(successDropdown) + .waitForElementPresent(failureDropdown) + .waitForElementPresent(alwaysDropdown) + .findThenClick(alwaysDropdown) + .click(selectButton) + .moveToElement(newChildNode, 0, 0, function() { + client.pause(500); + client.click(newChildNode+nodeRemove); + }) + .pause(1000) + .findThenClick(deleteConfirmation) + .findThenClick(leafNode) + .pause(1000) + .findThenClick(edgeTypeDropdownBar) + .waitForElementPresent(successDropdown) + .waitForElementPresent(failureDropdown) + .waitForElementPresent(alwaysDropdown); + } }; From 1e3c2294603758ccb27414deb056508db749a3b9 Mon Sep 17 00:00:00 2001 From: Daniel Sami Date: Thu, 11 Oct 2018 12:24:55 -0400 Subject: [PATCH 3/4] lint fixes --- awx/ui/test/e2e/commands/findThenClick.js | 4 ++-- awx/ui/test/e2e/tests/test-workflow-visualizer.js | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/awx/ui/test/e2e/commands/findThenClick.js b/awx/ui/test/e2e/commands/findThenClick.js index 178cf3a784..82dc2b62f9 100644 --- a/awx/ui/test/e2e/commands/findThenClick.js +++ b/awx/ui/test/e2e/commands/findThenClick.js @@ -1,6 +1,6 @@ exports.command = function findThenClick (selector) { - this.waitForElementPresent(selector, function() { - this.moveToElement(selector, 0, 0, function() { + this.waitForElementPresent(selector, () => { + this.moveToElement(selector, 0, 0, () => { this.click(selector); }); }); diff --git a/awx/ui/test/e2e/tests/test-workflow-visualizer.js b/awx/ui/test/e2e/tests/test-workflow-visualizer.js index 67e7053d49..6a118566fd 100644 --- a/awx/ui/test/e2e/tests/test-workflow-visualizer.js +++ b/awx/ui/test/e2e/tests/test-workflow-visualizer.js @@ -17,7 +17,7 @@ const leafNode = "//*[@id='node-6']"; const nodeAdd = "//*[contains(@class, 'nodeAddCross')]"; const nodeRemove = "//*[contains(@class, 'nodeRemoveCross')]"; -//one of the jobs or projects or inventories +// one of the jobs or projects or inventories const testActionsProject = "//td[contains(text(), 'test-actions-project')]"; const testActionsJob = "//td[contains(text(), 'test-actions-job')]"; @@ -77,10 +77,10 @@ module.exports = { 'verify that a sibling node can be any edge type': client => { client .useXpath() - .moveToElement(childNode, 0, 0, function() { + .moveToElement(childNode, 0, 0, () => { client.pause(500); // Concatenating the xpaths lets us click the proper node - client.click(childNode+nodeAdd); + client.click(childNode + nodeAdd); }) .pause(1000) .findThenClick(testActionsJob) @@ -99,9 +99,9 @@ module.exports = { .findThenClick(edgeTypeDropdownBar) .findThenClick(successDropdown) .click(selectButton) - .moveToElement(newChildNode, 0, 0, function() { + .moveToElement(newChildNode, 0, 0, () => { client.pause(500); - client.click(newChildNode+nodeAdd); + client.click(newChildNode + nodeAdd); }) .pause(1000) .findThenClick(testActionsJob) @@ -112,9 +112,9 @@ module.exports = { .waitForElementPresent(alwaysDropdown) .findThenClick(alwaysDropdown) .click(selectButton) - .moveToElement(newChildNode, 0, 0, function() { + .moveToElement(newChildNode, 0, 0, () => { client.pause(500); - client.click(newChildNode+nodeRemove); + client.click(newChildNode + nodeRemove); }) .pause(1000) .findThenClick(deleteConfirmation) From c25d2084657eeb24ee739bbb3025d9227fc7de03 Mon Sep 17 00:00:00 2001 From: Daniel Sami Date: Fri, 12 Oct 2018 10:18:49 -0400 Subject: [PATCH 4/4] added browser close at end, waits for spinners --- .../test/e2e/tests/test-workflow-visualizer.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/awx/ui/test/e2e/tests/test-workflow-visualizer.js b/awx/ui/test/e2e/tests/test-workflow-visualizer.js index 6a118566fd..5d6a3d570b 100644 --- a/awx/ui/test/e2e/tests/test-workflow-visualizer.js +++ b/awx/ui/test/e2e/tests/test-workflow-visualizer.js @@ -6,6 +6,7 @@ import { } from '../fixtures'; let data; +const spinny = "//*[contains(@class, 'spinny')]"; const workflowTemplateNavTab = "//at-side-nav-item[contains(@name, 'TEMPLATES')]"; const workflowSelector = "//a[contains(text(), 'test-actions-workflow-template')]"; const workflowVisualizerBtn = "//button[contains(@id, 'workflow_job_template_workflow_visualizer_btn')]"; @@ -50,6 +51,7 @@ module.exports = { .useXpath() .findThenClick(workflowTemplateNavTab) .pause(1500) + .waitForElementNotVisible(spinny) .findThenClick(workflowSelector) .findThenClick(workflowVisualizerBtn); }, @@ -68,6 +70,7 @@ module.exports = { .useXpath() .findThenClick(childNode) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(edgeTypeDropdownBar) .waitForElementPresent(successDropdown) .waitForElementPresent(failureDropdown) @@ -79,12 +82,15 @@ module.exports = { .useXpath() .moveToElement(childNode, 0, 0, () => { client.pause(500); + client.waitForElementNotVisible(spinny); // Concatenating the xpaths lets us click the proper node client.click(childNode + nodeAdd); }) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(testActionsJob) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(edgeTypeDropdownBar) .waitForElementPresent(successDropdown) .waitForElementPresent(failureDropdown) @@ -96,16 +102,20 @@ module.exports = { client .findThenClick(newChildNode) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(edgeTypeDropdownBar) .findThenClick(successDropdown) .click(selectButton) .moveToElement(newChildNode, 0, 0, () => { client.pause(500); + client.waitForElementNotVisible(spinny); client.click(newChildNode + nodeAdd); }) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(testActionsJob) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(edgeTypeDropdownBar) .waitForElementPresent(successDropdown) .waitForElementPresent(failureDropdown) @@ -114,15 +124,21 @@ module.exports = { .click(selectButton) .moveToElement(newChildNode, 0, 0, () => { client.pause(500); + client.waitForElementNotVisible(spinny); client.click(newChildNode + nodeRemove); }) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(deleteConfirmation) .findThenClick(leafNode) .pause(1000) + .waitForElementNotVisible(spinny) .findThenClick(edgeTypeDropdownBar) .waitForElementPresent(successDropdown) .waitForElementPresent(failureDropdown) .waitForElementPresent(alwaysDropdown); + }, + after: client => { + client.end(); } };