Sinon stub throwing Attempted to wrap object which is already wrapped - node.js

Although there are posts regarding this , I could not fix it using before, after functions and restoring the objects. Posting the code below:-
var Log = sinon.stub(hello, 'someEvent', function(type, name){
var obj = {};
obj.addData = function(data){
return;
};
obj.complete = function(){
return;
}
return obj;
}),
someVar = sinon.stub(servicecore, 'some'),
The error I get is:-
Attempted to wrap someEvent which is already wrapped.
And
Attempted to wrap some which is already wrapped.
Can someone help with this?
Edited below
I even tried with before and after functions as suggested:-
var Log,someVar;
before(function(){
Log = sinon.stub(hello, 'someEvent', function(type, name){
var obj = {};
obj.addData = function(data){
return;
};
obj.complete = function(){
return;
}
return obj;
});
someVar = sinon.stub(servicecore, 'some');
});
after(function(){
Log.restore();
someVar.restore();
});
Tried even with beforeEach and afterEach functions but same error.

From the sinon documentation:
var stub = sinon.stub(object, "method"); Replaces object.method with a
stub function. The original function can be restored by calling
object.method.restore(); (or stub.restore();). An exception is thrown
if the property is not already a function, to help avoid typos when
stubbing methods.
The stub is normally restored after the test is complete using the after or afterEach hooks.
after(function() {
// runs before all tests in this block
someVar.restore();
});
afterEach(function() {
// runs before each test in this block
someVar.restore();
});

you are stubbing someVar.some not someVar itself
so you need to restore its method:
someVar.some.restore();
If you still have problems, then try to stub using the following method.
someVar.some = sinon.stub();
Looks like the same but it is not :) (discovered after hours of swearing)
Anyway let's try the sandbox in sinon to stub from it and just restore the sandbox at the end
https://sinonjs.org/releases/v1.17.7/sandbox/

Related

Promisify trying to connect class with callback [duplicate]

