De-lint test files and update test,build config

This commit is contained in:
gconsidine
2017-10-10 16:32:11 -04:00
parent 8b6cc0e323
commit 82f81752e4
61 changed files with 1335 additions and 991 deletions

View File

@@ -1,6 +1,7 @@
webpack.*.js
Gruntfile.js Gruntfile.js
karma.*.js karma.*.js
webpack.*.js
nightwatch.*.js
etc etc
coverage coverage
@@ -9,12 +10,10 @@ node_modules
po po
static static
templates templates
tests
client/**/*.js
test
!client/lib/components/**/*.js client/src/**/*.js
!client/lib/models/**/*.js client/assets/**/*.js
!client/lib/services/**/*.js test/spec/**/*.js
!client/features/**/*.js
!client/src/app.start.js !client/src/app.start.js
!client/src/vendor.js

View File

@@ -6,13 +6,19 @@ module.exports = {
'airbnb-base' 'airbnb-base'
], ],
plugins: [ plugins: [
'import' 'import',
'disable'
], ],
settings: { settings: {
'import/resolver': { 'import/resolver': {
webpack: { webpack: {
config: path.join(__dirname, 'build/webpack.development.js') config: path.join(__dirname, 'build/webpack.development.js')
} }
},
'eslint-plugin-disable': {
paths: {
import: ['**/build/*.js']
}
} }
}, },
env: { env: {
@@ -44,7 +50,9 @@ module.exports = {
'no-plusplus': 'off', 'no-plusplus': 'off',
'no-underscore-dangle': 'off', 'no-underscore-dangle': 'off',
'no-use-before-define': 'off', 'no-use-before-define': 'off',
'no-multiple-empty-lines': ['error', { max: 1 }],
'object-curly-newline': 'off', 'object-curly-newline': 'off',
'space-before-function-paren': ['error', 'always'] 'space-before-function-paren': ['error', 'always'],
'no-trailing-spaces': ['error']
} }
}; };

View File

@@ -18,12 +18,13 @@ const LANGUAGES_PATH = path.join(CLIENT_PATH, 'languages');
const MODELS_PATH = path.join(LIB_PATH, 'models'); const MODELS_PATH = path.join(LIB_PATH, 'models');
const NODE_MODULES_PATH = path.join(UI_PATH, 'node_modules'); const NODE_MODULES_PATH = path.join(UI_PATH, 'node_modules');
const SERVICES_PATH = path.join(LIB_PATH, 'services'); const SERVICES_PATH = path.join(LIB_PATH, 'services');
const SOURCE_PATH = path.join(CLIENT_PATH, 'src'); const SRC_PATH = path.join(CLIENT_PATH, 'src');
const STATIC_PATH = path.join(UI_PATH, 'static'); const STATIC_PATH = path.join(UI_PATH, 'static');
const TEST_PATH = path.join(UI_PATH, 'test');
const THEME_PATH = path.join(LIB_PATH, 'theme'); const THEME_PATH = path.join(LIB_PATH, 'theme');
const APP_ENTRY = path.join(SOURCE_PATH, 'app.js'); const APP_ENTRY = path.join(SRC_PATH, 'app.js');
const VENDOR_ENTRY = path.join(SOURCE_PATH, 'vendor.js'); const VENDOR_ENTRY = path.join(SRC_PATH, 'vendor.js');
const INDEX_ENTRY = path.join(CLIENT_PATH, 'index.template.ejs'); const INDEX_ENTRY = path.join(CLIENT_PATH, 'index.template.ejs');
const INDEX_OUTPUT = path.join(UI_PATH, 'templates/ui/index.html'); const INDEX_OUTPUT = path.join(UI_PATH, 'templates/ui/index.html');
const THEME_ENTRY = path.join(LIB_PATH, 'theme', 'index.less'); const THEME_ENTRY = path.join(LIB_PATH, 'theme', 'index.less');
@@ -49,7 +50,7 @@ const base = {
chunks: false, chunks: false,
excludeAssets: name => { excludeAssets: name => {
const chunkNames = `(${CHUNKS.join('|')})`; const chunkNames = `(${CHUNKS.join('|')})`;
const outputPattern = new RegExp(`${chunkNames}\.[a-f0-9]+\.(js|css)(|\.map)$`, 'i'); const outputPattern = new RegExp(`${chunkNames}.[a-f0-9]+.(js|css)(|.map)$`, 'i');
return !outputPattern.test(name); return !outputPattern.test(name);
} }
@@ -82,7 +83,7 @@ const base = {
}) })
}, },
{ {
test: /\lib\/theme\/index.less$/, test: /lib\/theme\/index.less$/,
use: ExtractTextPlugin.extract({ use: ExtractTextPlugin.extract({
use: ['css-loader', 'less-loader'] use: ['css-loader', 'less-loader']
}) })
@@ -92,7 +93,8 @@ const base = {
use: ['ngtemplate-loader', 'html-loader'], use: ['ngtemplate-loader', 'html-loader'],
include: [ include: [
/lib\/components\//, /lib\/components\//,
/features\// /features\//,
/src\//
] ]
}, },
{ {
@@ -149,17 +151,17 @@ const base = {
context: NODE_MODULES_PATH context: NODE_MODULES_PATH
}, },
{ {
from: path.join(SOURCE_PATH, '**/*.partial.html'), from: path.join(SRC_PATH, '**/*.partial.html'),
to: path.join(STATIC_PATH, 'partials/'), to: path.join(STATIC_PATH, 'partials/'),
context: SOURCE_PATH context: SRC_PATH
}, },
{ {
from: path.join(SOURCE_PATH, 'partials', '*.html'), from: path.join(SRC_PATH, 'partials', '*.html'),
to: STATIC_PATH, to: STATIC_PATH,
context: SOURCE_PATH context: SRC_PATH
}, },
{ {
from: path.join(SOURCE_PATH, '*config.js'), from: path.join(SRC_PATH, '*config.js'),
to: STATIC_PATH, to: STATIC_PATH,
flatten: true flatten: true
} }
@@ -170,31 +172,34 @@ const base = {
filename: INDEX_OUTPUT, filename: INDEX_OUTPUT,
inject: false, inject: false,
chunks: CHUNKS, chunks: CHUNKS,
chunksSortMode: chunk => chunk.names[0] === 'vendor' ? -1 : 1 chunksSortMode: chunk => (chunk.names[0] === 'vendor' ? -1 : 1)
}) })
], ],
resolve: { resolve: {
alias: { alias: {
'~assets': ASSETS_PATH,
'~components': COMPONENTS_PATH,
'~features': FEATURES_PATH, '~features': FEATURES_PATH,
'~models': MODELS_PATH, '~models': MODELS_PATH,
'~node_modules': NODE_MODULES_PATH,
'~services': SERVICES_PATH, '~services': SERVICES_PATH,
'~components': COMPONENTS_PATH, '~src': SRC_PATH,
'~test': TEST_PATH,
'~theme': THEME_PATH, '~theme': THEME_PATH,
'~modules': NODE_MODULES_PATH, '~ui': UI_PATH,
'~assets': ASSETS_PATH, d3$: '~node_modules/d3/d3.min.js',
'd3$': '~modules/d3/d3.min.js', 'codemirror.jsonlint$': '~node_modules/codemirror/addon/lint/json-lint.js',
'codemirror.jsonlint$': '~modules/codemirror/addon/lint/json-lint.js', jquery: '~node_modules/jquery/dist/jquery.js',
'jquery': '~modules/jquery/dist/jquery.js', 'jquery-resize$': '~node_modules/javascript-detect-element-resize/jquery.resize.js',
'jquery-resize$': '~modules/javascript-detect-element-resize/jquery.resize.js', select2$: '~node_modules/select2/dist/js/select2.full.min.js',
'select2$': '~modules/select2/dist/js/select2.full.min.js', 'js-yaml$': '~node_modules/js-yaml/dist/js-yaml.min.js',
'js-yaml$': '~modules/js-yaml/dist/js-yaml.min.js', 'lr-infinite-scroll$': '~node_modules/lr-infinite-scroll/lrInfiniteScroll.js',
'lr-infinite-scroll$': '~modules/lr-infinite-scroll/lrInfiniteScroll.js', 'angular-tz-extensions$': '~node_modules/angular-tz-extensions/lib/angular-tz-extensions.js',
'angular-tz-extensions$': '~modules/angular-tz-extensions/lib/angular-tz-extensions.js', 'angular-ui-router$': '~node_modules/angular-ui-router/release/angular-ui-router.js',
'angular-ui-router$': '~modules/angular-ui-router/release/angular-ui-router.js', 'angular-ui-router-state-events$': '~node_modules/angular-ui-router/release/stateEvents.js',
'angular-ui-router-state-events$': '~modules/angular-ui-router/release/stateEvents.js', 'ng-toast-provider$': '~node_modules/ng-toast/src/scripts/provider.js',
'ng-toast-provider$': '~modules/ng-toast/src/scripts/provider.js', 'ng-toast-directives$': '~node_modules/ng-toast/src/scripts/directives.js',
'ng-toast-directives$': '~modules/ng-toast/src/scripts/directives.js', 'ng-toast$': '~node_modules/ng-toast/src/scripts/module.js'
'ng-toast$': '~modules/ng-toast/src/scripts/module.js'
} }
} }
}; };

View File

@@ -1,4 +1,4 @@
const _ = require('lodash'); const merge = require('webpack-merge');
const base = require('./webpack.base'); const base = require('./webpack.base');
@@ -6,4 +6,4 @@ const development = {
devtool: 'source-map' devtool: 'source-map'
}; };
module.exports = _.merge(base, development); module.exports = merge(base, development);

View File

@@ -1,6 +1,6 @@
const path = require('path'); const path = require('path');
const _ = require('lodash'); const merge = require('webpack-merge');
const webpack = require('webpack'); const webpack = require('webpack');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin');
@@ -25,16 +25,14 @@ const production = {
filename: INSTALL_RUNNING_OUTPUT, filename: INSTALL_RUNNING_OUTPUT,
inject: false, inject: false,
chunks: CHUNKS, chunks: CHUNKS,
chunksSortMode: chunk => chunk.names[0] === 'vendor' ? -1 : 1 chunksSortMode: chunk => (chunk.names[0] === 'vendor' ? -1 : 1)
}), }),
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { 'process.env': {
'NODE_ENV': JSON.stringify('production') NODE_ENV: JSON.stringify('production')
} }
}) })
] ]
}; };
production.plugins = base.plugins.concat(production.plugins); module.exports = merge(base, production);
module.exports = _.merge(base, production);

View File

