I'm working on trying to write an asynchronous test with mocha using the done(); call. This is my code so far.
it('should have data.', function () {
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
done();
})
.fail(function (err) {
err.should.not.exist;
done();
})
})
The result however is that the code just executes without waiting for the then or fail to actually return with a result. Does done(); need to be at a different place within the code?
Also posted the whole repo right here: https://github.com/Adron/node_testing_testing
if you want an async test you need to handle the done parameter
it('should have data.', function (done) {
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
done();
})
.fail(function (err) {
err.should.not.exist;
done();
})
})
also if you are using Q as your promise library you might want to complete your chain like so.
it('should have data.', function (done) {
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
})
.fail(function (err) {
err.should.not.exist;
})
.done(done,done)
})
I think you mean to actually call the done() callback.
it('should have data.', function () {
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
done();
})
.fail(function (err) {
err.should.not.exist;
done();
})
})
Related
I am trying to implement a decorator on the fs.readFile function. Instead of the regular error and data params, this version should take two callbacks as arguments (both after the file name) – one to be called on success and one to be called on failure. Both callbacks only have one parameter (the data read from the file or an error object). The actual implementation simply calls fs.readFile.
I can't figure out why this isn't working, and what I'm doing wrong. Please help me debug this. Thank you.
function myReadFile(fileName, successFn, errorFn) {
fs.readFile(fileName,'utf8', function read(errorFn, successFn) {
if (errorFn) {
errorFn();
}
else {
successFn();
}
});
}
fs.readFile callback does not return an errorFn or successFn.
Example from Node.js fs docs:
fs.readFile('/etc/passwd', (err, data) => {
if (err) throw err;
console.log(data);
});
Instead you can pass the err object into your errorFn and same for success with data.
function myReadFile(fileName, successFn, errorFn) {
fs.readFile(fileName,'utf8', function read(err, data) {
if (err) return errorFn(err);
return successFn(data);
});
}
Alternatively you could turn it into a Promise like so:
function myReadFile(fileName) {
return new Promise((resolve, reject) => {
fs.readFile(fileName,'utf8', function read(err, data) {
if (err) return reject(err);
return resolve(data);
});
});
}
//usage:
myReadFile('/some/file')
.then(data => {
//data here
})
.catch(err => {
//error here
});
I have the following method, simplified:
var component = require('../../component.js')
exports.bigMethod = function (req, res) {
var connection = new sql.Connection(process.config.sql, function (err) {
new sql.Request(connection)
.input('input', sql.VarChar, 'value')
.execute('dbo.sp1')
.then(function (data) {
if(data[0].length === 0) {
res.status(500).send({ message: 'Some Error' });
}
// set some local variable I'll use later: localVar
new sql.Request(connection)
.input('input1', sql.Int, req.query.input1)
.input('input2', sql.Int, req.query.input2)
.input('input3', sql.DateTime2, req.query.input3)
.input('input4', sql.DateTime2, req.query.input4)
.execute('dbo.sp2')
.then(function (recordset) {
json2csv( { data: recordset[0] }, function(err, data) {
if (err) {
res.status(500).json(err);
}
fs.writeFile(localVar.path, data, function (err) {
if (err) {
res.status(500).json(err);
}
try {
var email = new component.Email();
email.set_callback(function (error) {
if (error) {
res.status(500).send({ message: 'Another error' });
}
res.jsonp([]);
});
email.send(
localVar,
{
filename: localVar.name,
path: localVar.path
}
);
} catch (e) {
res.status(500).send({ message: 'Another Error' });
}
})
});
})
.catch(function (err) {
res.status(500).send({ message: 'Another Error' });
});
})
.catch(function (err) {
res.status(500).send({ message: 'Another Error' });
});
});
};
As you can see, it's a long method, which is an anti-pattern. Furthermore, the call to sp2 is actually a duplication: there's another component that makes a similar call, only returning the result of json2csv directly.
Now, I'm not so sure how to go about dividing this method to fully take advantage of reusability. Should I encapsulate the database calls in functions returning Promises? Should I use some currying?
Thanks.
Dividing your code into different functions should be your top priority — that function alone is handling way too many things which could be easily divided.
You can make your code function much cleaner by dividing through callbacks and promises, as you already suspected.
Callback example:
new sql.Connection(..., handleSQLConnection);
handleSQLConnection(error) { ... }
Promise example:
doSomething
.then((a) => doOtherStuff(a))
.then((b) => doSmthElse(b));
doOtherStuff(a) { ... }
doSmthElse(b) { ...}
Nonetheless, refactoring is very opinionated. But you should try to avoid God functions, and instead write functions that do one thing but they do it well.
I have two consecutive asynchronous operations, the problem is that when the first is an error, the second operation is still being executed:
File.convertToBase64(file.files[0])
.then(function (code) {
let params = {
csv: code
};
return new Api().createFromCSV(params);
})
.catch(function (error) {
dispatch(showError(error));
return false; // doesn't work
})
.then(function (response) {
dispatch(showSuccess('File was imported!'));
})
.catch(function (error) {
dispatch(showError(error));
});
So, if the first catch gets called, I don't want to execute the .then after it, I want the chain execution stopped. How can I deal with this?
How to get asserts in mocha before blocks to work? If I am not suppose to do this let me know. Currently, using promises, if I get an error using an catch block, I'll add an assert to fail the before block. WHat I want is it to fail the describe block, but instead I get two possible outcomes. 1. My test suite completely crashes, 2. I have to wait for each timeout to hit for each test because the before block failed.
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
assert(!error);
done();
});
});
I even tried this, thinking, maybe the done was never called.
before(function (done) {
promise()
.then(function () {
//no done here
})
.catch(function (error) {
assert(!error);
});
.finally(function () {
done();
});
});
So far to avoid crashing and waiting, and to make it work, I have done this:
var beforeError;
before(function (done) {
promise()
.then(function () {
done();
})
.catch(function (error) {
beforeError = error;
done();
});
});
it('test something', function () {
assert(beforeError, 'Before block failed with error.');
});
I am really curious if there is a better way to go about this so that if my before/beforeEach/after/afterEach blocks fail, it doesn't cause me to wait ages or my suite to crash! Thanks S/O community! :)
I can't speak to your use of the done callback, but mocha 3.0 supports promises in before hooks now. Were I to write this, I would let the returned promise throw its own error, which will fail the before hook without breaking the suite.
before(function () {
return promise(<async behavior here>);
});
I am trying to write a test case for one of my REST Apis using mocha.
My Rest api looks like this:
server.route({
method : "DELETE",
path : "/local/{id}",
handler: function (request, reply) {
var id = request.params.id;
return getId(id)
.then(function (result) {
return testFunction(result, id, reply);
})
.catch (function (err) {
reply(400).err;
})
}
function testFunction(result, id, reply) {
return update(id, result)
.then(function (resp) {
reply(resp);
stopSomething(id)
.then(function () {
//do some work
return Bluebird.resolve(data);
})
.catch(function (error) {
//handle error & just log..user does not need to know
//stopSomething is a promise chain which runs in background
});
})
.catch(function (err) {
//handle error and reply to user
});
}
});
To test this I wrote the following test case:
describe("with an valid id", function () {
var stopSomethingStub;
var result
before(function () {
stopSomethingStub = Sinon.stub(stopSomethinbObject, "stopSomething", function () {
return Bluebird.resolve();
});
return new Request("DELETE", "/local/id123").inject(server)
.then(function (data) {
result = data;
});
});
after(function () {
//do clean up of stubs
});
it("deletes id", function () {
expect(result.statusCode).to.equal(200);
expect(stopSomethingStub.called).to.be.true;
//Few more checks
});
}
Right now, the "it" block executes immediately after receiving the 200 Ok response for the DELETE Request. However I would like it to finish the entire promise chain before checking the assertion. stopSOmethingStub.called is shown as false if I keep it as the first expect block. However if I keep it as the last assertion it works. I think this is some timing issue.