Clean down the index before each text (Mocha, Elastic) - node.js

How do we clear down the index before each test? (at the moment it fails my test, with a timeout)
I have tried
DeleteBy (I have tried the term and q)
http delete
delete the index
I have the following code:
var assert = require("assert"),
elasticsearch = require('elasticsearch'),
request = require('request'),
q = require('q'),
client;
client = new elasticsearch.Client();
describe('people', function(){
beforeEach(function(done){
//is this correct?
//looks like poeple get deleted.
client.deleteByQuery({
index: 'people',
q: '*'
}, function (error, response) {
done();
});
//I have also tried the following:
//this way returns an accept code.
// var deleteOptions = {
// method: 'DELETE',
// uri: 'http://localhost:9200/people/person'
// };
//
// webApi(deleteOptions).then(function(data){
// //{"acknowledged":true}
// console.log(data.body);
// done();
// });
//the following throws an exception
//delete index
// client.indices.delete('people').then(function(del){
// console.log(del);
// client.indices.create('people').then(function(ct){
// console.log(ct);
// done();
// });
// });
});
describe('add a entry into the index', function(){
it('should add Dave as a person to the database', function(done){
//THIS TEST WILL FAIL
//Error: timeout of 2000ms exceeded
//I have tried adding a timeout.
assert.equal(1,1);
});
});
});
var webApi = function(options){
var deferred = q.defer();
var handle = function (error, response, body) {
//console.log(body);
if(error) {
deferred.reject(error);
}
else {
deferred.resolve({response:response, body:body});
}
};
request(options, handle);
return deferred.promise; //NOTE: we now return a promise
};

The test that you marked with THIS TEST WILL FAIL fails with a timeout because you never call done() in it. You've declared the anonymous function you pass to it with a parameter, which tells Mocha that your test is asynchronous (even if the code in it is not asynchronous right now) and thus Mocha waits for done() to be called. You can either call it, or remove the parameter from your function.

Related

Weird behaviour of request-json with bluebird promise

I'm trying to wrap my head around promises, but so far I can't seem to get simple example working. Here it a code to request JSON from the server:
module.exports = function (app, options) {
var promise = require('bluebird');
var request = require('request-json');
var module = {
url: options.url,
httpClient: promise.promisifyAll(request.createClient(options.url))
};
module.getSample = function() {
return this.httpClient.getAsync('sample/')
.then(function(error, response, body) {
console.log(body);
})
.catch(function(e) {
console.log('error');
console.log(e);
});
};
return module;
};
but when I call it like this:
var backendClient = require('./utils/backendClient.js')(app, {
url: 'http://localhost:8080/'
});
backendClient.getSample()
at runtime I get an error saying '[SyntaxError: Unexpected token o]'. Version without promises works fine. What did I miss?
module.getSample = function() {
return this.httpClient.getAsync('sample/')
.then(function(error, response, body) {
// not sure what Promise library you are using, but in the Promise/A+ spec, the function in then only receives a single argument, the resolved value of the Promise
console.log(body);
// this returns equivalent to Promise.resolve(undefined);
// you really want to return something meaningful here
})
.catch(function(e) {
console.log('error');
console.log(e);
// this also returns equivalent to Promise.resolve(undefined);
// to propagate the "error" condition, you want to either throw e, or return Promise.reject(something here);
});
};
This will always return a fullfilled promise with undefined as the value, never a rejected one. Other errors commented above

How to handle callbacks in Node.js?