@@ -2,6 +2,8 @@ const path = require('path');
const _ = require('lodash'); const _ = require('lodash');
const webpack = require('webpack'); const webpack = require('webpack');
const merge = require('webpack-merge');
const nodeObjectHash = require('node-object-hash');
const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); const HardSourceWebpackPlugin = require('hard-source-webpack-plugin');
const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin'); const HtmlWebpackHarddiskPlugin = require('html-webpack-harddisk-plugin');
@@ -33,9 +35,7 @@ const watch = {
new HardSourceWebpackPlugin({ new HardSourceWebpackPlugin({
cacheDirectory: 'node_modules/.cache/hard-source/[confighash]', cacheDirectory: 'node_modules/.cache/hard-source/[confighash]',
recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json', recordsPath: 'node_modules/.cache/hard-source/[confighash]/records.json',
configHash: config => { configHash: config => nodeObjectHash({ sort: false }).hash(config),
return require('node-object-hash')({ sort: false }).hash(config);
},
environmentHash: { environmentHash: {
root: process.cwd(), root: process.cwd(),
directories: ['node_modules'], directories: ['node_modules'],
@@ -68,7 +68,4 @@ const watch = {
} }
}; };
watch.module.rules = development.module.rules.concat(watch.module.rules); module.exports = merge(development, watch);
watch.plugins = development.plugins.concat(watch.plugins);
module.exports = _.merge(development, watch);

View File

@@ -2,18 +2,20 @@
require('~assets/custom-theme/jquery-ui-1.10.3.custom.min.css'); require('~assets/custom-theme/jquery-ui-1.10.3.custom.min.css');
require('~assets/ansible-bootstrap.min.css'); require('~assets/ansible-bootstrap.min.css');
require('~assets/fontcustom/fontcustom.css'); require('~assets/fontcustom/fontcustom.css');
require('~modules/components-font-awesome/css/font-awesome.min.css'); require('~node_modules/components-font-awesome/css/font-awesome.min.css');
require('~modules/select2/dist/css/select2.css'); require('~node_modules/select2/dist/css/select2.css');
require('~modules/codemirror/lib/codemirror.css'); require('~node_modules/codemirror/lib/codemirror.css');
require('~modules/codemirror/theme/elegant.css'); require('~node_modules/codemirror/theme/elegant.css');
require('~modules/codemirror/addon/lint/lint.css'); require('~node_modules/codemirror/addon/lint/lint.css');
require('~modules/nvd3/build/nv.d3.css'); require('~node_modules/nvd3/build/nv.d3.css');
require('~modules/ng-toast/dist/ngToast.min.css'); require('~node_modules/ng-toast/dist/ngToast.min.css');
// jQuery + extensions // jQuery + extensions
global.jQuery = require('jquery'); global.jQuery = require('jquery');
global.jquery = global.jQuery; global.jquery = global.jQuery;
global.$ = global.jQuery; global.$ = global.jQuery;
require('jquery-resize'); require('jquery-resize');
require('jquery-ui'); require('jquery-ui');
require('bootstrap'); require('bootstrap');

View File

@@ -21,12 +21,12 @@
"languages": "grunt nggettext_compile", "languages": "grunt nggettext_compile",
"build-release": "npm run production", "build-release": "npm run production",
"pretest": "", "pretest": "",
"test": "karma start karma.conf.js", "test": "karma start test/spec/karma.spec.js",
"jshint": "grunt jshint:source --no-color", "jshint": "grunt jshint:source --no-color",
"test:ci": "npm run test -- --single-run --reporter junit,dots --browsers=PhantomJS", "test:ci": "npm run test -- --single-run --reporter junit,dots --browsers=PhantomJS",
"e2e": "./client/test/e2e/runner.js --config ./client/test/e2e/nightwatch.conf.js", "e2e": "./test/e2e/runner.js --config ./test/e2e/nightwatch.conf.js",
"component-test": "karma start client/test/unit/karma.conf.js", "unit": "karma start test/unit/karma.unit.js",
"lint": "eslint -c .eslintrc.js .", "lint": "eslint .",
"dev": "webpack --config build/webpack.development.js --progress", "dev": "webpack --config build/webpack.development.js --progress",
"watch": "webpack-dev-server --config build/webpack.watch.js --progress", "watch": "webpack-dev-server --config build/webpack.watch.js --progress",
"production": "webpack --config build/webpack.production.js" "production": "webpack --config build/webpack.production.js"
@@ -47,6 +47,7 @@
"eslint-config-airbnb-base": "^12.0.0", "eslint-config-airbnb-base": "^12.0.0",
"eslint-import-resolver-webpack": "^0.8.3", "eslint-import-resolver-webpack": "^0.8.3",
"eslint-loader": "^1.9.0", "eslint-loader": "^1.9.0",
"eslint-plugin-disable": "^0.3.0",
"eslint-plugin-import": "^2.7.0", "eslint-plugin-import": "^2.7.0",
"extract-text-webpack-plugin": "^3.0.0", "extract-text-webpack-plugin": "^3.0.0",
"grunt": "^1.0.1", "grunt": "^1.0.1",
@@ -84,8 +85,10 @@
"phantomjs-prebuilt": "^2.1.12", "phantomjs-prebuilt": "^2.1.12",
"time-grunt": "^1.4.0", "time-grunt": "^1.4.0",
"uglifyjs-webpack-plugin": "^0.4.6", "uglifyjs-webpack-plugin": "^0.4.6",
"uuid": "^3.1.0",
"webpack": "^3.0.0", "webpack": "^3.0.0",
"webpack-dev-server": "^2.7.1" "webpack-dev-server": "^2.7.1",
"webpack-merge": "^4.1.0"
}, },
"dependencies": { "dependencies": {
"angular": "~1.4.14", "angular": "~1.4.14",

View File

@@ -0,0 +1,5 @@
module.exports = {
rules: {
'no-unused-expressions': 'off'
}
};

View File

@@ -6,8 +6,7 @@ import {
awxURL, awxURL,
awxUsername, awxUsername,
awxPassword awxPassword
} from './settings.js'; } from './settings';
let authenticated; let authenticated;
@@ -20,29 +19,22 @@ const session = axios.create({
}) })
}); });
const getEndpoint = location => {
const endpoint = function(location) { if (location.indexOf('/api/v') === 0 || location.indexOf('://') > 0) {
if (location.indexOf('/api/v') === 0) {
return location;
}
if (location.indexOf('://') > 0) {
return location; return location;
} }
return `${awxURL}/api/v2${location}`; return `${awxURL}/api/v2${location}`;
}; };
const authenticate = () => {
const authenticate = function() {
if (authenticated) { if (authenticated) {
return Promise.resolve(); return Promise.resolve();
} }
let uri = endpoint('/authtoken/'); const uri = getEndpoint('/authtoken/');
let credentials = { const credentials = {
username: awxUsername, username: awxUsername,
password: awxPassword password: awxPassword
}; };
@@ -50,48 +42,34 @@ const authenticate = function() {
return session.post(uri, credentials).then(res => { return session.post(uri, credentials).then(res => {
session.defaults.headers.Authorization = `Token ${res.data.token}`; session.defaults.headers.Authorization = `Token ${res.data.token}`;
authenticated = true; authenticated = true;
return res
return res;
}); });
}; };
const request = (method, location, data) => {
const uri = getEndpoint(location);
const action = session[method.toLowerCase()];
const request = function(method, location, data) { return authenticate()
let uri = endpoint(location); .then(() => action(uri, data))
let action = session[method.toLowerCase()]; .then(res => {
console.log([ // eslint-disable-line no-console
return authenticate().then(() => action(uri, data)).then(res => { res.config.method.toUpperCase(),
console.log([ uri,
res.config.method.toUpperCase(), res.status,
uri, res.statusText
res.status, ].join(' '));
res.statusText
].join(' '));
return res; return res;
}); });
};
const get = function(endpoint, data) {
return request('GET', endpoint, data);
};
const options = function(endpoint) {
return request('OPTIONS', endpoint);
};
const post = function(endpoint, data) {
return request('POST', endpoint, data);
};
const patch = function(endpoint, data) {
return request('PATCH', endpoint, data)
};
const put = function(endpoint, data) {
return request('PUT', endpoint, data);
}; };
const get = (endpoint, data) => request('GET', endpoint, data);
const options = endpoint => request('OPTIONS', endpoint);
const post = (endpoint, data) => request('POST', endpoint, data);
const patch = (endpoint, data) => request('PATCH', endpoint, data);
const put = (endpoint, data) => request('PUT', endpoint, data);
module.exports = { module.exports = {
get, get,

View File

@@ -1,5 +1,7 @@
exports.command = function(deps, script, callback) { exports.command = function inject (deps, script, callback) {
this.executeAsync(`let args = Array.prototype.slice.call(arguments,0); this.executeAsync(
`let args = Array.prototype.slice.call(arguments,0);
return function(deps, done) { return function(deps, done) {
let injector = angular.element('body').injector(); let injector = angular.element('body').injector();
let loaded = deps.map(d => { let loaded = deps.map(d => {
@@ -11,11 +13,13 @@ exports.command = function(deps, script, callback) {
}); });
(${script.toString()}).apply(this, loaded).then(done); (${script.toString()}).apply(this, loaded).then(done);
}.apply(this, args);`, }.apply(this, args);`,
[deps], [deps],
function(result) { function handleResult (result) {
if(typeof(callback) === "function") { if (typeof callback === 'function') {
callback.call(this, result.value); callback.call(this, result.value);
}
} }
}); );
return this; return this;
}; };

View File

@@ -1,16 +1,13 @@
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { inherits } from 'util'; import { inherits } from 'util';
function Login () {
const Login = function() {
EventEmitter.call(this); EventEmitter.call(this);
} }
inherits(Login, EventEmitter); inherits(Login, EventEmitter);
Login.prototype.command = function command (username, password) {
Login.prototype.command = function(username, password) {
username = username || this.api.globals.awxUsername; username = username || this.api.globals.awxUsername;
password = password || this.api.globals.awxPassword; password = password || this.api.globals.awxPassword;
@@ -33,16 +30,17 @@ Login.prototype.command = function(username, password) {
this.api.elementIdDisplayed(id, ({ value }) => { this.api.elementIdDisplayed(id, ({ value }) => {
if (!alertVisible && value) { if (!alertVisible && value) {
alertVisible = true; alertVisible = true;
loginPage.setValue('@username', username) loginPage.setValue('@username', username);
loginPage.setValue('@password', password) loginPage.setValue('@password', password);
loginPage.click('@submit') loginPage.click('@submit');
loginPage.waitForElementVisible('div.spinny') loginPage.waitForElementVisible('div.spinny');
loginPage.waitForElementNotVisible('div.spinny'); loginPage.waitForElementNotVisible('div.spinny');
} }
}) });
}) });
this.emit('complete'); this.emit('complete');
}) });
}; };
module.exports = Login; module.exports = Login;

View File

@@ -1,20 +1,17 @@
exports.command = function(callback) { exports.command = function waitForAngular (callback) {
let self = this; this.timeoutsAsyncScript(this.globals.asyncHookTimeout, () => {
this.timeoutsAsyncScript(this.globals.asyncHookTimeout, function() { this.executeAsync(done => {
this.executeAsync(function(done) { if (angular && angular.getTestability) {
if(angular && angular.getTestability) {
angular.getTestability(document.body).whenStable(done); angular.getTestability(document.body).whenStable(done);
} } else {
else {
done(); done();
} }
}, }, [], result => {
[], if (typeof callback === 'function') {
function(result) { callback.call(this, result);
if(typeof(callback) === "function") {
callback.call(self, result);
} }
}); });
}); });
return this; return this;
}; };

View File

