Make sure promise resolved inside transformFunction - node.js

I am studying through2 and sequelize.
My codes:
return Doc.createReadStream({
where: { /*...*/ },
include: [
{
/*...*/
},
],
})
.pipe(through({ objectMode: true }, (doc, enc, cb) => {
Comment.findOne(null, { where: { onId: doc.id } }).then((com) => { /* sequelize: findOne*/
com.destroy(); /* sequelize instance destroy: http://docs.sequelizejs.com/manual/tutorial/instances.html#destroying-deleting-persistent-instances */
cb();
});
}))
.on('finish', () => {
console.log('FINISHED');
})
.on('error', err => console.log('ERR', err));
I am trying to express my question clearly. Doc and Comment are sequelize Models. I want to use stream to read Doc instances from database one by one and delete comments on each Doc instance. Comment.findOne and com.destroy() will both return promises. I want to the promises resolved for each doc and then call cb(). But my above codes cannot work, before com be destroyed, the codes already finish running.
How to fix it? Thanks
I wrap the above piece of codes in mocha test, like
it('should be found by readstream', function _testStream(){
/* wrap the first piece of codes here*/
});
But before stream finished reading, the test exist.

You can wait for another promise by returning the promise and using another .then.
You may need to check for the com result being null as well, before running .destroy().
.pipe(through({ objectMode: true }, (doc, enc, cb) => {
Comment.findOne(null, { where: { onId: doc.id } })
.then(com => com.destroy())
.then(()=> cb())
.catch(cb)
}))
Then when running the test in mocha, you need to wait for the asynchronous stream by adding done to the test function signature and calling done() on completion or error.
it('should be found by readstream', function _testStream(done){
...
.on('finish', () => done())
.on('error', done)
})

Related

Mocha does not seem wait for promise chain to complete before running test

I am using Mocha to test data base interactions in my code (so I cannot mock the database).
For the tests to work I want to clean up my database before each test. According to my research I should be using Mocha's ability to handle promises being returned by the before function.
Here is how I am trying to achieve this:
const Orm = require('../db');
describe('Loading Xml Files to Database should work', () => {
before(() => {
return Orm.models.File.destroy({force: true, truncate: true, cascade: true});
});
it('run test', () => {
loadXmlFileToDatabase(....); // this loads data from a
// file into the table "files"
Orm.Orm.query("SELECT * FROM files")
.then(function (result){
console.log(result);
})
.catch(function(error){
console.log(error);
});
});
});
I am, however getting zero rows back from my Query at the end of the code. If I omit the before() function everything wrks, so my conclusion is, that for some reason Mocha is not waiting for it to complete.
How do I make sure, the before() function completes, before my test is run?
Mocha expects a promise to be returned by a function for it to wait.
Either explicitly return a promise from plain functions or use async functions that await
describe('Loading Xml Files to Database should work', function(){
before(async function(){
await Orm.models.File.destroy({force: true, truncate: true, cascade: true});
});
it('run test', async function(){
await loadXmlFileToDatabase(....); // this loads data from a
// file into the table "files"
const result = await Orm.Orm.query("SELECT * FROM files");
expect(result).to.eql({})
})
});

How to do test after connection with mongoose to atlas