I am trying to refactory my nodejs server using promises with Bluebird library, but I am stuck in a simple problem.
After to get the users from my db, I want to list all notification class associated with this user:
Bad Way (working...)
adapter.getUsers(function(users){
users.rows.forEach(function(item){
user = item.username;
adapter.getNotifications(user, function(notificationList){
console.log(notificationList);
})
});
});
Elegant Tentative Way (not working...)
var getNotifications = Promise.promisify(adapter.getNotifications);
adapter.getUsers().then(function(users) {
users.rows.forEach(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
});
}).then(function(result){
console.log(result);
console.log("NOTIFICATIONLIST");
});
However when I execute this code I get this error inside my getNotification method:
Unhandled rejection TypeError: Cannot read property 'nano' of undefined
at Adapter.getNotifications (/Users/DaniloOliveira/Workspace/sigalei-api/api/tools/couchdb-adapter.js:387:30)
at tryCatcher (/Users/DaniloOliveira/Workspace/sigalei-api/node_modules/bluebird/js/main/util.js:26:23)
EDIT
After the user2864740`s precious comments, I noticed that the error is related with some scope problem. So, why after to use promisify method, the method dont getNotifications recognize the "this" env variable?
var Adapter = module.exports = function(config) {
this.nano = require('nano')({
url: url,
request_defaults: config.request_defaults
});
};
Adapter.prototype.getNotifications = function(userDb, done) {
var that = this;
console.log(that);
var userDbInstance = that.nano.use(userDb);
userDbInstance.view('_notificacao', 'lista',
{start_key: "[false]", end_key: "[false,{}]"},
function(err, body) {
if(err){ done(err); }
done(body);
});
};
This is just the very common problem of calling "unbound" methods.
You can pass the context as an option to Promise.promisify to have it bound:
var getNotifications = Promise.promisify(adapter.getNotifications, {context: adapter});
Alternatively, you'd need to .bind() the method, or call the new getNotifications function on the adapter (using .call()). You might also consider using Promise.promisifyAll(adapater) and then just calling adapter.getNotificationsAsync(…).
Notice that this still doesn't work. You cannot simply create promises in a loop - you need to await them explicitly and return a promise from the then callback, otherwise just the undefined value you returned will be passed to the next callback immediately.
adapter.getUsers().then(function(users) {
return Promise.all(users.rows.map(function(item){
var dbUser = "sigalei/" + item.value.name;
console.log(dbUser);
return getNotifications(dbUser);
}));
}).then(function(results) {
for (var i=0; i<results.length; i++)
console.log("result:", results[i]);
});
Instead of Promise.all(users.rows.map(…)), in Bluebird you can also use Promise.map(users.rows, …).
What about simply
var getNotifications = Promise.promisify(adapter.getNotifications.bind(adapter));
or possibly
var getNotifications = Promise.promisify(function () {
return adapter.getNotifications.apply(adapter, arguments);
});
?
I'm not sure I understand your problem well, but this should make sure this is bound and not undefined when you do return getNotifications(dbUser);

Stub/mock process.platform sinon

I am working with process.platform and want to stub that string value to fake different OSes.
(this object is generated out of my reach, and I need to test against different values it can take on)
Is it possible to stub/fake this value?
I have tried the following without any luck:
stub = sinon.stub(process, "platform").returns("something")
I get the error TypeError: Attempted to wrap string property platform as function
The same thing happens if I try to use a mock like this:
mock = sinon.mock(process);
mock.expects("platform").returns("something");
You don't need Sinon to accomplish what you need. Although the process.platform process is not writable, it is configurable. So, you can temporarily redefine it and simply restore it when you're done testing.
Here's how I would do it:
var assert = require('assert');
describe('changing process.platform', function() {
before(function() {
// save original process.platform
this.originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform');
// redefine process.platform
Object.defineProperty(process, 'platform', {
value: 'any-platform'
});
});
after(function() {
// restore original process.platfork
Object.defineProperty(process, 'platform', this.originalPlatform);
});
it('should have any-platform', function() {
assert.equal(process.platform, 'any-platform');
});
});
sinon's stub supports a "value" function to set the new value for a stub now:
sinon.stub(process, 'platform').value('ANOTHER_OS');
...
sinon.restore() // when you finish the mocking
For details please check from https://sinonjs.org/releases/latest/stubs/

Blocking node from reading simultaneously from db

I have a set of values in a mongoDB I need to only be read ones. So when I have read them I delete that line from the DB. But since node is async if I do getValue() twice in quick succession I get the same value, since the DB has not had time to delete the old one. Does anyone know a good way to fix this problem. I can think of a couple but nothing good.
I don’t have my code here so just wrote a quick example to show my problem.
Var getValue = function() {
ReadfromDB(function(data){
deleteRecord(); // show that what we read has been updated
});
}
You could try something like this. The reading is placed into a promise that's done when the deleting is done as well. This can stack so if you do getValue() 20 times it still should execute in the correct order.
var getValue = function(){
var currentPromise;
var read = function(){
return ReadfromDB().then(function(data){
deleteRecord(); // show that what we read has been updated
});
}
return function() {
if(currentPromise){
currentPromise = currentPromise.then(read)
}else{
currentPromise = read();
}
}
}
What you need to do outside this code is make sure ReadfromDB returns a promise object.
Sounds like a good use case for a closure!
var getValue = (function() {
var called = false;
return function() {
if (!called) {
called = true;
ReadFromDB(function(data) {
deleteRecord();
});
}
};
}());
You could also use once to do exactly the same thing.
var once = require('once');
var getValue = once(function() {
ReadFromDB(function(data) {
deleteRecord();
});
});

Manually promisifying pg.connect with Bluebird

I want to promisify node-postgres' pg.connect method along with the inner connection.query method provided in the callback.
I can .promisify the latter, but I need to implement the first one manually (if I'm missing something here, please explain).
The thing is, I'm not sure if this code is correct or should be improved? The code is working, I just want to know if I'm using Bluebird as meant.
// aliases
var asPromise = Promise.promisify;
// save reference to original method
var connect = pg.connect.bind(pg);
// promisify method
pg.connect = function (data) {
var deferred = Promise.defer();
connect(data, function promisify(err, connection, release) {
if (err) return deferred.reject(err);
// promisify query factory
connection.query = asPromise(connection.query, connection);
// resolve promised connection
deferred.resolve([connection,release]);
});
return deferred.promise;
};
Throw all that horrible callback code away, then do this somewhere in your application initialization:
var pg = require("pg");
var Promise = require("bluebird");
Object.keys(pg).forEach(function(key) {
var Class = pg[key];
if (typeof Class === "function") {
Promise.promisifyAll(Class.prototype);
Promise.promisifyAll(Class);
}
})
Promise.promisifyAll(pg);
Later in anywhere you can use the pg module as if it was designed to use promises to begin with:
// Later
// Don't even need to require bluebird here
var pg = require("pg");
// Note how it's the pg API but with *Async suffix
pg.connectAsync(...).spread(function(connection, release) {
return connection.queryAsync("...")
.then(function(result) {
console.log("rows", result.rows);
})
.finally(function() {
// Creating a superfluous anonymous function cos I am
// unsure of your JS skill level
release();
});
});
By now there are a number of libraries which do this for you:
pg-promise - generic Promises/A+ for PG
postgres-bluebird
dbh-ph
pg-bluebird
Update for bluebird 3:
The pg.connectAsync(...).spread(function(connection, release) { ... }) call will not work anymore, because the API of bluebird has changed: http://bluebirdjs.com/docs/new-in-bluebird-3.html#promisification-api-changes .
The problem is that promisifyAll in bluebird 3 does not handle multiple arguments by default. This results in the .spread() call reporting a TypeError like the following:
TypeError: expecting an array or an iterable object but got [object Null]
To solve this, you can explicitly enable multiple arguments for connect / connectAsync. Do the following after all the promisifying stuff mentioned above:
...
pg.connectAsync = Promise.promisify(pg.connect, { multiArgs: true });
I suggest to modify Petka Antonov solution a bit
var Promise = require('bluebird');
var pg = require('pg');
Object.keys(pg).forEach(function (key) {
var Cls = null;
try {
Cls = pg[key];
if (typeof Cls === 'function') {
Promise.promisifyAll(Cls.prototype);
Promise.promisifyAll(Cls);
}
} catch (e) {
console.log(e);
}
});
Promise.promisifyAll(pg);
here 'pg[key] wrapped up in try-catch block because pg[key] can retrun error when attempt to access pg['native']

wrapping node-memcached with deferred.promisify error

I am trying to wrap the node-memcached api with deferred's promisify in order to simplify my nested callbacks.
When I try to call the promisified function I just get "TypeError: Cannot read property 'namespace' of undefined".
Memcached = require('memcached');
var memcache = new Memcached('localhost:11211');
var add = deferred.promisify(memcache.add);
add('myKey', 'myVal', 0)(function(result) {
...
});
I can't seem to find anyone else trying to wrap node-memcached, or getting my same error. Any insight into what may be going wrong? Or maybe even a push into a better direction if this is imperfect?
Thanks!
EDIT::
Just wanted to response that I found the best solution I could for now by doing some digging.
It seems that deferred.promisify calls the passed function with its own scope (this), instead of the context of the function that is passed in.
Using my own promisfy function appears to fix the issue (idea from http://howtonode.org/promises):
function promisify(fn, context) {
return function() {
var def = deferred();
var args = Array.prototype.slice.call(arguments);
args.push(function(err, val) {
if (err !== null) {
return def.reject(new Error(err));
}
return def.resolve(val);
});
fn.apply(context, args);
return def.promise;
};
}
When promisify instances members you should bind it to this instance like:
Memcached = require('memcached');
var memcache = new Memcached('localhost:11211');
var add = deferred.promisify(memcache.add.bind( memcache ) );
add('myKey', 'myVal', 0)(function(result) {
...
});

Resources