How can i set multiCapabilities dynamically in protractor config file - protractor

I am using protractor 5.2.2. I have a requirement of setting multiCapabilities dynamically in protractor config file.Currently i have hard coded and set multiCapabilities as given below.
multiCapabilities: [
{
browserName: 'chrome',
BatchNo:1
},
{
browserName: 'chrome',
BatchNo:2
}],
i have a dynamic parameter called threads in beforeLaunch function.So depending on the value of this parameter, i have to set multiCapabilities dynamically and the BatchNo also.In above code i have threads=2, so i have 2 objects in multiCapabilities and BatchNo set as 1 and 2 respectively.If i have threads=4 in beforeLaunch function, then i have to set 4 objects in multiCapabilities and BatchNo should set as 1,2,3 and 4 respectively(i am using chrome browser for all threads).How can i do this.Thanks in advance.

We can use getMultiCapabilities() to customize dynamical capabilites.
/**
* If you need to resolve multiCapabilities asynchronously (i.e. wait for
* server/proxy, set firefox profile, etc), you can specify a function here
* which will return either `multiCapabilities` or a promise to
* `multiCapabilities`.
*
* If this returns a promise, it is resolved immediately after
* `beforeLaunch` is run, and before any driver is set up. If this is
* specified, both capabilities and multiCapabilities will be ignored.
*/
getMultiCapabilities?: any;
Define a function to get thread value.
let getThreadValue = function () {
return new Promise(function (resolve, reject) {
request = new Request("sql to query thread value", function (err, rowCount, rows) {
if (err) {
reject(err);
}
else {
resolve('put thread value at here');
}
});
connection.execSql(request);
});
};
Use getMultiCapabilities in protractor conf.js:
exports.config = {
seleniumAddress: 'http://localhost:4444/wd/hub',
specs: ['./test.js'],
// If getMultiCapabilities is specified,
// both capabilities and multiCapabilities will be ignored
getMultiCapabilities: function () {
return getThreadValue().then(function (thread) {
let multiCapabilities = [];
for (index = 1; index <= thread; index++) {
multiCapabilities.push({
browserName: 'chrome',
BatchNo: index
})
}
return multiCapabilities;
});
}
};
Related code for further question about beforeLaunch issue:
let getThreadValue = function () {
return new Promise(function (resolve, reject) {
connection.on('connect', function (err) {
if (err) {
reject(err);
}
else {
request = new Request("select * from location", function (err, rowCount, rows) {
if (err) {
reject(err);
} else {
resolve(Math.ceil(rowCount / 3));
}
});
connection.execSql(request);
}
});
});
};
beforeLaunch: function() {
return getThreadValue().then(function (thread) {
console.log('thread: ' + thread);
return new Promise(function(resolve, reject){
connection.on('connect', function (err) {
if (err) {
reject(err);
} else {
request = new Request("EXEC [usp_GetPostDetails] 1514," + thread, function (err, rowCount, rows) {
if (err) {
reject(err);
} else {
console.log("done");
resolve('done');
}
});
connection.execSql(request);
}
});
});
});
}

multiCapabilities should get Array<string>. You could create a variable that will have a function that returns specific array corresponding to your condition.
For example:
firstly create a function that create your own multiCapabilities array
function createArray(threads) {
const array = [];
for (let batch = 1; batch <= threads; batch++) {
array.push({
browserName: 'chrome',
BatchNo: batch
});
}
return array;
}
create variable that returns specific multiCapabilities corresponding to your threads
const myMultiCapabilities = (threads) => {
return createArray(threads);
}
and finally use it for setting multiCapabilities:
multiCapabilities: myMultiCapabilities(threads)

Related

Not able to fetch correct data while executing 2 queries in BeforeAll function in protractor