Let's say I have 3 files.
index.js makes a call to the backend like this
$.post('/test/', data, function(response) {
//handle success here
})
routes.js handles the route like this
app.post('/test/', function(req, res){
item.getItems(function(response){
res.json(response);
});
});
items.js is the model which accesses the database and makes a POST request for each item
function getItems(callback) {
database.query('SELECT * from items', function(result){
result.forEach(function(item){
request.post('/api/', item, function(req, res) {
//finished posting item
});
});
});
//callback here doesnt wait for calls to finish
}
where/when should I call the callback passed to getItems() to handle a success/failure in index.js?
Because your request.post() operations are async, you have to use some method of keeping track of when they are all done and then you can call your callback. There are multiple ways of doing that. I'll outline a few:
Manually Keeping Track of Count of Request Operations
function getItems(callback) {
database.query('SELECT * from items', function(result){
var remaining = result.length;
result.forEach(function(item){
request.post('/api/', item, function(err, res) {
--remaining;
//finished posting item
if (remaining === 0) {
callback();
}
});
});
});
}
The main problem with doing this manually is that propagating error in nested async operations is difficult when you get to actually figuring out how you're going to handle errors. This is much easier in the other methods shown here.
Using Promises
// load Bluebird promise library
var Promise = require('bluebird');
// promisify async operations
Promise.promisifyAll(request);
function queryAsync(query) {
return new Promise(function(resolve, reject) {
// this needs proper error handling from the database query
database.query('SELECT * from items', function(result){
resolve(result);
});
});
}
function getItems(callback) {
return queryAsync('SELECT * from items').then(function(result) {
return Promise.map(result, function(item) {
return request.postAsync('/api/', item);
});
});
}
getItems.then(function(results) {
// success here
}, function(err) {
// error here
})
It seems strange that you're making an API request in your server-side code, unless this is some sort of middle tier code that interacts with the API... but you're interacting with a database, so I'm still confused on why you can't just do a database insert, or have a bulk insert API call?
Anyway, if you must do it the way you're asking, I've done this in the past with a recursive method that trims down the result array... I really don't know if this is a good approach, so I'd like to hear any feedback. Something like this:
function recursiveResult(result, successfulResults, callback) {
var item = result.shift();
// if item is undefined, then we've hit the end of the array, so we'll call the original callback
if (item !== undefined) {
console.log(item, result);
// do the POST in here, and in its callback, call recursiveResult(result, successfulResults, callback);
successfulResults.push(item);
return recursiveResult(result, successfulResults, callback);
}
// make sure callback is defined, otherwise, server will crash
else if (callback) {
return callback(successfulResults);
}
else {
// log error... callback undefined
}
}
function getItems(callback) {
var successfulResults = [];
var result = [1, 2, 3, 4];
recursiveResult(result, successfulResults, callback);
}
console.log('starting');
getItems(function(finalResult) {
console.log('done', finalResult);
});

How can I stub a Promise such that my test can be run synchronously?

I am trying to unit test a module by stubbing one of its dependencies, in this case the UserManager
A simplified version of the module is as follows:
// CodeHandler
module.exports = function(UserManager) {
return {
oAuthCallback: function(req, res) {
var incomingCode = req.query.code;
var clientKey = req.query.key;
UserManager.saveCode(clientKey, incomingCode)
.then(function(){
res.redirect('https://test.tes');
}).catch(function(err){
res.redirect('back');
}
);
}
};
};
I'm stubbing the UserManager's saveCode function which returns a Promise such that it returns a resolved Promise, but when I assert that res.redirect has been called, alas at the time of the assertion res.redirect has not yet been called.
A simplified version of the unit test is:
// test
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var res = {
redirect: function() {}
};
var expectedUrl = 'https://test.tes';
var ch;
beforeEach(function() {
sinon.stub(UserManager, 'saveCode').returns(
new RSVP.Promise(function(resolve, reject){
resolve();
})
);
sinon.stub(res, 'redirect');
ch = CodeHandler(UserManager);
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
});
How can I properly stub the promise such that the method under test behaves synchronously?
I've worked out a solution using sinon-stub-promise.
describe('CodeHandler', function() {
var req = {
query: {
code: 'test-code',
key: 'test-state'
}
};
var ch;
var promise;
var res = {
redirect: function() {}
};
beforeEach(function() {
promise = sinon.stub(UserManager, 'saveCode').returnsPromise();
ch = CodeHandler(UserManager);
sinon.stub(res, 'redirect');
});
afterEach(function() {
UserManager.saveCode.restore();
res.redirect.restore();
});
describe('can save code', function() {
var expectedUrl = 'https://test.tes';
beforeEach(function() {
promise.resolves();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
});
});
describe('can not save code', function() {
var expectedUrl = 'back';
beforeEach(function() {
promise.rejects();
});
it('redirects to the expected URL', function(){
ch.oAuthCallback(req, res);
assert(res.redirect.calledWith(expectedUrl));
})
})
});
This works perfectly.
Well, the easiest thing would be not to stub it to run synchronously at all since that might change execution order and use Mocha's built in promises support (or jasmine-as-promised if using jasmine).
The reason is there can be cases like:
somePromise.then(function(){
doB();
});
doA();
If you cause promises to resolve synchronously the execution order - and thus output of the program changes, making the test worthless.
On the contrary, you can use the test syntax:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () => {
return methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
});
});
You can use the even lighter arrow syntax for single lines which makes the test even less verbose:
describe("the test", () => { // use arrow functions, node has them and they're short
it("does something", () =>
methodThatReturnsPromise().then(x => {
// assert things about x, throws will be rejections here
// which will cause a test failure, so can use `assert`
});
);
});
In RSVP, you can't set the scheduler as far as I know so it's quite impossible to test things synchronously anyway, other libraries like bluebird let you do it at your own risk, but even in libraries that let you do it it's probably not the best idea.

