From 73fa8521d076f58c2642ff0079a1cb131590dd48 Mon Sep 17 00:00:00 2001 From: Jake McDermott Date: Sat, 2 Dec 2017 22:06:01 -0500 Subject: [PATCH] add e2e test for job and workflow template copy --- awx/ui/test/e2e/fixtures.js | 62 +++++-- .../e2e/tests/test-templates-list-actions.js | 161 ++++++++++++++++++ 2 files changed, 212 insertions(+), 11 deletions(-) create mode 100644 awx/ui/test/e2e/tests/test-templates-list-actions.js diff --git a/awx/ui/test/e2e/fixtures.js b/awx/ui/test/e2e/fixtures.js index caaabb5ff3..403028f252 100644 --- a/awx/ui/test/e2e/fixtures.js +++ b/awx/ui/test/e2e/fixtures.js @@ -10,11 +10,10 @@ import { } from './api'; const session = `e2e-${uuid().substr(0, 8)}`; - const store = {}; -const getOrCreate = (endpoint, data) => { - const identifier = Object.keys(data).find(key => ['name', 'username'].includes(key)); +const getOrCreate = (endpoint, data, unique = ['name', 'username', 'id']) => { + const identifier = Object.keys(data).find(key => unique.includes(key)); if (identifier === undefined) { throw new Error('A unique key value must be provided.'); @@ -22,12 +21,10 @@ const getOrCreate = (endpoint, data) => { const identity = data[identifier]; - if (store[endpoint] && store[endpoint][identity]) { - return store[endpoint][identity].then(created => created.data); - } + store[endpoint] = store[endpoint] || {}; - if (!store[endpoint]) { - store[endpoint] = {}; + if (store[endpoint][identity]) { + return store[endpoint][identity].then(created => created.data); } const query = { params: { [identifier]: identity } }; @@ -246,6 +243,47 @@ const getJobTemplate = (namespace = session) => { }))); }; +const getWorkflowTemplate = (namespace = session) => { + const endpoint = '/workflow_job_templates/'; + + const workflowTemplatePromise = getOrganization(namespace) + .then(organization => getOrCreate(endpoint, { + name: `${namespace}-workflow-template` + organization: organization.id, + variables: '---', + extra_vars: '', + })); + + const resources = [ + workflowTemplatePromise, + getInventorySource(namespace), + getUpdatedProject(namespace), + getJobTemplate(namespace), + ]; + + const workflowNodePromise = all(resources) + .then(spread((workflowTemplate, source, project, jobTemplate) => { + const workflowNodes = workflowTemplate.related.workflow_nodes; + const unique = 'unified_job_template'; + + const nodes = [ + getOrCreate(workflowNodes, { [unique]: project.id }, [unique]), + getOrCreate(workflowNodes, { [unique]: jobTemplate.id }, [unique]), + getOrCreate(workflowNodes, { [unique]: source.id }, [unique]), + ]; + + const createSuccessNodes = (projectNode, jobNode, sourceNode) => all([ + getOrCreate(projectNode.related.success_nodes, { id: jobNode.id }), + getOrCreate(jobNode.related.success_nodes, { id: sourceNode.id }), + ]); + + return all(nodes).then(spread(createSuccessNodes)); + })); + + return all([workflowTemplatePromise, workflowNodePromise]) + .then(spread((workflowTemplate, nodes) => workflowTemplate)); +}; + const getAuditor = (namespace = session) => getOrganization(namespace) .then(organization => getOrCreate('/users/', { username: `auditor-${uuid().substr(0, 8)}`, @@ -334,21 +372,23 @@ module.exports = { getAdminAWSCredential, getAdminMachineCredential, getAuditor, + getHost, getInventory, getInventoryScript, getInventorySource, getInventorySourceSchedule, + getJob, getJobTemplate, getJobTemplateAdmin, getJobTemplateSchedule, getNotificationTemplate, - getOrCreate, getOrganization, + getProject, getProjectAdmin, getSmartInventory, getTeam, getUpdatedProject, getUser, - getJob, - getHost, + getUser, + getWorkflowTemplate, }; diff --git a/awx/ui/test/e2e/tests/test-templates-list-actions.js b/awx/ui/test/e2e/tests/test-templates-list-actions.js new file mode 100644 index 0000000000..000338126e --- /dev/null +++ b/awx/ui/test/e2e/tests/test-templates-list-actions.js @@ -0,0 +1,161 @@ +import { + getInventorySource, + getJobTemplate, + getProject, + getWorkflowTemplate +} from '../fixtures'; + +let data; + +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(); + }); + }, + 'copy job template': client => { + const templates = client.page.templates(); + + client.useCss(); + client.resizeWindow(1200, 800); + client.login(); + client.waitForAngular(); + + templates.navigate(); + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + templates.expect.element('smart-search').visible; + templates.expect.element('smart-search input').enabled; + + templates + .sendKeys('smart-search input', `id:>${data.template.id - 1} id:<${data.template.id + 1}`) + .sendKeys('smart-search input', client.Keys.ENTER); + + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); + templates.expect.element(`#row-${data.template.id}`).visible; + templates.expect.element('i[class*="copy"]').visible; + templates.expect.element('i[class*="copy"]').enabled; + + templates.click('i[class*="copy"]'); + 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); + templates.section.addJobTemplate.expect.element('@title').text.not.equal(data.template.name); + templates.expect.element('@save').visible; + templates.expect.element('@save').enabled; + + client.end(); + }, + 'copy workflow template': client => { + const templates = client.page.templates(); + + client.useCss(); + client.resizeWindow(1200, 800); + client.login(); + client.waitForAngular(); + + templates.navigate(); + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + templates.expect.element('smart-search').visible; + templates.expect.element('smart-search input').enabled; + + templates + .sendKeys('smart-search input', `id:>${data.workflow.id - 1} id:<${data.workflow.id + 1}`) + .sendKeys('smart-search input', client.Keys.ENTER); + + templates.waitForElementVisible('div.spinny'); + templates.waitForElementNotVisible('div.spinny'); + + templates.expect.element('.at-Panel-headingTitleBadge').text.equal('1'); + templates.expect.element(`#row-${data.workflow.id}`).visible; + templates.expect.element('i[class*="copy"]').visible; + templates.expect.element('i[class*="copy"]').enabled; + + templates + .click('i[class*="copy"]') + .waitForElementVisible('div.spinny') + .waitForElementNotVisible('div.spinny') + .waitForAngular(); + + 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); + templates.section.editWorkflowJobTemplate.expect.element('@title').text.not.equal(data.workflow.name); + + templates.expect.element('@save').visible; + templates.expect.element('@save').enabled; + + client + .useXpath() + .pause(1000) + .waitForElementVisible('//*[text()=" Workflow Editor"]') + .click('//*[text()=" Workflow Editor"]') + .useCss() + .waitForElementVisible('div.spinny') + .waitForElementNotVisible('div.spinny') + .waitForAngular(); + + client.expect.element('#workflow-modal-dialog').visible; + client.expect.element('#workflow-modal-dialog span[class^="badge"]').visible; + client.expect.element('#workflow-modal-dialog span[class^="badge"]').text.equal('3'); + client.expect.element('div[class="WorkflowMaker-title"]').visible; + client.expect.element('div[class="WorkflowMaker-title"]').text.contain(data.workflow.name); + client.expect.element('div[class="WorkflowMaker-title"]').text.not.equal(data.workflow.name); + + client.expect.element('#workflow-modal-dialog i[class*="fa-cog"]').visible; + client.expect.element('#workflow-modal-dialog i[class*="fa-cog"]').enabled; + + client.click('#workflow-modal-dialog i[class*="fa-cog"]'); + + client.waitForElementVisible('workflow-controls'); + client.waitForElementVisible('div[class*="-zoomPercentage"]'); + + client.click('i[class*="fa-home"]').expect.element('div[class*="-zoomPercentage"]').text.equal('100%'); + client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('90%'); + client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('80%'); + client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('70%'); + client.click('i[class*="fa-minus"]').expect.element('div[class*="-zoomPercentage"]').text.equal('60%'); + + client.expect.element('#node-1').visible; + client.expect.element('#node-2').visible; + client.expect.element('#node-3').visible; + client.expect.element('#node-4').visible; + + client.expect.element('#node-1 text').text.not.equal('').after(5000); + client.expect.element('#node-2 text').text.not.equal('').after(5000); + client.expect.element('#node-3 text').text.not.equal('').after(5000); + client.expect.element('#node-4 text').text.not.equal('').after(5000); + + const checkNodeText = (selector, text) => client.getText(selector, ({ value }) => { + client.assert.equal(text.indexOf(value.replace('...', '')) >= 0, true); + }); + + checkNodeText('#node-1 text', 'START'); + checkNodeText('#node-2 text', data.project.name); + checkNodeText('#node-3 text', data.template.name); + checkNodeText('#node-4 text', data.source.name); + + templates.expect.element('@save').visible; + templates.expect.element('@save').enabled; + + client.end(); + } +};