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;
}
Related
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.
I'm learning about MongoDb and the exercise of the module is about a function in MongoDb to return the match in the database with the parameter "Director" that I pass but doesn't pass the test. This is my code:
In movies.js
exports.byDirector = function(db, director, callback) {
// TODO: implement
db.collection('movies').find(
{"director" : director}).sort({title : 1}).toArray(function(error, docs){
if (error){
console.log(error);
process.exit(1);
}
docs.forEach(function(doc){
console.log(JSON.stringify(doc));
});
process.exit(0);
})
callback(null, []);
};
This is the function's test:
it('returns multiple results ordered by title', function(done) {
dbInterface.byDirector(db, 'George Lucas', function(error, docs) {
assert.ifError(error);
assert.ok(Array.isArray(docs));
assert.equal(docs.length, 4);
assert.equal(docs[0].title, 'Attack of the Clones');
assert.equal(docs[1].title, 'Revenge of the Sith');
assert.equal(docs[2].title, 'Star Wars');
assert.equal(docs[3].title, 'The Phantom Menace');
docs.forEach(function(doc) {
delete doc._id;
});
assert.deepEqual(Object.keys(docs[0]), ['title', 'year', 'director']);
++succeeded;
georgeLucasMovies = docs;
done();
});
});
var succeeded = 3;
What's wrong?
Thank you so much for your help.
You are calling the callback function outside the toArray callback function
Try this
exports.byDirector = function(db, director, callback) {
// TODO: implement
db.collection('movies').find(
{"director" : director}).sort({title : 1}).toArray(function(error, docs){
if (error){
callback(err, null);
}
docs.forEach(function(doc){
console.log(JSON.stringify(doc));
});
callback(null, docs);
});
};
I'm still quite new to promises and the like and I need some help with this problem. One of my it blocks does not end before the next one begins ending up in a StaleElementReferenceError a whole specfile later from where the code was supposed to be called.
listView.js (I know it looks weird but I set it up this way for an unrelated reason):
module.exports = function () {
var public = {};
public.checkFilters = function (filters) {
var promises = [];
for (var i = 0; i < filters.length; i++) {
promises[i] = getFilterPromise(filters[i]);
}
return protractor.promise.all(promises);
};
var getFilterPromise = function (filter) {
return public.getHeaderIndex(filter.on).then(function (headerIndex) {
return checkRows(filter.values, headerIndex);
});
};
public.getHeaderIndex = function (text) {
var headers = table.all(by.tagName('th'));
var correctHeaderIndex;
return headers.each(function (header, index) {
header.getText().then(function (actualHeaderText) {
if (actualHeaderText === text) {
correctHeaderIndex = index;
}
})
}).then(function () {
return new Promise(function (resolve, reject) {
if (correctHeaderIndex) {
resolve(correctHeaderIndex);
} else {
reject('Header not found');
}
});
});
};
public.getWorkflowCount = function () {
return workflows.count();
};
var checkRows = function (matchers, headerIndex) {
var mismatch = false;
return workflows.each(function (element, index) {
public.getTextFromCell(index, headerIndex).then(function (actual) {
if (!anyMatch(actual, matchers)) {
mismatch = true;
}
});
}).then(function () {
return new Promise(function (resolve, reject) {
if (mismatch) {
reject('Header not found');
} else {
resolve('all rows matched');
}
});
});
};
var anyMatch = function (actual, matchers) {
var match = false;
for (var j = 0; j < values.length; j++) {
if (text === values[j]) {
match = true;
}
}
return match;
};
public.getTextFromCell = function (row, column) {
return workflows.get(row).all(by.tagName('td')).get(column).getText();
};
return public;
}();
LV_00:
describe('LV_00:', function () {
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
I think you should move the test preparation code into the beforeEach():
describe('LV_00:', function () {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
You may also need to use the done callback function:
describe('LV_00:', function (done) {
beforeEach('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress).then(function () {
done();
});
});
it('statusfilter works', function () {
P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
assuming filter() returns a promise.
Found the solution thanks to alecxe proposing to use done() I used the following after some googling around.
it('statusfilter', function () {
P.listView.filter('status', H.regStatus.S.inProgress);
});
it('statusfilter works', function () {
protractor.promise.controlFlow().execute(function () {
return P.listView.checkFilters([{
on: H.lang.S.status,
values: [H.regStatus.S.inProgress]
}]);
});
});
Found here: Prevent Protractor from finishing before promise has been resolved
I am using Protractor to test my Angular Application.
I am using the modules i created as a pre-condition to test my cases.
When i run my test before the pre-condition met the browser is exiting.
Please check my pre-condition call in my test and suggest any solution to solve this issue.
beforeAll(function (done) {
async.series([
function (callback1) {
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1900000;
setTimeout(function () {
console.log("inside timeout.....");
callback1();
}, 500);
browser.driver.manage().deleteAllCookies();
browser.ignoreSynchronization = false;
},
function (callback2) {
registerNewUser(myCredentials, function (res) {
//browser.waitForAngular();
myCredentials = res;
console.log(JSON.stringify(res));
console.log(res);
expect(res).not.toBeNull();
//browser.waitForAngular();
// browser.sleep(5000)
callback2(res);
//browser.pause(10000);
// browser.sleep(5000)
browser.waitForAngular();
});
}
],
function (err) {
// browser.sleep(5000)
console.log("Inside done");
browser.waitForAngular();
done();
I suggest you to use browser.driver.sleep(500) to befire or after your operations. :)
If I try to drop the database using after (at the end of my tests) it works.
If I try the following:
var db = mongoose.connect('mongodb://localhost/db-test')
describe('Database', function() {
before(function (done) {
db.connection.db.dropDatabase(function(){
done()
})
})
...
it does not drop the DB. what is going on? I would prefer dropping the db before starting testing -- so that after testing I can explore the db.
solved by connect in another define.. not sure if ideal.
describe('Init', function() {
before(function (done) {
mongoose.connect('mongodb://localhost/db-test', function(){
mongoose.connection.db.dropDatabase(function(){
done()
})
})
})
describe('Database', function() {
I implemented it a bit different.
I removed all documents in the "before" hook - found it a lot faster than dropDatabase().
I used Promise.all() to make sure all documents were removed before exiting the hook.
beforeEach(function (done) {
function clearDB() {
var promises = [
Model1.remove().exec(),
Model2.remove().exec(),
Model3.remove().exec()
];
Promise.all(promises)
.then(function () {
done();
})
}
if (mongoose.connection.readyState === 0) {
mongoose.connect(config.dbUrl, function (err) {
if (err) {
throw err;
}
return clearDB();
});
} else {
return clearDB();
}
});