httpinvoke and pouchdb promise stalling

after making an httpinvoke call, I need to load couchDB but the promise is not passing on.
createDB: function() {
var db = new PouchDB('options');
db.info().then(function (info){
if(info.doc_count <= 10000) {
var db = new PouchDB('options');
db.destroy().then(function(info){
httpinvoke('http://localhost:9080/secure/sync.form','GET');
}).then(function (res){
console.log(JSON.stringify(res)); //This never gets called but if I move this then() block to httpinvoke(xxx).then() it does get called
}).catch(function(err){
console.log(JSON.stringify(err));
});
}
});
}
Promises chain by return values. If you want to make anything meaningful with a promise you have to return it. A promise represents a value + time, your httpinvoke call doesn't return is similar to a synchronus function not returning.
createDB: function() {
var db = new PouchDB('options');
db.info().then(function (info){
if(info.doc_count <= 10000) {
var db = new PouchDB('options');
db.destroy().then(function(info){
return httpinvoke('...','GET'); // NOTE THE RETURN
}).then(function (res){
console.log(res); // console already shows JSON
}); // no need to `catch anyway`, errors are errors let's not suppress.
}
});
}
Also note that promise

Using promises with download module

I am using bluebird for promises.
I am trying to promisify the download module.
Here is my implementation:
Promise = require('bluebird'),
download = require('download');
var methodNameToPromisify = ["download"];
function EventEmitterPromisifier(originalMethod) {
// return a function
return function promisified() {
var args = [].slice.call(arguments);
// Needed so that the original method can be called with the correct receiver
var self = this;
// which returns a promise
return new Promise(function(resolve, reject) {
// We call the originalMethod here because if it throws,
// it will reject the returned promise with the thrown error
var emitter = originalMethod.apply(self, args);
emitter
.on("response", function(data) {
resolve(data);
})
.on("data ", function(data) {
resolve(data);
})
.on("error", function(err) {
reject(err);
})
.on("close", function() {
resolve();
});
});
};
};
download = { download: download };
Promise.promisifyAll(download, {
filter: function(name) {
return methodNameToPromisify.indexOf(name) > -1;
},
promisifier: EventEmitterPromisifier
});
Then using it:
return download.downloadAsync(fileURL, copyTo, {});
My problem is that it doesn't download all of the files (I have a list sent to this function), what am I doing wrong?
An emitter does emit multiple data events, one for every chunk it receives. However, a represents only one future value, in your case you want that to be the complete response.
resolve is supposed to be called only once, to fulfill the promise with the passed value, which is then settled. Further calls will have no effect - and that's why you get only the first parts of your list.
Instead, you will need to accumulate all the data, and when the stream ends you can fulfill the promise with all of it.
var Promise = require('bluebird'),
download = require('download'),
Buffer = require('buffer'); // should be global anyway
exports = {
downloadAsync: function promisifiedDownload() {
var args = arguments, self = this;
return new Promise(function(resolve, reject) {
// We call the originalMethod here because if it throws,
// it will reject the returned promise with the thrown error
var emitter = download.apply(self, args);
var buffers = [];
emitter.on("data", function(data) {
buffers.push(data);
}).on("error", function(err) {
reject(err);
}).on("close", function() {
resolve(Buffer.concat(buffers));
});
});
};
};
Notice it's quite nonsensical to use promisifyAll when you only want to promisify a single method. I've omitted it for simplicity
You might also listen for the incoming response object, and attach the data listener directly to it. You can then use the end event instead of close.

Resources