I am using protractor 5.2.2. and cucumber 3.2.0.I am executing 2 queries in Before All function for fetching the data from the DB.But i need to execute in a way that after executing first query completely, then only i need to start executing the second query(because i am using the 1st query result in 2nd query and i need to catch the 2nd query result before starting all scenarios.).The code i have given in the BeforeAll function is given below
var Connection = require('tedious').Connection;
var Request = require('tedious').Request;
var config =
{
userName: 'xxx',
password: 'xxxx',
server: 'xxxx',
options:
{
database: 'xx' ,
encrypt: true,
rowCollectionOnRequestCompletion: true
}
}
var connection = new Connection(config);
connection.on('connect', function (err) {
if (err) {
console.log(err);
}
else {
request1 = new Request("EXEC [dbo].[usp_GetPost]", function (err, rowCount, rows) {
if (err) {
console.log("Error");
}
});
connection.execSql(request1);
request2 = new Request("select * from [dbo].[Post_Automation] ", function (err, rowCount, rows) {
});
request2.on('row', function (columns) {
var row = {};
columns.forEach(function (column) {
row[column.metadata.colName] = column.value;
});
post_details.push(row);
});
connection.execSql(request2);
}
});
How can i do this.Thanks in advance.

Issue with adding suite name in gulp protractor

I am stuck with Gulp as a wrapper. I have multiple spec files in my work for different projects(websites) and i want to create test suites out of these spec files.
Below is the code written by someone in gulp
`
var binPath = './node_modules/.bin/';
gulp.task('test-all', function(cb) {
async.eachSeries(glob.sync('sites/*'), testSite, cb);
});
gulp.task('test', function(cb) {
env.validate(util.env, {
site: {
required: true,
},
useSelenium: {
required: false,
},
params: {
required: false,
}
});
testSite('sites/' + util.env.site, cb);
});
gulp.task('explorer', function(cb) {
runProtractor(['--elementExplorer', '--directConnect'], cb);
});
gulp.task('serve', function(cb) {
runModule('webdriver-manager', ['start'], cb);
});
gulp.task('update', function(cb) {
runModule('webdriver-manager', ['update'], cb);
});
gulp.task('default', ['test']);
function runModule(name, params, cb) {
new simpleCommand(path.join(binPath, name), params, process.cwd()).run(cb);
}
function runProtractor(params, cb) {
runModule('protractor', params, cb);
}
function testSite(site, cb) {
var params = [
site + '/protractor.conf.js', suite=smoke,
'--params.timestamp=' + timestamp
];
if (!util.env.useSelenium) {
params.push('--directConnect');
}
if (util.env.params) {
params.push(util.env.params.replace(/(^['"]|['"]$)/g, '').trim());
}
util.log('Testing ' + site);
runProtractor(params, function(err) {
if (err) {
util.log(err);
}
cb();
});
}
`
I have now specified suite name which i want to execute above. But i want to capture this name of suite from command line argument.
gulp test --site [sitename] --suite=smoke
How will i be able to capture suite name from above statement?
I got this to work.
function testSite(site, cb) {
var params = [
site + '/protractor.conf.js', '--suite='+util.env.suite,
'--params.timestamp=' + timestamp

Protractor ignoring specs passed in a callback function

I'm running into an issue and need your help.
I have a list of products and I want to run some it blocks for each product.
The function getProducts is an asynchronous function. Here is my code.
jsonLoader = new Promise(function(resolve, reject) {
beforeAll(function(done) {
getProducts(function(loadedProducts) {
resolve(loadedProducts);
done();
});
});
});
describe('product-maintenance', function() {
jsonLoader.then(function(products) {
productsList = products;
//productsList contains the desired products
_.forOwn(productsList, function(product) {
//execute it-blocks
});
});
it('some test', function() {
expect(1).toBe(1);
});
});
He is only executing the it 'some test' and simply ignoring the it blocks in the _.forOwn loop.
Thanks !!! :)
I solved this by using promises in the onPrepare function.
onPrepare: function() {
var deferred = protractor.promise.defer();
getProducts(function(products) {
if (!products) {
deferred.reject(new Error('An error occured while loading products'));
} else {
productsModule.setProducts(products);
deferred.fulfill();
}
});
return deferred.promise;
}

nightwatch custom command callback

I'm trying to create a custom command in nightwatch that runs a query on a Postgres database and returns the result. The query runs just fine and outputs the result to the console but then the execution of the test stops. I don't understand how callbacks work. How can I fix this custom command?
exports.command = function(sql, callback) {
var self = this;
var pg = require('pg');
var conString = self.globals.testinfo.connectionString;
var db = new pg.Client(conString);
db.connect(function(err) {
if(err) {
console.error('could not connect', err);
}
else {
db.query(sql, function(err, result) {
if(err) {
console.log('error running query', err);
}
else {
console.log(result.rows.length);
db.end();
}
});
}
}),
function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
}
return this;
};
I had to wrap the database connection in a perform command to get this working. I'm not sure if this is the best way to handle the callback, but it works. Here's the updated version of the custom command:
exports.command = function(sql,callback) {
var self = this;
var pg = require('pg');
var cs = self.globals.testinfo.connectionString;
self.perform(function(self,done) {
pg.connect(cs,function(err,db,done) {
if(err) {
return console.error(err);
}
db.query(sql, function(err,result) {
done();
if(err) {
return console.error(err);
}
console.log(result.rows.length);
callback(result.rows[0]);
});
});
pg.end();
done();
});
};
Here's how I call the custom command in the test:
browser.myCustomCommand('select * from table limit 1;', function(row) {
browser.assert.deepEqual(row.column,'some value');
});
Can you try this:
exports.command = function(sql, callback) {
var self = this;
var pg = require('pg');
var conString = self.globals.testinfo.connectionString;
var db = new pg.Client(conString);
var cb= function(result) {
if (typeof callback === 'function') {
callback.call(self, result);
}
};
db.connect(function(err) {
if(err) {
console.error('could not connect', err);
cb(false);
}
else {
db.query(sql, function(err, result) {
if(err) {
console.log('error running query', err);
cb(false);
}
else {
console.log(result.rows.length);
db.end();
cb(true);
}
});
}
}),
return this;
};
And in your test :
'test' : function(browser){
browser.yourCommandName(sql,function(result){
console.log(result); //if connect is good result would be true and false if fail to connect.
});
}
Ps: the result in callback can be as an object(contain rows or anything you want), instead of boolean only in this example.
And Nightwatch is used for end-to-end testing, it is not aimed for Database testing,i think you should find another framework to test database connection.

