Does anyone know a way I can automatically rerun a Nightwatch test a set number of times?
I have the following code:
module.exports = {
'Log into system - create order': function (client) {
client
.url('XXXX')
.waitForElementVisible('body', 1000)
.assert.title('Reach - Log in')
.assert.visible('#UserName')
.setValue('#UserName', 'XXXX')
.assert.visible('#Password')
.setValue('#Password', 'XXXX')
.assert.visible('input[value="Login"]')
.click('input[value="Login"]')
.waitForElementVisible('img.test', 1000)
.assert.visible('li[title="XXXX"] a[tabindex="5"]')
.click('li[title="Sales"]')
.assert.cssClassPresent('li[title="XXXX"]', 'active')
.click('a[href="/Quotes/Add"]')
.waitForElementVisible('#s2id_CustomerId_Remote', 1000)
.click('#s2id_CustomerId_Remote')
.assert.visible('#s2id_autogen2_search')
.setValue('#s2id_autogen2_search', 'bik')
.waitForElementVisible('.select2-highlighted', 1000)
.click('.select2-highlighted')
.waitForElementVisible('#customerNotes', 1000)
.click('#s2id_ProductId_Remote')
.assert.visible('#s2id_autogen3_search')
.setValue('#s2id_autogen3_search', '123XP')
.pause(5000)
.assert.visible('.select2-highlighted')
.click('.select2-highlighted')
.pause(5000)
.assert.visible('.ui-sortable > tr')
.setValue('#Quote_PONumber', 'abc123')
.click('input[value="Create Order"]')
.waitForElementVisible('.ac-order-number', 1000)
.assert.visible('a[data-value="abc123"]')
.pause(5000)
.end()
}
}
rather than .end() the test I'd like to .rerun() the test say 30 times. I can't see an option to do this anywhere in the docs.
Many thanks in advance.
You can wrap your commands in a client.perform() and a for loop
client.perform(function(){
for (i = 0; i < 29; i++) {
client
.url('XXXX')
.
.
.
.end();
}
})
What you need is a little of async iteration logic and client.perform() function :
module.exports = {
'Log into system - create order': function (client) {
var currentIteration = 0,
iterationCount = 30;
function runTest() {
client
.url('XXXX')
// ... YOUR CODE HERE, WITHOUT .end()
.perform(function() {
if (++currentIteration < iterationCount) {
return runTest();
}
client.end(); // After passing 30 iterations end the session
});
}
runTest();
}
};
If you want to repeat he test with different inputs ? then you can do something like this
module.exports = {
"Login Fail Cases": function(browser) {
let dataSet = [
{ username: "madhus", pass: "madhus" },
{ username: "admin", pass: "admin" }
];
//will run for 2 times as length of dataset is 2
dataSet.forEach(function(data) {
browser
.url("https://localhost:3000/")
// you tests here
}, this);
// note: end the test outside the loop once all tests are executed
browser.end();
}
};
Related
I'm still currently learning on using React Native.
What I'm trying to do is update the limit value to 1 so it would break the while loop, but I am not sure on how to execute it since I can't update the value from inside the .then() in Axios POST call.
Glad if anyone would point out any method to handle this. Thank you for your help.
var limit = 0;
while (limit == 0) {
running = running + 20;
console.log("restart");
postDataCalories = {
"query": `${running} minutes run and ${walking} minutes walking`,
"gender":"male",
// "nf_calories": 363.62,
"weight_kg":63.5,
"height_cm":167.64,
"age":30
};
console.log(`${running} minutes run and ${walking} minutes walking`);
axios.post('https://trackapi.nutritionix.com/v2/natural/exercise', postDataCalories, axiosConfig2)
.then((res3) => {
console.log("exercise RESPONSE RECEIVED: ", res3);
let caloriesFood = res2.data.foods[0].nf_calories;
let caloriesExercise = res3.data.exercises[0].nf_calories;
let caloriesDifferences = caloriesFood - caloriesExercise;
console.log("hi " + caloriesDifferences);
if (caloriesDifferences < 50){
console.log('done');
limit = 1;
} else {
console.log('nope');
}
})
}
That's right in your case you cannot break the while loop inside the then-function because that function is called at a different moment in time (they call it asynchronous).
There are two things you can do. If you have access to await/async in your environment you could rewrite it to:
async someFunction() {
var limit = 0;
var running = 1; // arbitrarily start at 1.
while (limit == 0) {
running = running + 20;
console.log("restart running " + running);
postDataCalories = {
"query": `${running} minutes run and ${walking} minutes walking`,
"gender":"male",
// "nf_calories": 363.62,
"weight_kg":63.5,
"height_cm":167.64,
"age":30
};
console.log(`${running} minutes run and ${walking} minutes walking`);
var res3 = await axios.post('https://trackapi.nutritionix.com/v2/natural/exercise', postDataCalories, axiosConfig2)
console.log("exercise RESPONSE RECEIVED: ", res3);
let caloriesFood = res2.data.foods[0].nf_calories;
let caloriesExercise = res3.data.exercises[0].nf_calories;
let caloriesDifferences = caloriesFood - caloriesExercise;
console.log("hi " + caloriesDifferences);
if (caloriesDifferences < 50){
console.log('done');
limit = 1;
// you may also do:
break;
} else {
console.log('nope');
}
}
}
}
For usual web conditions it requires either a modern browser (Firefox/Chrome) (or when you have babel / regenerator-runtime might do the trick, maybe your setup is already capable of transpiling this/running this.)
If you dont have access to async/await then you need to apply recursion (to work around the synchronicity). Normally you can perform the tasks sequentially (in a row, step by step, using a while loop), now you would write something like:
function runTheLoop(running, walking) {
postDataCalories = {
"query": `${running} minutes run and ${walking} minutes walking`,
"gender":"male",
// "nf_calories": 363.62,
"weight_kg":63.5,
"height_cm":167.64,
"age":30
};
console.log(`${running} minutes run and ${walking} minutes walking`);
axios.post('https://trackapi.nutritionix.com/v2/natural/exercise', postDataCalories, axiosConfig2)
.then((res3) => {
console.log("exercise RESPONSE RECEIVED: ", res3);
let caloriesFood = res2.data.foods[0].nf_calories;
let caloriesExercise = res3.data.exercises[0].nf_calories;
let caloriesDifferences = caloriesFood - caloriesExercise;
console.log("hi " + caloriesDifferences);
if (caloriesDifferences < 50){
console.log('done');
// limit = 1;
return;
} else {
console.log('nope');
// This is the recursive variant of "running the loop again"
return runTheLoop(running + 20, walking + 20);
}
})
}
}
// Somewhere:
console.log("restart");
// one minute of walking and one minute of running.
runTheLoop(1, 1);
Note: I've used your your code to make the examples relevant in to your situation, I could not test it out myself so it may not work directly if you copy and paste this.
I'm trying concurrently run my tests except for tests that include login.
I've tried to separate tests into two groups (with login and without login). These two groups run in parallel. Tests without login are running concurrently with each other, but tests with login run one after each other. The problem is that runner only runs tests without logins twice. I saw .serial feature discussion in https://github.com/DevExpress/testcafe/issues/116 and I think it would help a lot in this situation.
const createTestCafe = require('testcafe');
const config = require('./config');
const testArrayBuilder = require('./Tests/helpers/testArrayBuilder');
let testSteps = require('./Tests/helpers/testSteps');
let testcafe;
const store = process['argv'][2],
name = process['argv'][3],
env = process['argv'][4];
const testsFile = require(`./Tests/${store}/tests.json`);
const output = 'logs/test-results-' + store + '-' + env + '-' + name + '.json';
createTestCafe('localhost', 0)
.then(tc => {
testcafe = tc;
const tests = getTests();
const runner = testcafe.createRunner();
if (name !== 'all') {
runner.filter(testName => {
return testName === name;
});
}
runner.reporter(['spec', {
name: 'json-custom',
output: output
}]);
return Promise.all(tests.map(obj => {
if(obj.login === true) {
//Don't change number value for this one,
//because login tests won't run properly.
return runTests(runner, obj.tests, 1);
} else{
return runTests(runner, obj.tests, 1);
}
}));
})
.then(() => {
testSteps.mergeWithReporter(output);
testcafe.close();
});
const runTests = (runner, tests, windows) => {
return runner
.src(tests)
.browsers(config.browsers)
.concurrency(windows)
.screenshots('logs/screenshots/', true)
.run({
skipJsErrors: true,
quarantineMode: true,
selectorTimeout: 20000,
assertionTimeout: 20000,
pageLoadTimeout: 20000,
speed: 0.5,
stopOnFirstFail: false
});
}
const getTests = () => {
const testsWithoutLogin = testArrayBuilder(testsFile[env], false);
switch (store) {
case 'shop1':
const testsWithLogin = testArrayBuilder(testsFile[env], true);
return [{login: true ,tests: testsWithLogin}, {login: false, tests: testsWithoutLogin}];
case 'shop2':
return [{login: false ,tests: testsWithoutLogin}];
}
}
Note that if I write createRunner() part in runTests(), reporter is overwritten.
I think the problem here is that you use the same runner for parallel test execution in the Promise.race function. I would recommend you use different runners for both your test sets.
I am able to run tests locally on my remote selenium server and they run just fine.
When I go to run them on my Jenkins box on the same remote selenium server in Jenkins I am getting No Specs found, and in the output of my selenium server I am seeing the following:
21:33:41.256 INFO - Executing: [execute async script: try { return (function (attempts, ng12Hybrid, asyncCallback) {
var callback = function(args) {
setTimeout(function() {
asyncCallback(args);
}, 0);
};
var check = function(n) {
try {
if (!ng12Hybrid && window.getAllAngularTestabilities) {
callback({ver: 2});
} else if (window.angular && window.angular.resumeBootstrap) {
callback({ver: 1});
} else if (n < 1) {
if (window.angular) {
callback({message: 'angular never provided resumeBootstrap'});
} else {
callback({message: 'retries looking for angular exceeded'});
}
} else {
window.setTimeout(function() {check(n - 1);}, 1000);
}
} catch (e) {
callback({message: e});
}
};
check(attempts);
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10, false]])
21:33:41.273 INFO - Done: [execute async script: try { return (function (attempts, ng12Hybrid, asyncCallback) {
var callback = function(args) {
setTimeout(function() {
asyncCallback(args);
}, 0);
};
var check = function(n) {
try {
if (!ng12Hybrid && window.getAllAngularTestabilities) {
callback({ver: 2});
} else if (window.angular && window.angular.resumeBootstrap) {
callback({ver: 1});
} else if (n < 1) {
if (window.angular) {
callback({message: 'angular never provided resumeBootstrap'});
} else {
callback({message: 'retries looking for angular exceeded'});
}
} else {
window.setTimeout(function() {check(n - 1);}, 1000);
}
} catch (e) {
callback({message: e});
}
};
check(attempts);
}).apply(this, arguments); }
catch(e) { throw (e instanceof Error) ? e : new Error(e); }, [10, false]]
21:33:41.288 INFO - Executing: [execute script: return (function (trackOutstandingTimeouts) {
var ngMod = angular.module('protractorBaseModule_', []).config([
'$compileProvider',
function($compileProvider) {
if ($compileProvider.debugInfoEnabled) {
$compileProvider.debugInfoEnabled(true);
}
}
]);
if (trackOutstandingTimeouts) {
ngMod.config([
'$provide',
function ($provide) {
$provide.decorator('$timeout', [
'$delegate',
function ($delegate) {
var $timeout = $delegate;
var taskId = 0;
if (!window['NG_PENDING_TIMEOUTS']) {
window['NG_PENDING_TIMEOUTS'] = {};
}
var extendedTimeout= function() {
var args = Array.prototype.slice.call(arguments);
if (typeof(args[0]) !== 'function') {
return $timeout.apply(null, args);
}
taskId++;
var fn = args[0];
window['NG_PENDING_TIMEOUTS'][taskId] =
fn.toString();
var wrappedFn = (function(taskId_) {
return function() {
delete window['NG_PENDING_TIMEOUTS'][taskId_];
return fn.apply(null, arguments);
};
})(taskId);
args[0] = wrappedFn;
var promise = $timeout.apply(null, args);
promise.ptorTaskId_ = taskId;
return promise;
};
extendedTimeout.cancel = function() {
var taskId_ = arguments[0] && arguments[0].ptorTaskId_;
if (taskId_) {
delete window['NG_PENDING_TIMEOUTS'][taskId_];
}
return $timeout.cancel.apply($timeout, arguments);
};
return extendedTimeout;
}
]);
}
]);
}
}).apply(null, arguments);, [true]])
21:33:41.312 INFO - Done: [execute script: return (function (trackOutstandingTimeouts) {
var ngMod = angular.module('protractorBaseModule_', []).config([
'$compileProvider',
function($compileProvider) {
if ($compileProvider.debugInfoEnabled) {
$compileProvider.debugInfoEnabled(true);
}
}
]);
if (trackOutstandingTimeouts) {
ngMod.config([
'$provide',
function ($provide) {
$provide.decorator('$timeout', [
'$delegate',
function ($delegate) {
var $timeout = $delegate;
var taskId = 0;
if (!window['NG_PENDING_TIMEOUTS']) {
window['NG_PENDING_TIMEOUTS'] = {};
}
var extendedTimeout= function() {
var args = Array.prototype.slice.call(arguments);
if (typeof(args[0]) !== 'function') {
return $timeout.apply(null, args);
}
taskId++;
var fn = args[0];
window['NG_PENDING_TIMEOUTS'][taskId] =
fn.toString();
var wrappedFn = (function(taskId_) {
return function() {
delete window['NG_PENDING_TIMEOUTS'][taskId_];
return fn.apply(null, arguments);
};
})(taskId);
args[0] = wrappedFn;
var promise = $timeout.apply(null, args);
promise.ptorTaskId_ = taskId;
return promise;
};
extendedTimeout.cancel = function() {
var taskId_ = arguments[0] && arguments[0].ptorTaskId_;
if (taskId_) {
delete window['NG_PENDING_TIMEOUTS'][taskId_];
}
return $timeout.cancel.apply($timeout, arguments);
};
return extendedTimeout;
}
]);
}
]);
}
}).apply(null, arguments);, [true]]
Like I said, these run just fine locally, so I am not sure what is going on with my Jenkins machine.
Here is my protractor config file:
// Configuration constants
var downloadsFolder = 'test/downloads/',
today = ("0" + (new Date()).getDate()).slice(-2),
month = ("0" + ((new Date()).getMonth() + 1)).slice(-2),
baseUrl = 'BASE URL GOES HERE';
// Test report setup w/ screenshot
var HtmlScreenshotReporter = require('protractor-jasmine2-screenshot-reporter');
var reporter = new HtmlScreenshotReporter({
dest: 'test/report',
filename: 'e2e-report.html'
});
// Protractor config
exports.config = {
suites: {
explore: '.protractor/src/app/exploration/tests/exploration.scenario.js',
login: '.protractor/src/auth-app/login/tests/login.scenario.js',
stories: '.protractor/src/app/story/tests/story.scenario.js',
cohorts: '.protractor/src/app/cohort/tests/cohort.scenario.js',
visualize: '.protractor/src/app/visualize/tests/visualize.scenario.js'
},
baseUrl: 'BASE URL GOES HERE',
directConnect: false,
// Override default 11s timeout for long requests such as visualize's "Recommended Visualizations"
// See https://github.com/angular/protractor/blob/master/docs/timeouts.md
allScriptsTimeout: 25 * 1000,
jasmineNodeOpts: {
defaultTimeoutInterval: 90 * 1000
},
multiCapabilities: [
{
browserName: 'chrome',
seleniumAddress: "http://SELENIUM SERVER URL HERE:4444/wd/hub",
platform: 'ANY',
version: 'ANY',
chromeOptions: {
args: ['--no-sandbox', '--test-type=browser', '--lang=en', '--start-maximized'],
prefs: {
download: {
prompt_for_download: false,
directory_upgrade: true,
default_directory: 'test/downloads'
},
},
}
// shardTestFiles: true,
// maxInstances: 2
}
],
onPrepare: function() {
// Set browser window size
browser.driver.manage().window().maximize();
//Setup screenshots
jasmine.getEnv().addReporter(reporter);
browser.get('BASE URL GOES HERE');
},
// Setup the report before any tests start
beforeLaunch: function() {
return new Promise(function(resolve){
reporter.beforeLaunch(resolve);
});
},
// Close the report after all tests finish
afterLaunch: function(exitCode) {
return new Promise(function(resolve){
reporter.afterLaunch(resolve.bind(this, exitCode));
});
},
params: {
baseUrl: baseUrl,
downloadsFolder: 'test/downloads',
cohort: {
listView: baseUrl + 'cohorts',
newView: baseUrl + 'cohorts/new'
},
story: {
listView: baseUrl + 'stories',
newView: baseUrl + 'story/new',
displayView: baseUrl + 'story'
},
visualize: {
listView: baseUrl + 'visualize',
newView: baseUrl + 'visualize/new'
},
explore: {
listView: baseUrl + 'explorations',
newView: baseUrl + 'explorations/new',
excelFilename: downloadsFolder + `DataExport_2016-${month}-${today}.xlsx`,
csvFilename: downloadsFolder + `DataExport_2016-${month}-${today}.csv`,
maxDownloadTime: 10 * 1000
}
}
};
This boiled down to a permissions issue. Once I added my jenkins user to sudo I was able to do a make command on the project which built all of the necessary files and which also converted my typescript tests over to Javascript and allowed them to run.
After fixing alot of erros in the testing, now Karma output is this:
PhantomJS 1.9.8 (Windows 8 0.0.0) Controller: MainCtrl should attach a list of t hings to the scope FAILED
Error: Unexpected request: GET /api/marcas
No more request expected at ....
api/marcas is an endpoint i've created. code for MainCtrl:
'use strict';
angular.module('app')
.controller('MainCtrl', function ($scope, $http, $log, socket, $location, $rootScope) {
window.scope = $scope;
window.rootscope = $rootScope
$scope.awesomeThings = [];
$scope.things = ["1", "2", "3"];
$http.get('/api/things').success(function(awesomeThings) {
$scope.awesomeThings = awesomeThings;
socket.syncUpdates('thing', $scope.awesomeThings);
});
$scope.addThing = function() {
if($scope.newThing === '') {
return;
}
$http.post('/api/things', { name: $scope.newThing });
$scope.newThing = '';
};
$scope.deleteThing = function(thing) {
$http.delete('/api/things/' + thing._id);
};
$scope.$on('$destroy', function () {
socket.unsyncUpdates('thing');
});
$http.get('/api/marcas').success(function(marcas) {
$scope.marcas = marcas;
socket.syncUpdates('marcas', $scope.response);
$scope.marcasArr = [];
$scope.response.forEach(function(value) {
$scope.marcas.push(value.name);
});
$scope.marcaSel = function() {
for (i = 0; i < $scope.response.length; i++) {
if ($scope.selectedMarca == $scope.response[i].name) {
$scope.modelos = $scope.response[i].modelos;
};
};
};
});
until you didn't posted your test-code, I guess that your test doesn't includes the following code:
beforeEach(inject(function () {
httpBackend.expectGET('/api/marcas').respond(function(){
return {/*some status code*/, {/*some data*/}, {/*any headers*/}};
});
}));
if the karma-runner tries to execute your test-code, there are to get-requests to the $http-service, $http.get('/api/marcas') and $http.get('/api/things'). if one of these backend calls is not expected, karma cannot run the testcode successfully.
if you don't want to do special stuff for each but only return a default with success code for both calls, you can write so:
beforeEach(inject(function () {
httpBackend.expectGET(/api/i).respond(function(){
return {/*some status code*/, {/*some data*/}, {/*any headers*/}};
});
}));
I am running a batch job and I would like them to be run serially for each query result
The problem is that it seems that query.each executes everything in parrallel
How can I change my code to have everything execute serially?
Parse.Cloud.job("fetchMenus", function(request, status) {
var counter = 0;
// Query for all users
var LocationSP = Parse.Object.extend("Location");
var query = new Parse.Query(LocationSP);
query.doesNotExist("menu");
query.equalTo("city_lc","new york");
// query.limit(10);
var p = Parse.Promise.as("");
query.each(function(location) {
p = p.then(function(){
if (counter % 100 === 0) {
// Set the job's progress status
status.message(counter + " users processed.");
}
// console.log(location);
// console.log(location.get("location_id"));
Parse.Cloud.run('getMenu2', {alias: location.get("location_id") }, {
success: function(result) {
// result is 'Hello world!'
counter += 1;
return Parse.Promise.as("1");
},
error: function(error) {
return Parse.Promise.as("1");
}
});
})
return p;
}).then(function() {
// Set the job's success status
status.success("Migration completed successfully.");
}, function(error) {
// Set the job's error status
status.error("Uh oh, something went wrong." + error);
});
});
Both query.each and Parse.Cloud.run return a promise, so you can simply write as following:
Parse.Cloud.job("fetchMenus", function(request, status) {
var LocationSP, counter, query;
counter = 0;
LocationSP = Parse.Object.extend("Location");
query = new Parse.Query(LocationSP);
query.doesNotExist("menu");
query.equalTo("city_lc", "new york");
return query.each(function(location) {
if (counter % 100 === 0) {
status.message(counter + " users processed.");
}
return Parse.Cloud.run('getMenu2', {
alias: location.get("location_id")
}).then(function(result) {
counter += 1;
return Parse.Promise.as("1");
}, function(error) {
return Parse.Promise.as("1");
});
}).then(function() {
return status.success("Migration completed successfully.");
}, function(error) {
return status.error("Uh oh, something went wrong." + error);
});
});