Issue with adding suite name in gulp protractor - 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

Related

protractor is not capturing the Screenshot with Cucumber Reporter

i am using Protractor with Cucumber to test angular application, for reporting i am using "cucumber-html-reporter", i am not able to capture the screenshot in report and its not getting saved in the given folder as well
reporter.js
const reporter = require("cucumber-html-reporter");
cucumberReporteroptions = {
theme: "bootstrap",
//jsonFile: targetJson,
jsonDir: targetjsonDir,
output: htmlReports + "/cucumber_reporter"+datetime+".html",
reportSuiteAsScenarios: true,
storeScreenshots:true,
screenshotsDirectory:htmlReports +'/screenshots',
reportSuiteAsScenarios:true,
launchReport:true,
ignoreBadJsonFile:true
};
class Reporter {
static createHTMLReport() {
try {
reporter.generate(cucumberReporteroptions); //invoke cucumber-html-reporter
} catch (err) {
if (err) {
console.log("Failed to save cucumber test results to json file.");
console.log(err);
}
}
}
hooks.js
After(function(scenario) {
const attach = this.attach;
return browser.takeScreenshot().then(function(png) {
const decodedImage = new Buffer(png, "base64");
return attach(decodedImage, "image/png");
});
});
Quick checks that you can do from your side, to make sure reporter is invoked properly:
onPrepare: () => {
browser.ignoreSynchronization = true;
browser.manage().window().maximize();
Reporter.createDirectory(jsonReports);
},
cucumberOpts: {
compiler: "ts:ts-node/register",
format: "json:./reports/json/cucumber_report.json",
require: ["../../typeScript/stepdefinitions/*.js", "../../typeScript/support/*.js"],
strict: true,
},
onComplete: () => {
Reporter.createHTMLReport();
},
Can you try this,
defineSupportCode(({After}) => {
After(function(scenario) {
if (scenario.isFailed()) {
var attach = this.attach;
return browser.takeScreenshot().then(function(png) {
var decodedImage = new Buffer(png, "base64");
return attach(decodedImage, "image/png");
});
}
});
});
Lemme know how it goes!

How can i set multiCapabilities dynamically in protractor config file

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)

Angularjs RESTul Resource Request

I am trying to make the request
....port/trimService/fragments/?fragment_name=:fragmentName
However if I try to make the "?fragment_name" a parameter, it breaks. As I am going to have more requests, my action with change so I cannot leave it in the url portion of the resource.
angular.module(foo).factory('FragmentService', ['$resource',
function ($resource)
{
var FragmentService = $resource('.../fragments/:action:fragmentName',
{},
{
'getFragments':
{
method: 'GET',
isArray: true,
params:
{
fragmentName: "#fragmentName",
action: "?fragment_name="
}
}
});
return FragmentService;
}
]);
As of right now, I have no idea what my URL is actually outputting.
EDIT: I changed my resource as /u/akonsu had mentioned below. I also added my controller as it is still not working correctly.
angular.module(foo).factory('FragmentService', ['$resource',
function ($resource)
{
var FragmentService = $resource('.../fragments/',
{},
{
'getFragments':
{
method: 'GET',
isArray: true,
params:
{
fragmentName: "#fragmentName",
}
}
});
return FragmentService;
}
]);
angular.module(foo).controller('FragmentController', ['$scope', 'FragmentService',
function ($scope, FragmentService)
{
$scope.fragmentQuery = {
fragmentName: 'a',
};
$scope.fragmentQuery.execute = function ()
{
if ($scope.fragmentQuery.fragmentName == '')
{
$scope.fragments = {};
}
else
{
$scope.fragments = FragmentService.getFragments(
{
fragmentName: $scope.fragmentQuery.fragmentName,
});
}
};
$scope.fragmentQuery.execute();
}
]);
Try omitting the query string altogether in the resource URL and just supply your fragmentName as a parameter to the action call. It should add it to the query string if it is not in the list of URL parameters.
$resource(".../port/trimService/fragments/").get({fragmentName: 'blah'})

How to reuse jquery-ui-autocomplete cached results when appending search term?