ionic service init before loading controller

I have service which has asynchronous init of parameter and I want that every controller to wait until the init will be finished.
The problem is that the getObject method is being called by the controller before the init of parameters variable is finished.
The service:
angular.module('core')
.factory('localstorage', ['$window', '$cordovaSQLite', '$q',
function ($window, $cordovaSQLite, $q) {
var db;
var parameters = {};
if (window.cordova) {
db = $cordovaSQLite.openDB({name: "my.db"}); //device
} else {
db = window.openDatabase("my.db", '1', 'life', 1024 * 1024 * 100);
}
var promise = $q(function (resolve, reject) {
$cordovaSQLite.execute(db, "SELECT * FROM life_table")
.then(function (res) {
if (res.rows.length == 0) {
$cordovaSQLite.execute(db,
"CREATE TABLE IF NOT EXISTS life_table (key text primary key, value text)");
}
else {
for (var i = 0; i < res.rows.length; ++i) {
parameters[res.rows[i].key] = JSON.parse(res.rows[i].value);
}
}
resolve(parameters);
});
});
return {
promise: promise,
getObject: function (key) {
var query = "SELECT value FROM life_table where key = ?";
$cordovaSQLite.execute(db, query, [key]).then(function (res) {
if (res.rows.length > 0) {
console.log("getObject: " + res.rows[0].value);
}
}, function (err) {
console.error(err);
});
return parameters[key];
}
}
}]);
the config:
.config(function ($stateProvider, $urlRouterProvider) {
$stateProvider
.state('navigator', {
url: '/',
abstract: true,
controller: 'NavigatorCtrl',
resolve: {
'MyServiceData': function (localstorage) {
// localstorage will also be injectable in the controller
return localstorage.promise;
}
}
})
.state('login', {
url: '/login',
templateUrl: 'templates/login.html',
controller: 'LoginCtrl',
controllerAs: 'loginCtrl',
resolve: {
'MyServiceData': function (localstorage) {
// localstorage will also be injectable in the controller
return localstorage.promise;
}
}
})
Shalom Dor!
Option 1
Make a chain of promises and return the factory only after all promises are resolved. This will prevent the controller from running as the factory dependency will not be returned until the desired promises are resolved.
Option 2
Create some sort initialization function in your service that returns a promise (you can use $q). Execute it inside $ionicPlaform.ready() and only run the controller logic after you got the promise.
In the controller:
MyService.initialize().then(function () {
// Service initialized, do stuff...
});
In the service:
returned.initialize = function () {
var d = q.defer();
// Do stuff...
// Resolve 'd' when you finished initializing the service using 'd.resolve()'.
return d.promise;
};