I want to test create user, so after connection to the DB I want to delete all the users that I tested and after it, I want to create new for the test.(Mocha)
test_helper.js
mongoose.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true });
mongoose.connection
.once('open', () => {
console.log("connected")
})
.on('error', (error) => {
console.warn('Warning', error)
});
beforeEach((done) => {
mongoose.connection.collections.users.drop(() => {
done();
}
)
})
create_test.js
describe('Creating', () => {
it('saves a user', () => {
const testUser = new User({ name: 'Test' });
testUser.save();
});
});
I am getting the next error
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves.
what do I miss?
Some topics before my answer:
Asynchronous coding:
If you don't know/ are sure how it works, I recommend you to stop and learn about it: callback,Promises, async / await.
Testing:
Basically the flow is : create some scenario and assert some case, for example the attached code. I created a user and tested if it really work.
Testing Asynchronous code: after you read about callback function you can understand that done() is a callback function that permit finish the current async. function and pass to the next async. function.
testUser.save() returns a Promise and you aren't handling it.
...
testUser.save().then(()=>{
assert(testUser.isNew === false)
done();
}
...
It should work, but if you want to test some scenarios one after other you should handle it.
describe('Creating', () => {
it('some test', (done) => {
// some logic
done()
}
it('another test', (done) => {
// some logic
done()
}
});
});

Nightmare then() invokes immediately after evaluate()

Consider the following code snippet:
nightmare
.evaluate(function (resolve){
setTimeout(function () {
resolve(null, 1234);
}, 1500)
})
.then(function (result) {
console.log('SUCCESS', result);
})
.catch(function (e) {
console.log('ERROR', e);
});
Assuming that nightmare instance has been initialized before, I have also used methods such as goto() and inject() (that part of code is very huge, but I can try cleaning it to present over there if necessary). But the result I get finally - is unlikely SUCCESS null instead of SUCCESS 1234.
I was experimenting with that and have understood that if call .wait(15000) before .evaluate() in that chain (or setup a breakpoint after .goto() and before the .evaluate() and wait some time when it's fired), the code works as it's exactly expected to.
What is wrong with that code?
Consider the following answer,
nightmare
.evaluate(function (){
return new Promise((resolve, reject)=>{
setTimeout(function () {
resolve(1234);
}, 1500)
})
})
.then(function (result) {
console.log('SUCCESS', result);
})
.catch(function (e) {
console.log('ERROR', e);
});
What does it do? It returns a promise. So the code will wait until it's resolved.
Also, you must resolve 1234 if you want to get 1234, and not a null.
Learn more about promises,
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://ponyfoo.com/articles/es6-promises-in-depth

Mongoose: write own methods with promise

I want to write some instance / static methods for a model, which uses the mongoose's API and do something before and after using the mongoose's API.
For example, I write my own Article.createArticle method, it checks the data before Article.create, and return article.toObject() after creation.
this is how I want my createArticle works:
Article.createArticle({someKeys: 'SomeData', ...})
.then(obj => {
// get plain object here
});
I tried to write something like this:
Article.Schema.static({
createArticle: function(data) {
return new Promise(function(resolve, reject){
checkDataKeys(data);
resolve(mongoose.model('Article').create(data)
.then(article => resolve(article.toObject()));
);
});
},
});
with this createArticle, I only get undefined in then,
I must get something wrong.
Also, in addition to make the createArticle work, is there any way to make the code more elegant?
Thanks.
I myself found a methods that works for me. Though I'm not very understand the mechanism, maybe I'll try to work on it later...
ArticleSchema.static({
createArticle: function(data) {
checkDataKeys(data); // pre works
return mongoose.model('Article').create(data)
.then(obj => {
return obj.toObject(); // afterworks
// here, just get the plain obj from doc
// and *return* it
});
},
});
update: after I searched something about Promise, maybe this could be better.
ArticleSchema.static({
createArticle: function(data) {
checkDataKeys(data); // pre works
return mongoose.model('Article').create(data)
.then(obj => {
return Promise.resolve(obj.toObject());
// Some say that this is totally same as directly return
})
.catch(err => {
return Promise.reject(err);
// if error, this will ensure the err will be caught
// for some async cases
});
},
});

Unable to use .then in express framework

I'm new to Express framework and learning, I'm having a problem using .then. The problem is I have 2 functions and I want the first one to complete before the second to start executing. I'm exporting the modules.
var ubm = require('./userBasic');
There are 2 functions setUserData and showUserId, the showUserId must execute only after setUserData has performed its operation.
var userId = ubm.setUserData(userName,userEmail,userDOB,moment);
userId.then(ubm.showUserId(userId));
Below are the 2 functions:
module.exports = {
setUserData: function (userName,userEmail,userDOB,moment){
//Performing database activities
return userId;
}
showUserId: function (userId){
console.log(userId);
}
}
When i run it says TypeError: Cannot read property 'then' of undefined.
Like I said I'm very new and learning and was unable to figure out the solution. I did some google search and got a brief about promise, but I don't know how to implement here.
Try using promises
module.exports = {
setUserData: function(userName, userEmail, userDOB, moment) {
return new Promise(function(resolve, reject) {
//db stuff
reject(error);
resolve(userId);
});
},
showUserId: function(userId) {
console.log(userId);
};
};
So in your execution you would write
ubm.setUserData(username, usereEmail, userDOB, moment)
.then((data) => {
showUserId(data);
})
.catch((err) => {
console.log(err);
});
A couple of things to note is that in this instance you could just log data without the need for another function like
ubm.setUserData(username, usereEmail, userDOB, moment)
.then((data) => {
console.log(data);
})
.catch((err) => {
console.log(err);
});
Whatever value you pass into resolve() will be returned as well as you pass errors into reject().

Resources