I have the following JS method to bind the jQuery UI autocomplete widget to a search text box. Everything works fine, including caching, except that I make unnecessary server calls when appending my search term because I don't reuse the just-retrieved results.
For example, searching for "ab" fetches some results from the server. Typing "c" after "ab" in the search box fetches "abc" results from the server, instead of reusing the cached "ab" results and omitting ones that don't match "abc".
I went down the path of manually looking up the "ab" search results, filtering them using a regex to select the "abc" subset, but this totally seems like I'm reinventing the wheel. What is the proper, canonical way to tell the widget to use the "ab" results, but filter them for the "abc" term and redisplay the shortened dropdown?
function bindSearchForm() {
"use strict";
var cache = new Object();
$('#search_text_field').autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term;
if (term in cache) {
response(cache[term]);
return;
}
$.ajax({type: 'POST',
dataType: 'json',
url: '/get_search_data',
data: {q: term},
success: function (data) {
cache[term] = data;
response(data);
}
});
});
}
Here's my "brute-force, reinventing the wheel" method, which is, for now, looking like the right solution.
function bindSearchForm() {
"use strict";
var cache = new Object();
var terms = new Array();
function cacheNewTerm(newTerm, results) {
// maintain a 10-term cache
if (terms.push(newTerm) > 10) {
delete cache[terms.shift()];
}
cache[newTerm] = results;
};
$('#search_text_field').autocomplete({
minLength: 2,
source: function (request, response) {
var term = request.term.toLowerCase();
if (term in cache) {
response(cache[term]);
return;
} else if (terms.length) {
var lastTerm = terms[terms.length - 1];
if (term.substring(0, lastTerm.length) === lastTerm) {
var results = new Array();
for (var i = 0; i < cache[lastTerm].length; i++) {
if (cache[lastTerm][i].label.toLowerCase().indexOf(term) !== -1) {
results.push(cache[lastTerm][i]);
}
}
response(results);
return;
}
}
$.ajax({type: 'POST',
dataType: 'json',
url: '/get_search_data',
data: {q: term},
success: function (data) {
cacheNewTerm(term, data);
response(data);
return;
}
});
});
}
If anyone wants a version that supports multiple entries in the text box then please see below:
$(function () {
function split(val) {
return val.split(/,\s*/);
}
function extractLast(term) {
return split(term).pop();
}
var cache = new Object();
var terms = new Array();
function cacheNewTerm(newTerm, results) {
// keep cache of 10 terms
if (terms.push(newTerm) > 10) {
delete cache[terms.shift()];
}
cache[newTerm] = results;
}
$("#searchTextField")
.on("keydown",
function (event) {
if (event.keyCode === $.ui.keyCode.TAB &&
$(this).autocomplete("instance").menu.active) {
event.preventDefault();
}
})
.autocomplete({
minLength: 2,
source: function (request, response) {
var term = extractLast(request.term.toLowerCase());
if (term in cache) {
response(cache[term]);
return;
} else if (terms.length) {
var lastTerm = terms[terms.length - 1];
console.log('LAst Term: ' + lastTerm);
if (term.substring(0, lastTerm.length) === lastTerm) {
var results = new Array();
for (var i = 0; i < cache[lastTerm].length; i++) {
console.log('Total cache[lastTerm[.length] = ' +
cache[lastTerm].length +
'....' +
i +
'-' +
lastTerm[i]);
console.log('Label-' + cache[lastTerm][i]);
var cachedItem = cache[lastTerm][i];
if (cachedItem != null) {
if (cachedItem.toLowerCase().indexOf(term) !== -1) {
results.push(cache[lastTerm][i]);
}
}
}
response(results);
return;
}
}
$.ajax({
url: '#Url.Action("GetSearchData", "Home")',
dataType: "json",
contentType: 'application/json, charset=utf-8',
data: {
term: extractLast(request.term)
},
success: function (data) {
cacheNewTerm(term, data);
response($.map(data,
function (item) {
return {
label: item
};
}));
},
error: function (xhr, status, error) {
alert(error);
}
});
},
search: function () {
var term = extractLast(this.value);
if (term.length < 2) {
return false;
}
},
focus: function () {
return false;
},
select: function (event, ui) {
var terms = split(this.value);
terms.pop();
terms.push(ui.item.value);
terms.push("");
this.value = terms.join(", ");
return false;
}
});

Childbrowser plugin not working in Phonegap

I'm using Backbone, Require and Underscore Bundled with Phonegap or Cordova.
I tried using the childbrowser plugin but it wont work. I followed the instructions here.
http://blog.digitalbackcountry.com/2012/03/installing-the-childbrowser-plugin-for-ios-with-phonegapcordova-1-5/
define([
'jquery',
'backbone',
'underscore',
'base64',
'mobile',
'const',
'child',
'text!template/login/login.tpl.html'
],function($, Backbone, _, base64, Mobile, Const, ChildBrowser, template){
var EncodeAuth = function(user,pass)
{
var _tok = user + ':' + pass;
var _hash = Base64.encode(_tok);
return "Basic "+ _hash;
}
var LoginView = Backbone.View.extend({
events:{
"click .login-btn" : "Login",
"click .connection-btn" : "OpenSite"
},
initialize: function(){
},
Login: function(){
Const.USERNAME = $("#username").val();
Const.PASSWORD = $("#password").val();
if(!Const.USERNAME || !Const.PASSWORD)
{
navigator.notification.alert("Invalid Username/Password!");
$("input").val("");
}else{
var auth = EncodeAuth(Const.USERNAME,Const.PASSWORD);
var sendAuthorization = function (xhr) {
xhr.setRequestHeader('Authorization', auth)
};
this.model.save(this.model, {
beforeSend : sendAuthorization,
success: function(model,result){
if(result.ErrorMessage === null)
{
alert(JSON.stringify(result.Message));
$("input").val("");
}
else
{
alert(JSON.stringify(result.ErrorMessage));
$("input").val("");
}
},
error: function(model,result){
alert("Remote server returned an error. Not Found");
$("input").val("");
}
});
}
},
OpenSite: function(){
window.plugins.ChildBrowser.showWebPage("http://www.google.com");
}
});
return LoginView;
});
Any ideas?