@@ -5,22 +5,20 @@ import {
get, get,
post, post,
spread spread
} from './api.js'; } from './api';
const sid = uuid().substr(0, 8);
const sid = uuid().substr(0,8); const store = {};
let store = {}; const getOrCreate = (endpoint, data) => {
const identifier = Object.keys(data).find(key => ['name', 'username'].includes(key));
const getOrCreate = function(endpoint, data) {
let identifier = Object.keys(data).find(key => ['name', 'username'].includes(key));
if (identifier === undefined) { if (identifier === undefined) {
throw new Error('A unique key value must be provided.'); throw new Error('A unique key value must be provided.');
} }
let identity = data[identifier]; const identity = data[identifier];
if (store[endpoint] && store[endpoint][identity]) { if (store[endpoint] && store[endpoint][identity]) {
return store[endpoint][identity].then(created => created.data); return store[endpoint][identity].then(created => created.data);
@@ -30,221 +28,195 @@ const getOrCreate = function(endpoint, data) {
store[endpoint] = {}; store[endpoint] = {};
} }
let query = { params: { [identifier]: identity } }; const query = { params: { [identifier]: identity } };
store[endpoint][identity] = get(endpoint, query).then(res => { store[endpoint][identity] = get(endpoint, query)
.then(res => {
if (res.data.results.length > 1) {
return Promise.reject(new Error('More than one matching result.'));
}
if (res.data.results.length > 1) { if (res.data.results.length === 1) {
return Promise.reject(new Error('More than one matching result.')); return get(res.data.results[0].url);
} }
if (res.data.results.length === 1) { if (res.data.results.length === 0) {
return get(res.data.results[0].url); return post(endpoint, data);
} }
if (res.data.results.length === 0) { return Promise.reject(new Error(`unexpected response: ${res}`));
return post(endpoint, data); });
}
return Promise.reject(new Error(`unexpected response: ${res}`));
});
return store[endpoint][identity].then(created => created.data); return store[endpoint][identity].then(created => created.data);
}; };
const getOrganization = () => getOrCreate('/organizations/', {
name: `e2e-organization-${sid}`
});
const getOrganization = function() { const getInventory = () => getOrganization()
return getOrCreate('/organizations/', { .then(organization => getOrCreate('/inventories/', {
name: `e2e-organization-${sid}` name: `e2e-inventory-${sid}`,
}); organization: organization.id
}; }));
const getInventoryScript = () => getOrganization()
.then(organization => getOrCreate('/inventory_scripts/', {
name: `e2e-inventory-script-${sid}`,
organization: organization.id,
script: '#!/usr/bin/env python'
}));
const getInventory = function() { const getAdminAWSCredential = () => {
return getOrganization().then(organization => { const promises = [
return getOrCreate('/inventories/', {
name: `e2e-inventory-${sid}`,
organization: organization.id
});
});
};
const getInventoryScript = function() {
return getOrganization().then(organization => {
return getOrCreate('/inventory_scripts/', {
name: `e2e-inventory-script-${sid}`,
organization: organization.id,
script: '#!/usr/bin/env python'
});
});
};
const getAdminAWSCredential = function() {
return all([
get('/me/'), get('/me/'),
getOrCreate('/credential_types/', { getOrCreate('/credential_types/', {
name: "Amazon Web Services" name: 'Amazon Web Services'
}) })
]) ];
.then(spread((me, credentialType) => {
let admin = me.data.results[0]; return all(promises)
return getOrCreate('/credentials/', { .then(spread((me, credentialType) => {
name: `e2e-aws-credential-${sid}`, const [admin] = me.data.results;
credential_type: credentialType.id,
user: admin.id, return getOrCreate('/credentials/', {
inputs: { name: `e2e-aws-credential-${sid}`,
username: 'admin', credential_type: credentialType.id,
password: 'password', user: admin.id,
security_token: 'AAAAAAAAAAAAAAAA' inputs: {
} username: 'admin',
}); password: 'password',
})); security_token: 'AAAAAAAAAAAAAAAA'
}
});
}));
}; };
const getAdminMachineCredential = () => {
const getAdminMachineCredential = function() { const promises = [
return all([
get('/me/'), get('/me/'),
getOrCreate('/credential_types/', { name: "Machine" }) getOrCreate('/credential_types/', { name: 'Machine' })
]) ];
.then(spread((me, credentialType) => {
let admin = me.data.results[0]; return all(promises)
return getOrCreate('/credentials/', { .then(spread((me, credentialType) => {
name: `e2e-machine-credential-${sid}`, const [admin] = me.data.results;
credential_type: credentialType.id,
user: admin.id return getOrCreate('/credentials/', {
}); name: `e2e-machine-credential-${sid}`,
credential_type: credentialType.id,
user: admin.id
});
}));
};
const getTeam = () => getOrganization()
.then(organization => getOrCreate('/teams/', {
name: `e2e-team-${sid}`,
organization: organization.id,
})); }));
};
const getSmartInventory = () => getOrganization()
.then(organization => getOrCreate('/inventories/', {
name: `e2e-smart-inventory-${sid}`,
organization: organization.id,
host_filter: 'search=localhost',
kind: 'smart'
}));
const getTeam = function() { const getNotificationTemplate = () => getOrganization()
return getOrganization().then(organization => { .then(organization => getOrCreate('/notification_templates/', {
return getOrCreate('/teams/', { name: `e2e-notification-template-${sid}`,
name: `e2e-team-${sid}`, organization: organization.id,
organization: organization.id, notification_type: 'slack',
}); notification_configuration: {
}); token: '54321GFEDCBAABCDEFG12345',
}; channels: ['awx-e2e']
}
}));
const getProject = () => getOrganization()
.then(organization => getOrCreate('/projects/', {
name: `e2e-project-${sid}`,
organization: organization.id,
scm_url: 'https://github.com/ansible/ansible-tower-samples',
scm_type: 'git'
}));
const getSmartInventory = function() { const waitForJob = endpoint => {
return getOrganization().then(organization => {
return getOrCreate('/inventories/', {
name: `e2e-smart-inventory-${sid}`,
organization: organization.id,
host_filter: 'search=localhost',
kind: 'smart'
});
});
};
const getNotificationTemplate = function() {
return getOrganization().then(organization => {
return getOrCreate('/notification_templates/', {
name: `e2e-notification-template-${sid}`,
organization: organization.id,
notification_type: 'slack',
notification_configuration: {
token: '54321GFEDCBAABCDEFG12345',
channels: ['awx-e2e']
}
});
});
};
const getProject = function() {
return getOrganization().then(organization => {
return getOrCreate('/projects/', {
name: `e2e-project-${sid}`,
organization: organization.id,
scm_url: 'https://github.com/ansible/ansible-tower-samples',
scm_type: 'git'
});
});
};
const waitForJob = function(endpoint) {
const interval = 2000; const interval = 2000;
const statuses = ['successful', 'failed', 'error', 'canceled']; const statuses = ['successful', 'failed', 'error', 'canceled'];
let attempts = 20; let attempts = 20;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
(function pollStatus() { (function pollStatus () {
get(endpoint).then(update => { get(endpoint).then(update => {
let completed = statuses.indexOf(update.data.status) > -1; const completed = statuses.indexOf(update.data.status) > -1;
if (completed) return resolve();
if (--attempts <= 0) return reject('Retry limit exceeded.'); if (completed) {
setTimeout(pollStatus, interval); return resolve();
}
if (--attempts <= 0) {
return reject(new Error('Retry limit exceeded.'));
}
return setTimeout(pollStatus, interval);
}); });
})(); }());
}); });
}; };
const getUpdatedProject = () => getProject()
.then(project => {
const updateURL = project.related.current_update;
const getUpdatedProject = function() {
return getProject().then(project => {
let updateURL = project.related.current_update;
if (updateURL) { if (updateURL) {
return waitForJob(updateURL).then(() => project); return waitForJob(updateURL).then(() => project);
} }
return project; return project;
}); });
};
const getJobTemplate = () => {
const getJobTemplate = function() { const promises = [
return all([
getInventory(), getInventory(),
getAdminMachineCredential(), getAdminMachineCredential(),
getUpdatedProject() getUpdatedProject()
]) ];
.then(spread((inventory, credential, project) => {
return getOrCreate('/job_templates', { return all(promises)
.then(spread((inventory, credential, project) => getOrCreate('/job_templates', {
name: `e2e-job-template-${sid}`, name: `e2e-job-template-${sid}`,
inventory: inventory.id, inventory: inventory.id,
credential: credential.id, credential: credential.id,
project: project.id, project: project.id,
playbook: 'hello_world.yml' playbook: 'hello_world.yml'
}); })));
}));
}; };
const getAuditor = () => getOrganization()
const getAuditor = function() { .then(organization => getOrCreate('/users/', {
return getOrganization().then(organization => { organization: organization.id,
return getOrCreate('/users/', { username: `e2e-auditor-${sid}`,
organization: organization.id, first_name: 'auditor',
username: `e2e-auditor-${sid}`, last_name: 'last',
first_name: 'auditor', email: 'null@ansible.com',
last_name: 'last',
email: 'null@ansible.com',
is_superuser: false,
is_system_auditor: true,
password: 'password'
})
});
};
const getUser = function() {
return getOrCreate('/users/', {
username: `e2e-user-${sid}`,
first_name: `user-${sid}-first`,
last_name: `user-${sid}-last`,
email: `null-${sid}@ansible.com`,
is_superuser: false, is_superuser: false,
is_system_auditor: false, is_system_auditor: true,
password: 'password' password: 'password'
}); }));
};
const getUser = () => getOrCreate('/users/', {
username: `e2e-user-${sid}`,
first_name: `user-${sid}-first`,
last_name: `user-${sid}-last`,
email: `null-${sid}@ansible.com`,
is_superuser: false,
is_system_auditor: false,
password: 'password'
});
module.exports = { module.exports = {
getAdminAWSCredential, getAdminAWSCredential,

View File

@@ -1,6 +1,6 @@
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/activity_stream` return `${this.api.globals.launch_url}/#/activity_stream`;
}, },
elements: { elements: {
title: '.List-titleText', title: '.List-titleText',

View File

@@ -1,11 +1,10 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import search from './sections/search.js'; import search from './sections/search';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
const addEditPanel = { const addEditPanel = {
selector: 'div[ui-view="form"]', selector: 'div[ui-view="form"]',
@@ -16,17 +15,16 @@ const addEditPanel = {
details: createFormSection({ details: createFormSection({
selector: '#credential_type_form', selector: '#credential_type_form',
labels: { labels: {
name: "Name", name: 'Name',
description: "Description", description: 'Description',
inputConfiguration: "Input Configuration", inputConfiguration: 'Input Configuration',
injectorConfiguration: "Injector Configuration" injectorConfiguration: 'Injector Configuration'
}, },
strategy: 'legacy' strategy: 'legacy'
}) })
} }
}; };
const listPanel = { const listPanel = {
selector: 'div[ui-view="list"]', selector: 'div[ui-view="list"]',
elements: { elements: {
@@ -50,10 +48,9 @@ const listPanel = {
} }
}; };
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/credential_types` return `${this.api.globals.launch_url}/#/credential_types`;
}, },
sections: { sections: {
header, header,

View File

@@ -1,153 +1,140 @@
import _ from 'lodash'; import _ from 'lodash';
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import dynamicSection from './sections/dynamicSection.js'; import dynamicSection from './sections/dynamicSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const common = createFormSection({ const common = createFormSection({
selector: 'form', selector: 'form',
labels: { labels: {
name: "Name", name: 'Name',
description: "Description", description: 'Description',
organization: "Organization", organization: 'Organization',
type: "Credential type" type: 'Credential type'
} }
}); });
const machine = createFormSection({ const machine = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
username: "Username", username: 'Username',
password: "Password", password: 'Password',
sshKeyData: "SSH Private Key", sshKeyData: 'SSH Private Key',
sshKeyUnlock: "Private Key Passphrase", sshKeyUnlock: 'Private Key Passphrase',
becomeMethod: "Privilege Escalation Method", becomeMethod: 'Privilege Escalation Method',
becomeUsername: "Privilege Escalation Username", becomeUsername: 'Privilege Escalation Username',
becomePassword: "Privilege Escalation Password" becomePassword: 'Privilege Escalation Password'
} }
}); });
const vault = createFormSection({ const vault = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
vaultPassword: "Vault Password", vaultPassword: 'Vault Password',
} }
}); });
const scm = createFormSection({ const scm = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
username: "Username", username: 'Username',
password: "Password", password: 'Password',
sshKeyData: "SCM Private Key", sshKeyData: 'SCM Private Key',
sshKeyUnlock: "Private Key Passphrase", sshKeyUnlock: 'Private Key Passphrase',
} }
}); });
const aws = createFormSection({ const aws = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
accessKey: "Access Key", accessKey: 'Access Key',
secretKey: "Secret Key", secretKey: 'Secret Key',
securityToken: "STS Token", securityToken: 'STS Token',
} }
}); });
const gce = createFormSection({ const gce = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
email: "Service Account Email Address", email: 'Service Account Email Address',
project: "Project", project: 'Project',
sshKeyData: "RSA Private Key", sshKeyData: 'RSA Private Key',
} }
}); });
const vmware = createFormSection({ const vmware = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
host: "VCenter Host", host: 'VCenter Host',
username: "Username", username: 'Username',
password: "Password", password: 'Password',
} }
}); });
const azureClassic = createFormSection({ const azureClassic = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
subscription: "Subscription ID", subscription: 'Subscription ID',
sshKeyData: "Management Certificate", sshKeyData: 'Management Certificate',
} }
}); });
const azure = createFormSection({ const azure = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
subscription: "Subscription ID", subscription: 'Subscription ID',
username: "Username", username: 'Username',
password: "Password", password: 'Password',
client: "Client ID", client: 'Client ID',
secret: "Client Secret", secret: 'Client Secret',
tenant: "Tenant ID", tenant: 'Tenant ID',
} }
}); });
const openStack = createFormSection({ const openStack = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
username: "Username", username: 'Username',
password: "Password (API Key)", password: 'Password (API Key)',
host: "Host (Authentication URL)", host: 'Host (Authentication URL)',
project: "Project (Tenant Name)", project: 'Project (Tenant Name)',
domain: "Domain Name", domain: 'Domain Name',
} }
}); });
const rackspace = createFormSection({ const rackspace = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
username: "Username", username: 'Username',
password: "Password", password: 'Password',
} }
}); });
const cloudForms = createFormSection({ const cloudForms = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
host: "Cloudforms URL", host: 'Cloudforms URL',
username: "Username", username: 'Username',
password: "Password", password: 'Password',
} }
}); });
const network = createFormSection({ const network = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
sshKeyData: "SSH Private Key", sshKeyData: 'SSH Private Key',
sshKeyUnlock: "Private Key Passphrase", sshKeyUnlock: 'Private Key Passphrase',
username: "Username", username: 'Username',
password: "Password", password: 'Password',
authorizePassword: "Authorize Password", authorizePassword: 'Authorize Password',
} }
}); });
@@ -156,26 +143,23 @@ network.elements.authorize = {
selector: '//input[../p/text() = "Authorize"]' selector: '//input[../p/text() = "Authorize"]'
}; };
const sat6 = createFormSection({ const sat6 = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
host: "Satellite 6 URL", host: 'Satellite 6 URL',
username: "Username", username: 'Username',
password: "Password", password: 'Password',
} }
}); });
const insights = createFormSection({ const insights = createFormSection({
selector: '.at-InputGroup-inset', selector: '.at-InputGroup-inset',
labels: { labels: {
username: "Username", username: 'Username',
password: "Password", password: 'Password',
}, },
}); });
const details = _.merge({}, common, { const details = _.merge({}, common, {
elements: { elements: {
cancel: '.btn[type="cancel"]', cancel: '.btn[type="cancel"]',
@@ -199,17 +183,17 @@ const details = _.merge({}, common, {
vmware vmware
}, },
commands: [{ commands: [{
custom({ name, inputs }) { custom ({ name, inputs }) {
let labels = {}; const labels = {};
inputs.fields.map(f => labels[f.id] = f.label); inputs.fields.forEach(f => { labels[f.id] = f.label; });
let selector = '.at-InputGroup-inset'; const selector = '.at-InputGroup-inset';
let generated = createFormSection({ selector, labels }); const generated = createFormSection({ selector, labels });
let params = _.merge({ name }, generated); const params = _.merge({ name }, generated);
return this.section.dynamicSection.create(params); return this.section.dynamicSection.create(params);
}, },
clear() { clear () {
this.clearValue('@name'); this.clearValue('@name');
this.clearValue('@organization'); this.clearValue('@organization');
this.clearValue('@description'); this.clearValue('@description');
@@ -217,7 +201,7 @@ const details = _.merge({}, common, {
this.waitForElementNotVisible('.at-InputGroup-inset'); this.waitForElementNotVisible('.at-InputGroup-inset');
return this; return this;
}, },
clearAndSelectType(type) { clearAndSelectType (type) {
this.clear(); this.clear();
this.setValue('@type', type); this.setValue('@type', type);
this.waitForElementVisible('.at-InputGroup-inset'); this.waitForElementVisible('.at-InputGroup-inset');
@@ -226,10 +210,9 @@ const details = _.merge({}, common, {
}] }]
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/credentials` return `${this.api.globals.launch_url}/#/credentials`;
}, },
sections: { sections: {
header, header,

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const standardInvDetails = createFormSection({ const standardInvDetails = createFormSection({
selector: 'form', selector: 'form',
@@ -36,7 +36,7 @@ const smartInvDetails = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/inventories`; return `${this.api.globals.launch_url}/#/inventories`;
}, },
sections: { sections: {

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -21,7 +21,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/inventory_scripts`; return `${this.api.globals.launch_url}/#/inventory_scripts`;
}, },
sections: { sections: {

View File

@@ -1,6 +1,6 @@
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/login` return `${this.api.globals.launch_url}/#/login`;
}, },
elements: { elements: {
username: '#login-username', username: '#login-username',

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -26,7 +26,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/notification_templates`; return `${this.api.globals.launch_url}/#/notification_templates`;
}, },
sections: { sections: {

View File

@@ -1,11 +1,11 @@
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -19,7 +19,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/organizations`; return `${this.api.globals.launch_url}/#/organizations`;
}, },
sections: { sections: {

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -22,7 +22,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/projects`; return `${this.api.globals.launch_url}/#/projects`;
}, },
sections: { sections: {

View File

@@ -12,5 +12,4 @@ const actions = {
} }
}; };
module.exports = actions; module.exports = actions;

View File

@@ -1,10 +1,8 @@
import { merge } from 'lodash'; import { merge } from 'lodash';
const translated = "translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')"; const translated = "translate(text(), 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', 'abcdefghijklmnopqrstuvwxyz')";
const normalized = `normalize-space(${translated})`; const normalized = `normalize-space(${translated})`;
const inputContainerElements = { const inputContainerElements = {
lookup: 'button > i[class="fa fa-search"]', lookup: 'button > i[class="fa fa-search"]',
error: '.at-InputMessage--rejected', error: '.at-InputMessage--rejected',
@@ -39,7 +37,6 @@ const inputContainerElements = {
} }
}; };
const legacyContainerElements = merge({}, inputContainerElements, { const legacyContainerElements = merge({}, inputContainerElements, {
prompt: { prompt: {
locateStrategy: 'xpath', locateStrategy: 'xpath',
@@ -49,22 +46,21 @@ const legacyContainerElements = merge({}, inputContainerElements, {
popover: ':root div[id^="popover"]', popover: ':root div[id^="popover"]',
}); });
const generateInputSelectors = (label, containerElements) => {
const generateInputSelectors = function(label, containerElements) {
// descend until span with matching text attribute is encountered // descend until span with matching text attribute is encountered
let span = `.//span[text()="${label}"]`; const span = `.//span[text()="${label}"]`;
// recurse upward until div with form-group in class attribute is encountered // recurse upward until div with form-group in class attribute is encountered
let container = `${span}/ancestor::div[contains(@class, 'form-group')]`; const container = `${span}/ancestor::div[contains(@class, 'form-group')]`;
// descend until element with form-control in class attribute is encountered // descend until element with form-control in class attribute is encountered
let input = `${container}//*[contains(@class, 'form-control')]`; const input = `${container}//*[contains(@class, 'form-control')]`;
let inputContainer = { const inputContainer = {
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: container, selector: container,
elements: containerElements elements: containerElements
}; };
let inputElement = { const inputElement = {
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: input selector: input
}; };
@@ -72,15 +68,14 @@ const generateInputSelectors = function(label, containerElements) {
return { inputElement, inputContainer }; return { inputElement, inputContainer };
}; };
function checkAllFieldsDisabled () {
const client = this.client.api;
const checkAllFieldsDisabled = function() { const selectors = this.props.formElementSelectors ? this.props.formElementSelectors : [
let client = this.client.api;
let selectors = this.props.formElementSelectors ? this.props.formElementSelectors : [
'.at-Input' '.at-Input'
]; ];
selectors.forEach(function(selector) { selectors.forEach(selector => {
client.elements('css selector', selector, inputs => { client.elements('css selector', selector, inputs => {
inputs.value.map(o => o.ELEMENT).forEach(id => { inputs.value.map(o => o.ELEMENT).forEach(id => {
client.elementIdAttribute(id, 'disabled', ({ value }) => { client.elementIdAttribute(id, 'disabled', ({ value }) => {
@@ -89,37 +84,37 @@ const checkAllFieldsDisabled = function() {
}); });
}); });
}); });
}; }
const generatorOptions = { const generatorOptions = {
default: inputContainerElements, default: inputContainerElements,
legacy: legacyContainerElements legacy: legacyContainerElements
}; };
const createFormSection = ({ selector, labels, strategy, props }) => {
const options = generatorOptions[strategy || 'default'];
const createFormSection = function({ selector, labels, strategy, props }) { const formSection = {
let options = generatorOptions[strategy || 'default']; props,
let formSection = {
selector, selector,
sections: {}, sections: {},
elements: {}, elements: {},
commands: [{ commands: [{ checkAllFieldsDisabled }]
checkAllFieldsDisabled: checkAllFieldsDisabled
}],
props: props
}; };
for (let key in labels) { if (!labels) {
let label = labels[key]; return formSection;
let { inputElement, inputContainer } = generateInputSelectors(label, options);
formSection.elements[key] = inputElement;
formSection.sections[key] = inputContainer;
} }
Object.keys(labels)
.forEach(key => {
const label = labels[key];
const { inputElement, inputContainer } = generateInputSelectors(label, options);
formSection.elements[key] = inputElement;
formSection.sections[key] = inputContainer;
});
return formSection; return formSection;
}; };

View File

@@ -1,5 +1,4 @@
import dynamicSection from './dynamicSection.js'; import dynamicSection from './dynamicSection';
const header = { const header = {
selector: 'thead', selector: 'thead',
@@ -7,7 +6,7 @@ const header = {
dynamicSection dynamicSection
}, },
commands: [{ commands: [{
findColumnByText(text) { findColumnByText (text) {
return this.section.dynamicSection.create({ return this.section.dynamicSection.create({
name: `column[${text}]`, name: `column[${text}]`,
locateStrategy: 'xpath', locateStrategy: 'xpath',
@@ -17,7 +16,7 @@ const header = {
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: './/*[contains(@class, "fa-sort")]' selector: './/*[contains(@class, "fa-sort")]'
}, },
sorted: { sorted: {
locateStrategy: 'xpath', locateStrategy: 'xpath',
selector: './/*[contains(@class, "fa-sort-")]' selector: './/*[contains(@class, "fa-sort-")]'
}, },
@@ -27,37 +26,32 @@ const header = {
}] }]
}; };
module.exports = ({ elements, sections, commands }) => ({
const createTableSection = function({ elements, sections, commands }) { selector: 'table',
return { sections: {
selector: 'table', header,
sections: { dynamicSection
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`
});
}, },
commands: [{ waitForRowCount (count) {
findRowByText(text) { const countReached = `tbody tr:nth-of-type(${count})`;
return this.section.dynamicSection.create({ this.waitForElementPresent(countReached);
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})`; const countExceeded = `tbody tr:nth-of-type(${count + 1})`;
this.waitForElementNotPresent(countExceeded); this.waitForElementNotPresent(countExceeded);
return this; return this;
} }
}] }]
}; });
};
module.exports = createTableSection;

View File

@@ -1,10 +1,10 @@
const dynamicSection = { const dynamicSection = {
selector: '.', selector: '.',
commands: [{ commands: [{
create({ name, locateStrategy, selector, elements, sections, commands }) { create ({ name, locateStrategy, selector, elements, sections, commands }) {
let Section = this.constructor; const Section = this.constructor;
let options = Object.assign(Object.create(this), { const options = Object.assign(Object.create(this), {
name, name,
locateStrategy, locateStrategy,
elements, elements,

View File

@@ -8,5 +8,4 @@ const header = {
} }
}; };
module.exports = header; module.exports = header;

View File

@@ -1,7 +1,6 @@
import createTableSection from './createTableSection.js'; import createTableSection from './createTableSection';
import pagination from './pagination.js'; import pagination from './pagination';
import search from './search.js'; import search from './search';
const lookupModal = { const lookupModal = {
selector: '#form-modal', selector: '#form-modal',

View File

@@ -21,5 +21,4 @@ const navigation = {
} }
}; };
module.exports = navigation; module.exports = navigation;

View File

@@ -1,8 +1,7 @@
import actions from './actions.js'; import actions from './actions';
import createTableSection from './createTableSection.js'; import createTableSection from './createTableSection';
import pagination from './pagination.js'; import pagination from './pagination';
import search from './search.js'; import search from './search';
const permissions = { const permissions = {
selector: 'div[ui-view="related"]', selector: 'div[ui-view="related"]',
@@ -26,5 +25,4 @@ const permissions = {
} }
}; };
module.exports = permissions; module.exports = permissions;

View File

@@ -8,5 +8,4 @@ const search = {
} }
}; };
module.exports = search; module.exports = search;

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -20,7 +20,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/teams`; return `${this.api.globals.launch_url}/#/teams`;
}, },
sections: { sections: {

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -24,7 +24,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/templates`; return `${this.api.globals.launch_url}/#/templates`;
}, },
sections: { sections: {

View File

@@ -1,13 +1,13 @@
import actions from './sections/actions.js'; import actions from './sections/actions';
import breadcrumb from './sections/breadcrumb.js'; import breadcrumb from './sections/breadcrumb';
import createFormSection from './sections/createFormSection.js'; import createFormSection from './sections/createFormSection';
import createTableSection from './sections/createTableSection.js'; import createTableSection from './sections/createTableSection';
import header from './sections/header.js'; import header from './sections/header';
import lookupModal from './sections/lookupModal.js'; import lookupModal from './sections/lookupModal';
import navigation from './sections/navigation.js'; import navigation from './sections/navigation';
import pagination from './sections/pagination.js'; import pagination from './sections/pagination';
import permissions from './sections/permissions.js'; import permissions from './sections/permissions';
import search from './sections/search.js'; import search from './sections/search';
const details = createFormSection({ const details = createFormSection({
selector: 'form', selector: 'form',
@@ -20,7 +20,7 @@ const details = createFormSection({
}); });
module.exports = { module.exports = {
url() { url () {
return `${this.api.globals.launch_url}/#/users`; return `${this.api.globals.launch_url}/#/users`;
}, },
sections: { sections: {

View File

@@ -10,7 +10,6 @@ const AWX_E2E_TIMEOUT_LONG = process.env.AWX_E2E_TIMEOUT_LONG || 10000;
const AWX_E2E_TIMEOUT_ASYNC = process.env.AWX_E2E_TIMEOUT_ASYNC || 30000; const AWX_E2E_TIMEOUT_ASYNC = process.env.AWX_E2E_TIMEOUT_ASYNC || 30000;
const AWX_E2E_WORKERS = process.env.AWX_E2E_WORKERS || 0; const AWX_E2E_WORKERS = process.env.AWX_E2E_WORKERS || 0;
module.exports = { module.exports = {
awxURL: AWX_E2E_URL, awxURL: AWX_E2E_URL,
awxUsername: AWX_E2E_USERNAME, awxUsername: AWX_E2E_USERNAME,

View File

@@ -1,4 +1,4 @@
import { all } from '../api.js'; import { all } from '../api';
import { import {
getAdminAWSCredential, getAdminAWSCredential,
@@ -7,80 +7,77 @@ import {
getInventory, getInventory,
getInventoryScript, getInventoryScript,
getNotificationTemplate, getNotificationTemplate,
getOrCreate,
getOrganization, getOrganization,
getSmartInventory, getSmartInventory,
getTeam, getTeam,
getUpdatedProject, getUpdatedProject,
getUser getUser
} from '../fixtures.js'; } from '../fixtures';
const data = {};
let credentials;
let inventoryScripts;
let notificationTemplates;
let organizations;
let projects;
// let templates;
let users;
let inventories;
let teams;
let data = {}; function navigateAndWaitForSpinner (client, url) {
let credentials,
inventoryScripts,
templates,
notificationTemplates,
organizations,
projects,
users,
inventories,
teams;
function navigateAndWaitForSpinner(client, url) {
client client
.url(url) .url(url)
.waitForElementVisible('div.spinny') .waitForElementVisible('div.spinny')
.waitForElementNotVisible('div.spinny'); .waitForElementNotVisible('div.spinny');
} }
module.exports = { module.exports = {
before: function (client, done) { before: (client, done) => {
all([ const promises = [
getAuditor().then(obj => data.auditor = obj), getAuditor().then(obj => { data.auditor = obj; }),
getOrganization().then(obj => data.organization = obj), getOrganization().then(obj => { data.organization = obj; }),
getInventory().then(obj => data.inventory = obj), getInventory().then(obj => { data.inventory = obj; }),
getInventoryScript().then(obj => data.inventoryScript = obj), getInventoryScript().then(obj => { data.inventoryScript = obj; }),
getAdminAWSCredential().then(obj => data.adminAWSCredential = obj), getAdminAWSCredential().then(obj => { data.adminAWSCredential = obj; }),
getAdminMachineCredential().then(obj => data.adminMachineCredential = obj), getAdminMachineCredential().then(obj => { data.adminMachineCredential = obj; }),
getSmartInventory().then(obj => data.smartInventory = obj), getSmartInventory().then(obj => { data.smartInventory = obj; }),
getTeam().then(obj => data.team = obj), getTeam().then(obj => { data.team = obj; }),
getUser().then(obj => data.user = obj), getUser().then(obj => { data.user = obj; }),
getNotificationTemplate().then(obj => data.notificationTemplate = obj), getNotificationTemplate().then(obj => { data.notificationTemplate = obj; }),
getUpdatedProject().then(obj => data.project = obj) getUpdatedProject().then(obj => { data.project = obj; })
]) ];
.then(() => {
client.useCss();
credentials = client.page.credentials(); all(promises)
inventoryScripts = client.page.inventoryScripts(); .then(() => {
templates = client.page.templates(); client.useCss();
notificationTemplates = client.page.notificationTemplates();
organizations = client.page.organizations();
projects = client.page.projects();
users = client.page.users();
inventories = client.page.inventories();
teams = client.page.teams();
client.login(data.auditor.username, data.auditor.password); credentials = client.page.credentials();
client.waitForAngular(); inventoryScripts = client.page.inventoryScripts();
// templates = client.page.templates();
notificationTemplates = client.page.notificationTemplates();
organizations = client.page.organizations();
projects = client.page.projects();
users = client.page.users();
inventories = client.page.inventories();
teams = client.page.teams();
done(); client.login(data.auditor.username, data.auditor.password);
}); client.waitForAngular();
done();
});
}, },
'verify an auditor\'s credentials inputs are read-only': function (client) { 'verify an auditor\'s credentials inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${credentials.url()}/${data.adminAWSCredential.id}/`); navigateAndWaitForSpinner(client, `${credentials.url()}/${data.adminAWSCredential.id}/`);
credentials.section.edit credentials.section.edit
.expect.element('@title').text.contain(data.adminAWSCredential.name); .expect.element('@title').text.contain(data.adminAWSCredential.name);
credentials.section.edit.section.details.checkAllFieldsDisabled(); credentials.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify an auditor\'s inventory scripts inputs are read-only': function (client) { 'verify an auditor\'s inventory scripts inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${inventoryScripts.url()}/${data.inventoryScript.id}/`); navigateAndWaitForSpinner(client, `${inventoryScripts.url()}/${data.inventoryScript.id}/`);
inventoryScripts.section.edit inventoryScripts.section.edit
@@ -88,13 +85,16 @@ module.exports = {
inventoryScripts.section.edit.section.details.checkAllFieldsDisabled(); inventoryScripts.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on inventory scripts form': function () { 'verify save button hidden from auditor on inventory scripts form': () => {
inventoryScripts.expect.element('@save').to.not.be.visible; inventoryScripts.expect.element('@save').to.not.be.visible;
}, },
// TODO: re-enable these tests when JT edit has been re-factored to reliably show/remove the loading spinner // TODO: re-enable these tests when JT edit has been re-factored to reliably show/remove the
// only one time. Without this, we can't tell when all the requisite data is available. // loading spinner only one time. Without this, we can't tell when all the requisite data is
// available.
//
// 'verify an auditor\'s job template inputs are read-only': function (client) { // 'verify an auditor\'s job template inputs are read-only': function (client) {
// navigateAndWaitForSpinner(client, `${templates.url()}/job_template/${data.jobTemplate.id}/`); // const url = `${templates.url()}/job_template/${data.jobTemplate.id}/`;
// navigateAndWaitForSpinner(client, url);
// //
// templates.section.editJobTemplate // templates.section.editJobTemplate
// .expect.element('@title').text.contain(data.jobTemplate.name); // .expect.element('@title').text.contain(data.jobTemplate.name);
@@ -104,7 +104,7 @@ module.exports = {
// 'verify save button hidden from auditor on job templates form': function () { // 'verify save button hidden from auditor on job templates form': function () {
// templates.expect.element('@save').to.not.be.visible; // templates.expect.element('@save').to.not.be.visible;
// }, // },
'verify an auditor\'s notification templates inputs are read-only': function (client) { 'verify an auditor\'s notification templates inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${notificationTemplates.url()}/${data.notificationTemplate.id}/`); navigateAndWaitForSpinner(client, `${notificationTemplates.url()}/${data.notificationTemplate.id}/`);
notificationTemplates.section.edit notificationTemplates.section.edit
@@ -112,10 +112,10 @@ module.exports = {
notificationTemplates.section.edit.section.details.checkAllFieldsDisabled(); notificationTemplates.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on notification templates page': function () { 'verify save button hidden from auditor on notification templates page': () => {
notificationTemplates.expect.element('@save').to.not.be.visible; notificationTemplates.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s organizations inputs are read-only': function (client) { 'verify an auditor\'s organizations inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${organizations.url()}/${data.organization.id}/`); navigateAndWaitForSpinner(client, `${organizations.url()}/${data.organization.id}/`);
organizations.section.edit organizations.section.edit
@@ -123,10 +123,10 @@ module.exports = {
organizations.section.edit.section.details.checkAllFieldsDisabled(); organizations.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on organizations form': function () { 'verify save button hidden from auditor on organizations form': () => {
organizations.expect.element('@save').to.not.be.visible; organizations.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s smart inventory inputs are read-only': function (client) { 'verify an auditor\'s smart inventory inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${inventories.url()}/smart/${data.smartInventory.id}/`); navigateAndWaitForSpinner(client, `${inventories.url()}/smart/${data.smartInventory.id}/`);
inventories.section.editSmartInventory inventories.section.editSmartInventory
@@ -134,10 +134,10 @@ module.exports = {
inventories.section.editSmartInventory.section.smartInvDetails.checkAllFieldsDisabled(); inventories.section.editSmartInventory.section.smartInvDetails.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on smart inventories form': function () { 'verify save button hidden from auditor on smart inventories form': () => {
inventories.expect.element('@save').to.not.be.visible; inventories.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s project inputs are read-only': function (client) { 'verify an auditor\'s project inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${projects.url()}/${data.project.id}/`); navigateAndWaitForSpinner(client, `${projects.url()}/${data.project.id}/`);
projects.section.edit projects.section.edit
@@ -145,21 +145,22 @@ module.exports = {
projects.section.edit.section.details.checkAllFieldsDisabled(); projects.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on projects form': function () { 'verify save button hidden from auditor on projects form': () => {
projects.expect.element('@save').to.not.be.visible; projects.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s standard inventory inputs are read-only': function (client) { 'verify an auditor\'s standard inventory inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${inventories.url()}/inventory/${data.inventory.id}/`); navigateAndWaitForSpinner(client, `${inventories.url()}/inventory/${data.inventory.id}/`);
inventories.section.editStandardInventory inventories.section.editStandardInventory
.expect.element('@title').text.contain(data.inventory.name); .expect.element('@title').text.contain(data.inventory.name);
inventories.section.editStandardInventory.section.standardInvDetails.checkAllFieldsDisabled(); inventories.section.editStandardInventory.section.standardInvDetails
.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on standard inventory form': function () { 'verify save button hidden from auditor on standard inventory form': () => {
inventories.expect.element('@save').to.not.be.visible; inventories.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s teams inputs are read-only': function (client) { 'verify an auditor\'s teams inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${teams.url()}/${data.team.id}/`); navigateAndWaitForSpinner(client, `${teams.url()}/${data.team.id}/`);
teams.section.edit teams.section.edit
@@ -167,10 +168,10 @@ module.exports = {
teams.section.edit.section.details.checkAllFieldsDisabled(); teams.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on teams form': function () { 'verify save button hidden from auditor on teams form': () => {
teams.expect.element('@save').to.not.be.visible; teams.expect.element('@save').to.not.be.visible;
}, },
'verify an auditor\'s user inputs are read-only': function (client) { 'verify an auditor\'s user inputs are read-only': client => {
navigateAndWaitForSpinner(client, `${users.url()}/${data.user.id}/`); navigateAndWaitForSpinner(client, `${users.url()}/${data.user.id}/`);
users.section.edit users.section.edit
@@ -178,7 +179,7 @@ module.exports = {
users.section.edit.section.details.checkAllFieldsDisabled(); users.section.edit.section.details.checkAllFieldsDisabled();
}, },
'verify save button hidden from auditor on users form': function (client) { 'verify save button hidden from auditor on users form': client => {
users.expect.element('@save').to.not.be.visible; users.expect.element('@save').to.not.be.visible;
client.end(); client.end();

View File

@@ -1,5 +1,5 @@
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentialTypes = client.page.credentialTypes(); const credentialTypes = client.page.credentialTypes();
client.login(); client.login();
@@ -13,9 +13,9 @@ module.exports = {
credentialTypes.section.add credentialTypes.section.add
.waitForElementVisible('@title', done); .waitForElementVisible('@title', done);
}, },
'expected fields are present and enabled': function(client) { 'expected fields are present and enabled': client => {
const credentialTypes = client.page.credentialTypes(); const credentialTypes = client.page.credentialTypes();
const details = credentialTypes.section.add.section.details; const { details } = credentialTypes.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,18 +12,17 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -44,9 +42,9 @@ module.exports = {
.setValue('@organization', store.organization.name) .setValue('@organization', store.organization.name)
.setValue('@type', 'Amazon Web Services', done); .setValue('@type', 'Amazon Web Services', done);
}, },
'expected fields are visible and enabled': function(client) { 'expected fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -64,20 +62,23 @@ module.exports = {
details.section.aws.expect.element('@secretKey').enabled; details.section.aws.expect.element('@secretKey').enabled;
details.section.aws.expect.element('@securityToken').enabled; details.section.aws.expect.element('@securityToken').enabled;
}, },
'required fields display \'*\'': function(client) { 'required fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const required = [ const required = [
details.section.name, details.section.name,
details.section.type, details.section.type,
details.section.aws.section.accessKey, details.section.aws.section.accessKey,
details.section.aws.section.secretKey details.section.aws.section.secretKey
] ];
required.map(s => s.expect.element('@label').text.to.contain('*'));
required.forEach(s => {
s.expect.element('@label').text.to.contain('*');
});
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details details
.clearAndSelectType('Amazon Web Services') .clearAndSelectType('Amazon Web Services')
@@ -88,10 +89,10 @@ module.exports = {
details.section.aws.setValue('@secretKey', 'AAAAAAAAAAAAA'); details.section.aws.setValue('@secretKey', 'AAAAAAAAAAAAA');
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'create aws credential': function(client) { 'create aws credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Amazon Web Services') .clearAndSelectType('Amazon Web Services')
@@ -110,16 +111,16 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const search = credentials.section.list.section.search; const { search } = credentials.section.list.section;
const table = credentials.section.list.section.table; const { table } = credentials.section.list.section;
search search
.waitForElementVisible('@input') .waitForElementVisible('@input')

View File

@@ -1,104 +1,100 @@
import uuid from 'uuid'; import uuid from 'uuid';
const store = {
let store = {
credentialType: { credentialType: {
name: `credentialType-${uuid().substr(0,8)}`, name: `credentialType-${uuid().substr(0, 8)}`,
description: "custom cloud credential", description: 'custom cloud credential',
kind: "cloud", kind: 'cloud',
inputs: { inputs: {
fields: [ fields: [
{ {
id: "project", id: 'project',
label: "Project", label: 'Project',
type: "string", type: 'string',
help_text: "Name of your project" help_text: 'Name of your project'
}, },
{ {
id: "token", id: 'token',
label: "Token", label: 'Token',
secret: true, secret: true,
type: "string", type: 'string',
help_text: "help" help_text: 'help'
}, },
{ {
id: "secret_key_data", id: 'secret_key_data',
label: "Secret Key", label: 'Secret Key',
type: "string", type: 'string',
secret: true, secret: true,
multiline: true, multiline: true,
help_text: "help", help_text: 'help',
}, },
{ {
id: "public_key_data", id: 'public_key_data',
label: "Public Key", label: 'Public Key',
type: "string", type: 'string',
secret: true, secret: true,
multiline: true, multiline: true,
help_text: "help", help_text: 'help',
}, },
{ {
id: "secret_key_unlock", id: 'secret_key_unlock',
label: "Private Key Passphrase", label: 'Private Key Passphrase',
type: "string", type: 'string',
secret: true, secret: true,
//help_text: "help" // help_text: 'help'
}, },
{ {
id: "color", id: 'color',
label: "Favorite Color", label: 'Favorite Color',
choices: [ choices: [
"", '',
"red", 'red',
"orange", 'orange',
"yellow", 'yellow',
"green", 'green',
"blue", 'blue',
"indigo", 'indigo',
"violet" 'violet'
], ],
help_text: "help", help_text: 'help',
}, },
], ],
required: ['project', 'token'] required: ['project', 'token']
}, },
injectors: { injectors: {
env: { env: {
CUSTOM_CREDENTIAL_TOKEN: "{{ token }}" CUSTOM_CREDENTIAL_TOKEN: '{{ token }}'
} }
} }
} }
}; };
const { inputs } = store.credentialType;
const inputs = store.credentialType.inputs; const { fields } = inputs;
const fields = store.credentialType.inputs.fields;
const help = fields.filter(f => f.help_text); const help = fields.filter(f => f.help_text);
const required = fields.filter(f => inputs.required.indexOf(f.id) > -1); const required = fields.filter(f => inputs.required.indexOf(f.id) > -1);
const strings = fields.filter(f => f.type === undefined || f.type === 'string'); const strings = fields.filter(f => f.type === undefined || f.type === 'string');
const getObjects = client => {
const credentials = client.page.credentials();
const { details } = credentials.section.add.section;
const type = details.custom(store.credentialType);
const getObjects = function(client) {
let credentials = client.page.credentials();
let details = credentials.section.add.section.details;
let type = details.custom(store.credentialType);
return { credentials, details, type }; return { credentials, details, type };
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store.credentialType, 'CredentialTypeModel'], (data, model) => { client.inject(
return new model().http.post(data); [store.credentialType, 'CredentialTypeModel'],
}, (data, Model) => new Model().http.post(data),
({ data }) => { ({ data }) => { store.credentialType.response = data; }
store.credentialType.response = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -117,15 +113,18 @@ module.exports = {
.setValue('@name', `cred-${uuid()}`) .setValue('@name', `cred-${uuid()}`)
.setValue('@type', store.credentialType.name, done); .setValue('@type', store.credentialType.name, done);
}, },
'all fields are visible': function(client) { 'all fields are visible': client => {
let { type } = getObjects(client); const { type } = getObjects(client);
fields.map(f => type.expect.element(`@${f.id}`).visible); fields.forEach(f => {
type.expect.element(`@${f.id}`).visible;
});
}, },
'helplinks open popovers showing expected content': function(client) { 'helplinks open popovers showing expected content': client => {
let { type } = getObjects(client); const { type } = getObjects(client);
help.forEach(f => {
const group = type.section[f.id];
help.map(f => {
let group = type.section[f.id];
group.expect.element('@popover').not.visible; group.expect.element('@popover').not.visible;
group.click('@help'); group.click('@help');
group.expect.element('@popover').visible; group.expect.element('@popover').visible;
@@ -133,18 +132,18 @@ module.exports = {
group.click('@help'); group.click('@help');
}); });
help.map(f => { help.forEach(f => {
let group = type.section[f.id]; const group = type.section[f.id];
group.expect.element('@popover').not.visible; group.expect.element('@popover').not.visible;
}); });
}, },
'secret field buttons hide and unhide input': function(client) { 'secret field buttons hide and unhide input': client => {
let { type } = getObjects(client); const { type } = getObjects(client);
let secrets = strings.filter(f => f.secret && !f.multiline); const secrets = strings.filter(f => f.secret && !f.multiline);
secrets.map(f => { secrets.forEach(f => {
let group = type.section[f.id]; const group = type.section[f.id];
let input = `@${f.id}`; const input = `@${f.id}`;
group.expect.element('@show').visible; group.expect.element('@show').visible;
group.expect.element('@hide').not.present; group.expect.element('@hide').not.present;
@@ -161,13 +160,13 @@ module.exports = {
group.expect.element('@show').visible; group.expect.element('@show').visible;
group.expect.element('@hide').not.present; group.expect.element('@hide').not.present;
type.expect.element(input).text.equal(''); type.expect.element(input).text.equal('');
}) });
}, },
'required fields show * symbol': function(client) { 'required fields show * symbol': client => {
let { type } = getObjects(client); const { type } = getObjects(client);
required.map(f => { required.forEach(f => {
let group = type.section[f.id]; const group = type.section[f.id];
group.expect.element('@label').text.to.contain('*'); group.expect.element('@label').text.to.contain('*');
}); });

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,19 +12,18 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -45,9 +43,9 @@ module.exports = {
.setValue('@organization', store.organization.name) .setValue('@organization', store.organization.name)
.setValue('@type', 'Google Compute Engine', done); .setValue('@type', 'Google Compute Engine', done);
}, },
'expected fields are visible and enabled': function(client) { 'expected fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -67,20 +65,23 @@ module.exports = {
details.section.organization.expect.element('@lookup').visible; details.section.organization.expect.element('@lookup').visible;
}, },
'required fields display \'*\'': function(client) { 'required fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const required = [ const required = [
details.section.name, details.section.name,
details.section.type, details.section.type,
details.section.gce.section.email, details.section.gce.section.email,
details.section.gce.section.sshKeyData details.section.gce.section.sshKeyData
] ];
required.map(s => s.expect.element('@label').text.to.contain('*'));
required.forEach(s => {
s.expect.element('@label').text.to.contain('*');
});
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details details
.clearAndSelectType('Google Compute Engine') .clearAndSelectType('Google Compute Engine')
@@ -98,10 +99,10 @@ module.exports = {
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'error displayed for invalid ssh key data': function(client) { 'error displayed for invalid ssh key data': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyData = details.section.gce.section.sshKeyData; const { sshKeyData } = details.section.gce.section;
details details
.clearAndSelectType('Google Compute Engine') .clearAndSelectType('Google Compute Engine')
@@ -124,10 +125,10 @@ module.exports = {
details.section.gce.setValue('@sshKeyData', 'AAAA'); details.section.gce.setValue('@sshKeyData', 'AAAA');
sshKeyData.expect.element('@error').not.present; sshKeyData.expect.element('@error').not.present;
}, },
'create gce credential': function(client) { 'create gce credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Google Compute Engine') .clearAndSelectType('Google Compute Engine')
@@ -150,12 +151,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,19 +12,18 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -45,9 +43,9 @@ module.exports = {
.setValue('@organization', store.organization.name) .setValue('@organization', store.organization.name)
.setValue('@type', 'Insights', done); .setValue('@type', 'Insights', done);
}, },
'expected fields are visible and enabled': function(client) { 'expected fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -63,20 +61,23 @@ module.exports = {
details.section.insights.expect.element('@username').enabled; details.section.insights.expect.element('@username').enabled;
details.section.insights.expect.element('@password').enabled; details.section.insights.expect.element('@password').enabled;
}, },
'required fields display \'*\'': function(client) { 'required fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const required = [ const required = [
details.section.name, details.section.name,
details.section.type, details.section.type,
details.section.insights.section.username, details.section.insights.section.username,
details.section.insights.section.password details.section.insights.section.password
] ];
required.map(s => s.expect.element('@label').text.to.contain('*'));
required.forEach(s => {
s.expect.element('@label').text.to.contain('*');
});
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details details
.clearAndSelectType('Insights') .clearAndSelectType('Insights')
@@ -90,10 +91,10 @@ module.exports = {
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'create insights credential': function(client) { 'create insights credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Insights') .clearAndSelectType('Insights')
@@ -112,12 +113,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,19 +12,18 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -41,9 +39,9 @@ module.exports = {
details.waitForElementVisible('@save', done); details.waitForElementVisible('@save', done);
}, },
'common fields are visible and enabled': function(client) { 'common fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -55,16 +53,16 @@ module.exports = {
details.expect.element('@organization').enabled; details.expect.element('@organization').enabled;
details.expect.element('@type').enabled; details.expect.element('@type').enabled;
}, },
'required common fields display \'*\'': function(client) { 'required common fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.section.name.expect.element('@label').text.to.contain('*'); details.section.name.expect.element('@label').text.to.contain('*');
details.section.type.expect.element('@label').text.to.contain('*'); details.section.type.expect.element('@label').text.to.contain('*');
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@save').not.enabled; details.expect.element('@save').not.enabled;
@@ -75,10 +73,10 @@ module.exports = {
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'machine credential fields are visible after choosing type': function(client) { 'machine credential fields are visible after choosing type': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const machine = details.section.machine; const { machine } = details.section;
machine.expect.element('@username').visible; machine.expect.element('@username').visible;
machine.expect.element('@password').visible; machine.expect.element('@password').visible;
@@ -87,10 +85,10 @@ module.exports = {
machine.expect.element('@sshKeyData').visible; machine.expect.element('@sshKeyData').visible;
machine.expect.element('@sshKeyUnlock').visible; machine.expect.element('@sshKeyUnlock').visible;
}, },
'error displayed for invalid ssh key data': function(client) { 'error displayed for invalid ssh key data': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyData = details.section.machine.section.sshKeyData; const { sshKeyData } = details.section.machine.section;
details details
.clearAndSelectType('Machine') .clearAndSelectType('Machine')
@@ -106,10 +104,10 @@ module.exports = {
details.section.machine.clearValue('@sshKeyData'); details.section.machine.clearValue('@sshKeyData');
sshKeyData.expect.element('@error').not.present; sshKeyData.expect.element('@error').not.present;
}, },
'error displayed for unencrypted ssh key with passphrase': function(client) { 'error displayed for unencrypted ssh key with passphrase': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyUnlock = details.section.machine.section.sshKeyUnlock; const { sshKeyUnlock } = details.section.machine.section;
details details
.clearAndSelectType('Machine') .clearAndSelectType('Machine')
@@ -130,11 +128,11 @@ module.exports = {
details.section.machine.clearValue('@sshKeyUnlock'); details.section.machine.clearValue('@sshKeyUnlock');
sshKeyUnlock.expect.element('@error').not.present; sshKeyUnlock.expect.element('@error').not.present;
}, },
'create machine credential': function(client) { 'create machine credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Machine') .clearAndSelectType('Machine')
@@ -161,12 +159,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,19 +12,18 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -41,9 +39,9 @@ module.exports = {
details.waitForElementVisible('@save', done); details.waitForElementVisible('@save', done);
}, },
'common fields are visible and enabled': function(client) { 'common fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -55,16 +53,16 @@ module.exports = {
details.expect.element('@organization').enabled; details.expect.element('@organization').enabled;
details.expect.element('@type').enabled; details.expect.element('@type').enabled;
}, },
'required common fields display \'*\'': function(client) { 'required common fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.section.name.expect.element('@label').text.to.contain('*'); details.section.name.expect.element('@label').text.to.contain('*');
details.section.type.expect.element('@label').text.to.contain('*'); details.section.type.expect.element('@label').text.to.contain('*');
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@save').not.enabled; details.expect.element('@save').not.enabled;
@@ -79,10 +77,10 @@ module.exports = {
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'network credential fields are visible after choosing type': function(client) { 'network credential fields are visible after choosing type': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const network = details.section.network; const { network } = details.section;
network.expect.element('@username').visible; network.expect.element('@username').visible;
network.expect.element('@password').visible; network.expect.element('@password').visible;
@@ -90,10 +88,10 @@ module.exports = {
network.expect.element('@sshKeyData').visible; network.expect.element('@sshKeyData').visible;
network.expect.element('@sshKeyUnlock').visible; network.expect.element('@sshKeyUnlock').visible;
}, },
'error displayed for invalid ssh key data': function(client) { 'error displayed for invalid ssh key data': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyData = details.section.network.section.sshKeyData; const { sshKeyData } = details.section.network.section;
details details
.clearAndSelectType('Network') .clearAndSelectType('Network')
@@ -111,10 +109,10 @@ module.exports = {
details.section.network.clearValue('@sshKeyData'); details.section.network.clearValue('@sshKeyData');
sshKeyData.expect.element('@error').not.present; sshKeyData.expect.element('@error').not.present;
}, },
'error displayed for unencrypted ssh key with passphrase': function(client) { 'error displayed for unencrypted ssh key with passphrase': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyUnlock = details.section.network.section.sshKeyUnlock; const { sshKeyUnlock } = details.section.network.section;
details details
.clearAndSelectType('Network') .clearAndSelectType('Network')
@@ -136,11 +134,11 @@ module.exports = {
details.section.network.clearValue('@sshKeyUnlock'); details.section.network.clearValue('@sshKeyUnlock');
sshKeyUnlock.expect.element('@error').not.present; sshKeyUnlock.expect.element('@error').not.present;
}, },
'error displayed for authorize password without authorize enabled': function(client) { 'error displayed for authorize password without authorize enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const authorizePassword = details.section.network.section.authorizePassword; const { authorizePassword } = details.section.network.section;
details details
.clearAndSelectType('Network') .clearAndSelectType('Network')
@@ -152,17 +150,17 @@ module.exports = {
details.click('@save'); details.click('@save');
let expected = 'cannot be set unless "Authorize" is set'; const expected = 'cannot be set unless "Authorize" is set';
authorizePassword.expect.element('@error').visible; authorizePassword.expect.element('@error').visible;
authorizePassword.expect.element('@error').text.to.equal(expected); authorizePassword.expect.element('@error').text.to.equal(expected);
details.section.network.clearValue('@authorizePassword'); details.section.network.clearValue('@authorizePassword');
authorizePassword.expect.element('@error').not.present; authorizePassword.expect.element('@error').not.present;
}, },
'create network credential': function(client) { 'create network credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Network') .clearAndSelectType('Network')
@@ -186,12 +184,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,9 +1,8 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
@@ -13,19 +12,18 @@ let store = {
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -41,9 +39,9 @@ module.exports = {
details.waitForElementVisible('@save', done); details.waitForElementVisible('@save', done);
}, },
'common fields are visible and enabled': function(client) { 'common fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -55,16 +53,16 @@ module.exports = {
details.expect.element('@organization').enabled; details.expect.element('@organization').enabled;
details.expect.element('@type').enabled; details.expect.element('@type').enabled;
}, },
'required common fields display \'*\'': function(client) { 'required common fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.section.name.expect.element('@label').text.to.contain('*'); details.section.name.expect.element('@label').text.to.contain('*');
details.section.type.expect.element('@label').text.to.contain('*'); details.section.type.expect.element('@label').text.to.contain('*');
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@save').not.enabled; details.expect.element('@save').not.enabled;
@@ -75,19 +73,19 @@ module.exports = {
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'scm credential fields are visible after choosing type': function(client) { 'scm credential fields are visible after choosing type': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.section.scm.expect.element('@username').visible; details.section.scm.expect.element('@username').visible;
details.section.scm.expect.element('@password').visible; details.section.scm.expect.element('@password').visible;
details.section.scm.expect.element('@sshKeyData').visible; details.section.scm.expect.element('@sshKeyData').visible;
details.section.scm.expect.element('@sshKeyUnlock').visible; details.section.scm.expect.element('@sshKeyUnlock').visible;
}, },
'error displayed for invalid ssh key data': function(client) { 'error displayed for invalid ssh key data': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyData = details.section.scm.section.sshKeyData; const { sshKeyData } = details.section.scm.section;
details details
.clearAndSelectType('Source Control') .clearAndSelectType('Source Control')
@@ -103,10 +101,10 @@ module.exports = {
details.section.scm.clearValue('@sshKeyData'); details.section.scm.clearValue('@sshKeyData');
sshKeyData.expect.element('@error').not.present; sshKeyData.expect.element('@error').not.present;
}, },
'error displayed for unencrypted ssh key with passphrase': function(client) { 'error displayed for unencrypted ssh key with passphrase': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const sshKeyUnlock = details.section.scm.section.sshKeyUnlock; const { sshKeyUnlock } = details.section.scm.section;
details details
.clearAndSelectType('Source Control') .clearAndSelectType('Source Control')
@@ -127,11 +125,11 @@ module.exports = {
details.section.scm.clearValue('@sshKeyUnlock'); details.section.scm.clearValue('@sshKeyUnlock');
sshKeyUnlock.expect.element('@error').not.present; sshKeyUnlock.expect.element('@error').not.present;
}, },
'create SCM credential': function(client) { 'create SCM credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Source Control') .clearAndSelectType('Source Control')
@@ -155,12 +153,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,31 +1,28 @@
import uuid from 'uuid'; import uuid from 'uuid';
const testID = uuid().substr(0, 8);
let testID = uuid().substr(0,8); const store = {
let store = {
organization: { organization: {
name: `org-${testID}` name: `org-${testID}`
}, },
credential: { credential: {
name: `cred-${testID}` name: `cred-${testID}`
}, }
}; };
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
client.inject([store, 'OrganizationModel'], (store, model) => { client.inject(
return new model().http.post(store.organization); [store, 'OrganizationModel'],
}, (_store_, Model) => new Model().http.post(_store_.organization),
({ data }) => { ({ data }) => { store.organization = data; }
store.organization = data; );
});
credentials.section.navigation credentials.section.navigation
.waitForElementVisible('@credentials') .waitForElementVisible('@credentials')
@@ -45,9 +42,9 @@ module.exports = {
.setValue('@organization', store.organization.name) .setValue('@organization', store.organization.name)
.setValue('@type', 'Vault', done); .setValue('@type', 'Vault', done);
}, },
'expected fields are visible and enabled': function(client) { 'expected fields are visible and enabled': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details.expect.element('@name').visible; details.expect.element('@name').visible;
details.expect.element('@description').visible; details.expect.element('@description').visible;
@@ -61,19 +58,20 @@ module.exports = {
details.expect.element('@type').enabled; details.expect.element('@type').enabled;
details.section.vault.expect.element('@vaultPassword').enabled; details.section.vault.expect.element('@vaultPassword').enabled;
}, },
'required fields display \'*\'': function(client) { 'required fields display \'*\'': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const required = [ const required = [
details.section.name, details.section.name,
details.section.type, details.section.type,
details.section.vault.section.vaultPassword, details.section.vault.section.vaultPassword,
] ];
required.map(s => s.expect.element('@label').text.to.contain('*')); required.map(s => s.expect.element('@label').text.to.contain('*'));
}, },
'save button becomes enabled after providing required fields': function(client) { 'save button becomes enabled after providing required fields': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details details
.clearAndSelectType('Vault') .clearAndSelectType('Vault')
@@ -83,9 +81,9 @@ module.exports = {
details.section.vault.setValue('@vaultPassword', 'ch@ng3m3'); details.section.vault.setValue('@vaultPassword', 'ch@ng3m3');
details.expect.element('@save').enabled; details.expect.element('@save').enabled;
}, },
'vault password field is disabled when prompt on launch is selected': function(client) { 'vault password field is disabled when prompt on launch is selected': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
details details
.clearAndSelectType('Vault') .clearAndSelectType('Vault')
@@ -95,10 +93,10 @@ module.exports = {
details.section.vault.section.vaultPassword.click('@prompt'); details.section.vault.section.vaultPassword.click('@prompt');
details.section.vault.expect.element('@vaultPassword').not.enabled; details.section.vault.expect.element('@vaultPassword').not.enabled;
}, },
'create vault credential': function(client) { 'create vault credential': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const add = credentials.section.add; const { add } = credentials.section;
const edit = credentials.section.edit; const { edit } = credentials.section;
add.section.details add.section.details
.clearAndSelectType('Vault') .clearAndSelectType('Vault')
@@ -115,12 +113,12 @@ module.exports = {
edit.expect.element('@title').text.equal(store.credential.name); edit.expect.element('@title').text.equal(store.credential.name);
}, },
'edit details panel remains open after saving': function(client) { 'edit details panel remains open after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
credentials.section.edit.expect.section('@details').visible; credentials.section.edit.expect.section('@details').visible;
}, },
'credential is searchable after saving': function(client) { 'credential is searchable after saving': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const row = '#credentials_table tbody tr'; const row = '#credentials_table tbody tr';

View File

@@ -1,7 +1,7 @@
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
@@ -19,11 +19,11 @@ module.exports = {
.click('@add'); .click('@add');
details details
.waitForElementVisible('@save', done) .waitForElementVisible('@save', done);
}, },
'open the lookup modal': function(client) { 'open the lookup modal': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const modal = 'div[class="modal-body"]'; const modal = 'div[class="modal-body"]';
const title = 'div[class^="Form-title"]'; const title = 'div[class^="Form-title"]';
@@ -38,7 +38,7 @@ module.exports = {
client.expect.element(modal).present; client.expect.element(modal).present;
let expected = 'SELECT CREDENTIAL TYPE'; const expected = 'SELECT CREDENTIAL TYPE';
client.expect.element(title).visible; client.expect.element(title).visible;
client.expect.element(title).text.equal(expected); client.expect.element(title).text.equal(expected);

View File

@@ -1,7 +1,7 @@
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
client.login(); client.login();
client.waitForAngular(); client.waitForAngular();
@@ -20,12 +20,11 @@ module.exports = {
details details
.waitForElementVisible('@save', done); .waitForElementVisible('@save', done);
}, },
'open the lookup modal': function(client) { 'open the lookup modal': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const lookupModal = credentials.section.lookupModal; const { lookupModal } = credentials.section;
details.expect.element('@organization').visible; details.expect.element('@organization').visible;
details.expect.element('@organization').enabled; details.expect.element('@organization').enabled;
@@ -37,15 +36,15 @@ module.exports = {
credentials.expect.section('@lookupModal').present; credentials.expect.section('@lookupModal').present;
let expected = 'SELECT ORGANIZATION'; const expected = 'SELECT ORGANIZATION';
lookupModal.expect.element('@title').visible; lookupModal.expect.element('@title').visible;
lookupModal.expect.element('@title').text.equal(expected); lookupModal.expect.element('@title').text.equal(expected);
}, },
'select button is disabled until item is selected': function(client) { 'select button is disabled until item is selected': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const details = credentials.section.add.section.details; const { details } = credentials.section.add.section;
const lookupModal = credentials.section.lookupModal; const { lookupModal } = credentials.section;
const table = lookupModal.section.table; const { table } = lookupModal.section;
details.section.organization.expect.element('@lookup').visible; details.section.organization.expect.element('@lookup').visible;
details.section.organization.expect.element('@lookup').enabled; details.section.organization.expect.element('@lookup').enabled;
@@ -70,12 +69,12 @@ module.exports = {
lookupModal.expect.element('@select').visible; lookupModal.expect.element('@select').visible;
lookupModal.expect.element('@select').enabled; lookupModal.expect.element('@select').enabled;
}, },
'sort and unsort the table by name with an item selected': function(client) { 'sort and unsort the table by name with an item selected': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const lookupModal = credentials.section.lookupModal; const { lookupModal } = credentials.section;
const table = lookupModal.section.table; const { table } = lookupModal.section;
let column = table.section.header.findColumnByText('Name'); const column = table.section.header.findColumnByText('Name');
column.expect.element('@self').visible; column.expect.element('@self').visible;
column.expect.element('@sortable').visible; column.expect.element('@sortable').visible;
@@ -100,11 +99,11 @@ module.exports = {
table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected; table.expect.element('tbody tr:nth-child(4) input[type="radio"]').not.selected;
table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected; table.expect.element('tbody tr:nth-child(5) input[type="radio"]').not.selected;
}, },
'use the pagination controls with an item selected': function(client) { 'use the pagination controls with an item selected': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const lookupModal = credentials.section.lookupModal; const { lookupModal } = credentials.section;
const table = lookupModal.section.table; const { table } = lookupModal.section;
const pagination = lookupModal.section.pagination; const { pagination } = lookupModal.section;
pagination.click('@next'); pagination.click('@next');
credentials.waitForElementVisible('div.spinny'); credentials.waitForElementVisible('div.spinny');

View File

@@ -1,5 +1,5 @@
module.exports = { module.exports = {
beforeEach: function(client, done) { beforeEach: (client, done) => {
const credentials = client.useCss().page.credentials(); const credentials = client.useCss().page.credentials();
client.login(); client.login();
@@ -10,7 +10,7 @@ module.exports = {
.waitForElementVisible('div.spinny') .waitForElementVisible('div.spinny')
.waitForElementNotVisible('div.spinny', done); .waitForElementNotVisible('div.spinny', done);
}, },
'activity link is visible and takes user to activity stream': function(client) { 'activity link is visible and takes user to activity stream': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const activityStream = client.page.activityStream(); const activityStream = client.page.activityStream();

View File

@@ -1,10 +1,8 @@
const columns = ['Name', 'Kind', 'Owners', 'Actions']; const columns = ['Name', 'Kind', 'Owners', 'Actions'];
const sortable = ['Name']; const sortable = ['Name'];
const defaultSorted = ['Name'];
module.exports = { module.exports = {
before: function(client, done) { before: (client, done) => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
client.login(); client.login();
@@ -18,30 +16,30 @@ module.exports = {
credentials.waitForElementVisible('#credentials_table', done); credentials.waitForElementVisible('#credentials_table', done);
}, },
'expected table columns are visible': function(client) { 'expected table columns are visible': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const table = credentials.section.list.section.table; const { table } = credentials.section.list.section;
columns.map(label => { columns.forEach(label => {
table.section.header.findColumnByText(label) table.section.header.findColumnByText(label)
.expect.element('@self').visible; .expect.element('@self').visible;
}); });
}, },
'only fields expected to be sortable show sort icon': function(client) { 'only fields expected to be sortable show sort icon': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const table = credentials.section.list.section.table; const { table } = credentials.section.list.section;
sortable.map(label => { sortable.forEach(label => {
table.section.header.findColumnByText(label) table.section.header.findColumnByText(label)
.expect.element('@sortable').visible; .expect.element('@sortable').visible;
}); });
}, },
'sort all columns expected to be sortable': function(client) { 'sort all columns expected to be sortable': client => {
const credentials = client.page.credentials(); const credentials = client.page.credentials();
const table = credentials.section.list.section.table; const { table } = credentials.section.list.section;
sortable.map(label => { sortable.forEach(label => {
let column = table.section.header.findColumnByText(label); const column = table.section.header.findColumnByText(label);
column.click('@self'); column.click('@self');

View File

@@ -1,6 +1,6 @@
'use strict'; 'use strict';
describe('Directive: column-sort', () =>{ xdescribe('Directive: column-sort', () =>{
let $scope, template, $compile, QuerySet, GetBasePath; let $scope, template, $compile, QuerySet, GetBasePath;

View File

@@ -0,0 +1,45 @@
const path = require('path');
const SRC_PATH = path.resolve(__dirname, '../../client/src');
const NODE_MODULES = path.resolve(__dirname, '../../node_modules');
const webpackConfig = require('./webpack.spec');
module.exports = function(config) {
config.set({
autoWatch: true,
colors: true,
browsers: ['Chrome', 'Firefox'],
coverageReporter: {
reporters: [
{ type: 'html', subdir: 'html' },
]
},
frameworks: [
'jasmine',
],
reporters: ['progress', 'coverage', 'junit'],
files:[
path.join(SRC_PATH, '**/*.html'),
path.join(SRC_PATH, 'vendor.js'),
path.join(NODE_MODULES, 'angular-mocks/angular-mocks.js'),
path.join(SRC_PATH, 'app.js'),
'**/*-test.js',
],
preprocessors: {
[path.join(SRC_PATH, '**/*.html')]: 'html2js',
[path.join(SRC_PATH, 'vendor.js')]: 'webpack',
[path.join(SRC_PATH, 'app.js')]: 'webpack',
'**/*-test.js': 'webpack'
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: true
},
junitReporter: {
outputDir: 'coverage',
outputFile: 'ui-unit-test-results.xml',
useBrowserName: false
}
});
};

View File

@@ -0,0 +1,18 @@
const path = require('path');
const webpack = require('webpack');
const merge = require('webpack-merge');
const base = require(path.resolve(__dirname, '../..', 'build/webpack.base'));
const STATIC_URL = '/static/';
const test = {
devtool: 'inline-source-map',
plugins: [
new webpack.DefinePlugin({
$basePath: STATIC_URL
})
]
};
module.exports = merge(base, test);

View File

@@ -0,0 +1,6 @@
module.exports = {
env: {
jasmine: true
}
};

View File

@@ -0,0 +1,8 @@
// Import angular and angular-mocks to the global scope
import 'angular-mocks';
// Import tests
import './layout.unit';
import './side-nav.unit';
import './side-nav-item.unit';

View File

@@ -0,0 +1,160 @@
describe('Components | Layout', () => {
let $compile;
let $rootScope;
let element;
let scope;
beforeEach(() => {
angular.mock.module('gettext');
angular.mock.module('I18N');
angular.mock.module('ui.router');
angular.mock.module('at.lib.services');
angular.mock.module('at.lib.components');
});
beforeEach(angular.mock.inject((_$compile_, _$rootScope_) => {
$compile = _$compile_;
$rootScope = _$rootScope_;
scope = $rootScope.$new();
element = angular.element('<at-layout></at-layout>');
element = $compile(element)(scope);
scope.$digest();
}));
describe('AtLayoutController', () => {
let controller;
beforeEach(() => {
controller = element.controller('atLayout');
});
it('$scope.$on($stateChangeSuccess) should assign toState name to currentState', () => {
const next = { name: 'dashboard' };
$rootScope.$broadcast('$stateChangeSuccess', next);
expect(controller.currentState).toBe('dashboard');
});
describe('$root.current_user watcher should assign value to ', () => {
beforeEach(() => {
const val = {
username: 'admin',
id: 1
};
$rootScope.current_user = val;
scope.$digest();
});
it('isLoggedIn', () => {
expect(controller.isLoggedIn).toBe('admin');
$rootScope.current_user = { id: 1 };
scope.$digest();
expect(controller.isLoggedIn).not.toBeDefined();
});
it('isSuperUser', () => {
$rootScope.current_user = 'one';
$rootScope.user_is_superuser = true;
$rootScope.user_is_system_auditor = false;
scope.$digest();
expect(controller.isSuperUser).toBe(true);
$rootScope.current_user = 'two';
$rootScope.user_is_superuser = false;
$rootScope.user_is_system_auditor = true;
scope.$digest();
expect(controller.isSuperUser).toBe(true);
$rootScope.current_user = 'three';
$rootScope.user_is_superuser = true;
$rootScope.user_is_system_auditor = true;
scope.$digest();
expect(controller.isSuperUser).toBe(true);
$rootScope.current_user = 'four';
$rootScope.user_is_superuser = false;
$rootScope.user_is_system_auditor = false;
scope.$digest();
expect(controller.isSuperUser).toBe(false);
});
it('currentUsername', () => {
expect(controller.currentUsername).toBeTruthy();
expect(controller.currentUsername).toBe('admin');
});
it('currentUserId', () => {
expect(controller.currentUserId).toBeTruthy();
expect(controller.currentUserId).toBe(1);
});
});
describe('$root.socketStatus watcher should assign newStatus to', () => {
const statuses = ['connecting', 'error', 'ok'];
it('socketState', () => {
_.forEach(statuses, (status) => {
$rootScope.socketStatus = status;
scope.$digest();
expect(controller.socketState).toBeTruthy();
expect(controller.socketState).toBe(status);
});
});
it('socketIconClass', () => {
_.forEach(statuses, (status) => {
$rootScope.socketStatus = status;
scope.$digest();
expect(controller.socketIconClass).toBe(`icon-socket-${status}`);
});
});
});
describe('$root.licenseMissing watcher should assign true or false to', () => {
it('licenseIsMissing', () => {
$rootScope.licenseMissing = true;
scope.$digest();
expect(controller.licenseIsMissing).toBe(true);
$rootScope.licenseMissing = false;
scope.$digest();
expect(controller.licenseIsMissing).toBe(false);
});
});
describe('getString()', () => {
it('calls ComponentsStrings get() method', angular.mock.inject((_ComponentsStrings_) => {
spyOn(_ComponentsStrings_, 'get');
controller.getString('VIEW_DOCS');
expect(_ComponentsStrings_.get).toHaveBeenCalled();
}));
it('ComponentsStrings get() method should throw an error if string is not a property name of the layout class', () => {
expect(controller.getString.bind(null, 'SUBMISSION_ERROR_TITLE')).toThrow();
});
it('should return layout string', () => {
const layoutStrings = {
CURRENT_USER_LABEL: 'Logged in as',
VIEW_DOCS: 'View Documentation',
LOGOUT: 'Logout',
};
_.forEach(layoutStrings, (value, key) => {
expect(controller.getString(key)).toBe(value);
});
});
it('should return default string', () => {
const defaultStrings = {
BRAND_NAME: 'AWX'
};
_.forEach(defaultStrings, (value, key) => {
expect(controller.getString(key)).toBe(value);
});
});
});
});
});

View File

@@ -0,0 +1,60 @@
describe('Components | Side Nav Item', () => {
let $compile;
let $rootScope;
let element;
let scope;
beforeEach(() => {
angular.mock.module('gettext');
angular.mock.module('I18N');
angular.mock.module('ui.router');
angular.mock.module('at.lib.services');
angular.mock.module('at.lib.components');
});
beforeEach(angular.mock.inject((_$compile_, _$rootScope_) => {
$compile = _$compile_;
$rootScope = _$rootScope_;
scope = $rootScope.$new();
element = angular.element('<at-layout><at-side-nav><at-side-nav-item icon-class="fa-tachometer" route="dashboard" name="DASHBOARD"></at-side-nav-item></at-layout></at-side-nav>');
element = $compile(element)(scope);
scope.name = 'dashboard';
scope.$digest();
}));
describe('Side Nav Item Controller', () => {
let SideNavItem;
let SideNavItemCtrl;
beforeEach(() => {
SideNavItem = angular.element(element[0].querySelector('at-side-nav-item'));
SideNavItemCtrl = SideNavItem.controller('atSideNavItem');
});
it('layoutVm.currentState watcher should assign isRoute', () => {
let current = { name: 'dashboard' };
$rootScope.$broadcast('$stateChangeSuccess', current);
scope.$digest();
expect(SideNavItemCtrl.isRoute).toBe(true);
current = { name: 'inventories' };
$rootScope.$broadcast('$stateChangeSuccess', current);
scope.$digest();
expect(SideNavItemCtrl.isRoute).toBe(false);
});
it('go() should call $state.go()', angular.mock.inject((_$state_) => {
spyOn(_$state_, 'go');
SideNavItemCtrl.go();
expect(_$state_.go).toHaveBeenCalled();
expect(_$state_.go).toHaveBeenCalledWith('dashboard', jasmine.any(Object), jasmine.any(Object));
}));
it('should load name, icon, and route from scope', () => {
expect(SideNavItem.isolateScope().name).toBeDefined();
expect(SideNavItem.isolateScope().iconClass).toBeDefined();
expect(SideNavItem.isolateScope().route).toBeDefined();
});
});
});

View File

@@ -0,0 +1,78 @@
describe('Components | Side Nav', () => {
let $compile;
let $rootScope;
let element;
let scope;
const windowMock = {
innerWidth: 500
};
beforeEach(() => {
angular.mock.module('gettext');
angular.mock.module('I18N');
angular.mock.module('ui.router');
angular.mock.module('at.lib.services');
angular.mock.module('at.lib.components', ($provide) => {
$provide.value('$window', windowMock);
});
});
beforeEach(angular.mock.inject((_$compile_, _$rootScope_) => {
$compile = _$compile_;
$rootScope = _$rootScope_;
scope = $rootScope.$new();
element = angular.element('<at-layout><at-side-nav></at-side-nav><at-layout>');
element = $compile(element)(scope);
scope.$digest();
}));
describe('Side Nav Controller', () => {
let sideNav;
let sideNavCtrl;
beforeEach(() => {
sideNav = angular.element(element[0].querySelector('.at-Layout-side'));
sideNavCtrl = sideNav.controller('atSideNav');
});
it('isExpanded defaults to false', () => {
expect(sideNavCtrl.isExpanded).toBe(false);
});
it('toggleExpansion()', () => {
expect(sideNavCtrl.isExpanded).toBe(false);
sideNavCtrl.toggleExpansion();
expect(sideNavCtrl.isExpanded).toBe(true);
sideNavCtrl.toggleExpansion();
expect(sideNavCtrl.isExpanded).toBe(false);
sideNavCtrl.toggleExpansion();
expect(sideNavCtrl.isExpanded).toBe(true);
sideNavCtrl.toggleExpansion();
expect(sideNavCtrl.isExpanded).toBe(false);
});
it('isExpanded should be false after state change event', () => {
sideNavCtrl.isExpanded = true;
const current = {
name: 'dashboard'
};
$rootScope.$broadcast('$stateChangeSuccess', current);
scope.$digest();
expect(sideNavCtrl.isExpanded).toBe(false);
});
it('clickOutsideSideNav watcher should assign isExpanded to false', () => {
sideNavCtrl.isExpanded = true;
$rootScope.$broadcast('clickOutsideSideNav');
scope.$digest();
expect(sideNavCtrl.isExpanded).toBe(false);
});
});
});

View File

@@ -1,7 +1,2 @@
// Import angular and angular-mocks to the global scope import './components';
import 'angular-mocks';
// Import tests
import './layout.spec';
import './side-nav.spec';
import './side-nav-item.spec';

View File

@@ -0,0 +1,39 @@
const path = require('path');
const SRC_PATH = path.resolve(__dirname, '../../client/src');
const webpackConfig = require('./webpack.unit');
module.exports = config => {
config.set({
basePath: '',
singleRun: true,
autoWatch: false,
colors: true,
frameworks: ['jasmine'],
browsers: ['PhantomJS'],
reporters: ['progress'],
files: [
path.join(SRC_PATH, 'vendor.js'),
path.join(SRC_PATH, 'app.js'),
path.join(SRC_PATH, '**/*.html'),
'index.js'
],
plugins: [
'karma-webpack',
'karma-jasmine',
'karma-phantomjs-launcher',
'karma-html2js-preprocessor'
],
preprocessors: {
[path.join(SRC_PATH, 'vendor.js')]: 'webpack',
[path.join(SRC_PATH, 'app.js')]: 'webpack',
[path.join(SRC_PATH, '**/*.html')]: 'html2js',
'index.js': 'webpack'
},
webpack: webpackConfig,
webpackMiddleware: {
noInfo: 'errors-only'
}
});
};

View File

@@ -0,0 +1,16 @@
const webpack = require('webpack');
const merge = require('webpack-merge');
const base = require('../../build/webpack.base');
const STATIC_URL = '/static/';
const test = {
devtool: 'cheap-source-map',
plugins: [
new webpack.DefinePlugin({
$basePath: STATIC_URL
})
]
};
module.exports = merge(base, test);