mirror of
https://github.com/ansible/awx.git
synced 2026-05-10 02:47:36 -02:30
Combine test directories
This commit is contained in:
16
awx/ui/test/e2e/objects/sections/actions.js
Normal file
16
awx/ui/test/e2e/objects/sections/actions.js
Normal file
@@ -0,0 +1,16 @@
|
||||
const actions = {
|
||||
selector: 'td[class="List-actionsContainer"]',
|
||||
elements: {
|
||||
launch: 'i[class="fa icon-launch"]',
|
||||
schedule: 'i[class="fa icon-schedule"]',
|
||||
copy: 'i[class="fa icon-copy"]',
|
||||
edit: 'i[class="fa icon-pencil"]',
|
||||
delete: 'i[class="fa icon-trash-o"]',
|
||||
view: 'i[class="fa fa-search-plus"]',
|
||||
sync: 'i[class="fa fa-cloud-download"]',
|
||||
test: 'i[class="fa fa-bell-o'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = actions;
|
||||
8
awx/ui/test/e2e/objects/sections/breadcrumb.js
Normal file
8
awx/ui/test/e2e/objects/sections/breadcrumb.js
Normal file
@@ -0,0 +1,8 @@
|
||||
const breadcrumb = {
|
||||
selector: 'bread-crumb > div',
|
||||
elements: {
|
||||
activity: 'i[class$="icon-activity-stream"]'
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = breadcrumb;
|
||||
126
awx/ui/test/e2e/objects/sections/createFormSection.js
Normal file
126
awx/ui/test/e2e/objects/sections/createFormSection.js
Normal file
@@ -0,0 +1,126 @@
|
||||
import { merge } from 'lodash';
|
||||
|
||||
|
||||
const translated = "translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')";
|
||||
const normalized = `normalize-space(${translated})`;
|
||||
|
||||
|
||||
const inputContainerElements = {
|
||||
lookup: 'button > i[class="fa fa-search"]',
|
||||
error: '.at-InputMessage--rejected',
|
||||
help: 'i[class$="fa-question-circle"]',
|
||||
hint: '.at-InputLabel-hint',
|
||||
label: 'label',
|
||||
popover: '.at-Popover-container',
|
||||
yaml: 'input[type="radio", value="yaml"]',
|
||||
json: 'input[type="radio", value="json"]',
|
||||
revert: 'a[class~="reset"]',
|
||||
down: 'span[class^="fa-angle-down"]',
|
||||
up: 'span[class^="fa-angle-up"]',
|
||||
prompt: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//p[${normalized}='prompt on launch']/preceding-sibling::input`
|
||||
},
|
||||
show: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='show']`
|
||||
},
|
||||
hide: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='hide']`
|
||||
},
|
||||
on: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='on']`
|
||||
},
|
||||
off: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//button[${normalized}='off']`
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
const legacyContainerElements = merge({}, inputContainerElements, {
|
||||
prompt: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//label[${normalized}='prompt on launch']/input`
|
||||
},
|
||||
error: 'div[class~="error"]',
|
||||
popover: ':root div[id^="popover"]',
|
||||
});
|
||||
|
||||
|
||||
const generateInputSelectors = function(label, containerElements) {
|
||||
// descend until span with matching text attribute is encountered
|
||||
let span = `.//span[text()="${label}"]`;
|
||||
// recurse upward until div with form-group in class attribute is encountered
|
||||
let container = `${span}/ancestor::div[contains(@class, 'form-group')]`;
|
||||
// descend until element with form-control in class attribute is encountered
|
||||
let input = `${container}//*[contains(@class, 'form-control')]`;
|
||||
|
||||
let inputContainer = {
|
||||
locateStrategy: 'xpath',
|
||||
selector: container,
|
||||
elements: containerElements
|
||||
};
|
||||
|
||||
let inputElement = {
|
||||
locateStrategy: 'xpath',
|
||||
selector: input
|
||||
};
|
||||
|
||||
return { inputElement, inputContainer };
|
||||
};
|
||||
|
||||
|
||||
const checkAllFieldsDisabled = function() {
|
||||
let client = this.client.api;
|
||||
|
||||
let selectors = this.props.formElementSelectors ? this.props.formElementSelectors : [
|
||||
'.at-Input'
|
||||
];
|
||||
|
||||
selectors.forEach(function(selector) {
|
||||
client.elements('css selector', selector, inputs => {
|
||||
inputs.value.map(o => o.ELEMENT).forEach(id => {
|
||||
client.elementIdAttribute(id, 'disabled', ({ value }) => {
|
||||
client.assert.equal(value, 'true');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
const generatorOptions = {
|
||||
default: inputContainerElements,
|
||||
legacy: legacyContainerElements
|
||||
};
|
||||
|
||||
|
||||
const createFormSection = function({ selector, labels, strategy, props }) {
|
||||
let options = generatorOptions[strategy || 'default'];
|
||||
|
||||
let formSection = {
|
||||
selector,
|
||||
sections: {},
|
||||
elements: {},
|
||||
commands: [{
|
||||
checkAllFieldsDisabled: checkAllFieldsDisabled
|
||||
}],
|
||||
props: props
|
||||
};
|
||||
|
||||
for (let key in labels) {
|
||||
let label = labels[key];
|
||||
|
||||
let { inputElement, inputContainer } = generateInputSelectors(label, options);
|
||||
|
||||
formSection.elements[key] = inputElement;
|
||||
formSection.sections[key] = inputContainer;
|
||||
}
|
||||
|
||||
return formSection;
|
||||
};
|
||||
|
||||
module.exports = createFormSection;
|
||||
63
awx/ui/test/e2e/objects/sections/createTableSection.js
Normal file
63
awx/ui/test/e2e/objects/sections/createTableSection.js
Normal file
@@ -0,0 +1,63 @@
|
||||
import dynamicSection from './dynamicSection.js';
|
||||
|
||||
|
||||
const header = {
|
||||
selector: 'thead',
|
||||
sections: {
|
||||
dynamicSection
|
||||
},
|
||||
commands: [{
|
||||
findColumnByText(text) {
|
||||
return this.section.dynamicSection.create({
|
||||
name: `column[${text}]`,
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//*[normalize-space(text())='${text}']/ancestor-or-self::th`,
|
||||
elements: {
|
||||
sortable: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: './/*[contains(@class, "fa-sort")]'
|
||||
},
|
||||
sorted: {
|
||||
locateStrategy: 'xpath',
|
||||
selector: './/*[contains(@class, "fa-sort-")]'
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
|
||||
const createTableSection = function({ elements, sections, commands }) {
|
||||
return {
|
||||
selector: 'table',
|
||||
sections: {
|
||||
header,
|
||||
dynamicSection
|
||||
},
|
||||
commands: [{
|
||||
findRowByText(text) {
|
||||
return this.section.dynamicSection.create({
|
||||
elements,
|
||||
sections,
|
||||
commands,
|
||||
name: `row[${text}]`,
|
||||
locateStrategy: 'xpath',
|
||||
selector: `.//tbody/tr/td//*[normalize-space(text())='${text}']/ancestor::tr`
|
||||
});
|
||||
},
|
||||
waitForRowCount(count) {
|
||||
let countReached = `tbody tr:nth-of-type(${count})`;
|
||||
this.waitForElementPresent(countReached);
|
||||
|
||||
let countExceeded = `tbody tr:nth-of-type(${count + 1})`;
|
||||
this.waitForElementNotPresent(countExceeded);
|
||||
|
||||
return this;
|
||||
}
|
||||
}]
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
module.exports = createTableSection;
|
||||
26
awx/ui/test/e2e/objects/sections/dynamicSection.js
Normal file
26
awx/ui/test/e2e/objects/sections/dynamicSection.js
Normal file
@@ -0,0 +1,26 @@
|
||||
const dynamicSection = {
|
||||
selector: '.',
|
||||
commands: [{
|
||||
create({ name, locateStrategy, selector, elements, sections, commands }) {
|
||||
let Section = this.constructor;
|
||||
|
||||
let options = Object.assign(Object.create(this), {
|
||||
name,
|
||||
locateStrategy,
|
||||
elements,
|
||||
selector,
|
||||
sections,
|
||||
commands
|
||||
});
|
||||
|
||||
options.elements.self = {
|
||||
locateStrategy: 'xpath',
|
||||
selector: '.'
|
||||
};
|
||||
|
||||
return new Section(options);
|
||||
}
|
||||
}]
|
||||
};
|
||||
|
||||
module.exports = dynamicSection;
|
||||
12
awx/ui/test/e2e/objects/sections/header.js
Normal file
12
awx/ui/test/e2e/objects/sections/header.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const header = {
|
||||
selector: 'div[class="at-Layout-topNav"]',
|
||||
elements: {
|
||||
logo: 'div[class$="logo"] img',
|
||||
user: 'i[class="fa fa-user"] + span',
|
||||
documentation: 'i[class="fa fa-book"]',
|
||||
logout: 'i[class="fa fa-power-off"]',
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = header;
|
||||
27
awx/ui/test/e2e/objects/sections/lookupModal.js
Normal file
27
awx/ui/test/e2e/objects/sections/lookupModal.js
Normal file
@@ -0,0 +1,27 @@
|
||||
import createTableSection from './createTableSection.js';
|
||||
import pagination from './pagination.js';
|
||||
import search from './search.js';
|
||||
|
||||
|
||||
const lookupModal = {
|
||||
selector: '#form-modal',
|
||||
elements: {
|
||||
close: 'i[class="fa fa-times-circle"]',
|
||||
title: 'div[class^="Form-title"]',
|
||||
select: 'button[class*="save"]',
|
||||
cancel: 'button[class*="cancel"]'
|
||||
},
|
||||
sections: {
|
||||
search,
|
||||
pagination,
|
||||
table: createTableSection({
|
||||
elements: {
|
||||
name: 'td[class~="name-column"]',
|
||||
selected: 'input[type="radio", value="1"]',
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = lookupModal;
|
||||
25
awx/ui/test/e2e/objects/sections/navigation.js
Normal file
25
awx/ui/test/e2e/objects/sections/navigation.js
Normal file
@@ -0,0 +1,25 @@
|
||||
const navigation = {
|
||||
selector: 'div[class^="at-Layout-side"]',
|
||||
elements: {
|
||||
expand: 'i[class$="fa-bars"]',
|
||||
dashboard: 'i[class$="fa-tachometer"]',
|
||||
jobs: 'i[class$="fa-spinner"]',
|
||||
schedules: 'i[class$="fa-calendar"]',
|
||||
portal: 'i[class$="fa-columns"]',
|
||||
projects: 'i[class$="fa-folder-open"]',
|
||||
credentials: 'i[class$="fa-key"]',
|
||||
credentialTypes: 'i[class$="fa-list-alt"]',
|
||||
inventories: 'i[class$="fa-sitemap"]',
|
||||
templates: 'i[class$="fa-pencil-square-o"]',
|
||||
organizations: 'i[class$="fa-building"]',
|
||||
users: 'i[class$="fa-user"]',
|
||||
teams: 'i[class$="fa-users"]',
|
||||
inventoryScripts: 'i[class$="fa-code"]',
|
||||
notifications: 'i[class$="fa-bell"]',
|
||||
managementJobs: 'i[class$="fa-wrench"]',
|
||||
instanceGroups: 'i[class$="fa-server"]'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = navigation;
|
||||
13
awx/ui/test/e2e/objects/sections/pagination.js
Normal file
13
awx/ui/test/e2e/objects/sections/pagination.js
Normal file
@@ -0,0 +1,13 @@
|
||||
const pagination = {
|
||||
selector: 'paginate div',
|
||||
elements: {
|
||||
first: 'i[class="fa fa-angle-double-left"]',
|
||||
previous: 'i[class="fa fa-angle-left"]',
|
||||
next: 'i[class="fa fa-angle-right"]',
|
||||
last: 'i[class="fa fa-angle-double-right"]',
|
||||
pageCount: 'span[class~="pageof"]',
|
||||
itemCount: 'span[class~="itemsOf"]',
|
||||
}
|
||||
};
|
||||
|
||||
module.exports = pagination;
|
||||
30
awx/ui/test/e2e/objects/sections/permissions.js
Normal file
30
awx/ui/test/e2e/objects/sections/permissions.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import actions from './actions.js';
|
||||
import createTableSection from './createTableSection.js';
|
||||
import pagination from './pagination.js';
|
||||
import search from './search.js';
|
||||
|
||||
|
||||
const permissions = {
|
||||
selector: 'div[ui-view="related"]',
|
||||
elements: {
|
||||
add: 'button[class="btn List-buttonSubmit"]',
|
||||
badge: 'div[class="List-titleBadge]',
|
||||
titleText: 'div[class="List-titleText"]',
|
||||
noitems: 'div[class="List-noItems"]'
|
||||
},
|
||||
sections: {
|
||||
search,
|
||||
pagination,
|
||||
table: createTableSection({
|
||||
elements: {
|
||||
username: 'td[class~="username"]',
|
||||
roles: 'td role-list:nth-of-type(1)',
|
||||
teamRoles: 'td role-list:nth-of-type(2)'
|
||||
},
|
||||
sections: { actions }
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = permissions;
|
||||
12
awx/ui/test/e2e/objects/sections/search.js
Normal file
12
awx/ui/test/e2e/objects/sections/search.js
Normal file
@@ -0,0 +1,12 @@
|
||||
const search = {
|
||||
selector: 'smart-search',
|
||||
elements: {
|
||||
clearAll: '.SmartSearch-clearAll',
|
||||
searchButton: '.SmartSearch-searchButton',
|
||||
input: '.SmartSearch-input',
|
||||
tags: '.SmartSearch-tagContainer'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
module.exports = search;
|
||||
Reference in New Issue
Block a user