Normally I use this code:
aws_stub.S3 = function(){};
var fake_aws_listObjects = function(params, func){func("failure", null)};
var fake_aws_listObjects_stub = sinon.spy(fake_aws_listObjects);
aws_stub.S3.prototype.listObjects = fake_aws_listObjects_stub;
To stub a function like the following one:
new AWS.S3().listObjects(that.build_params(), function(err, data) {
if(err){
that.make_failure_callback();
}
else{
that.add_keys(data);
if(data.IsTruncated){
that.make_request(data.NextMarker);
}else{
that.make_success_callback(that.keys);
}
}
});
The problem with this stubbing is that on each request it returns the same
Now I wanted to do is different stubbing for each call:
aws_stub.S3 = function(){};
var fake_aws_truncated = function(params, func){func(null, {
Contents: [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/1:::2.jpg"}],
IsTruncated: true,
NextMarker: "nextMarker"
})};
var fake_aws_listObjects = function(params, func){func(null, {Contents: [{
Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/2:::3.jpg"
}]})};
var fake_aws_listObjects_stub = sinon.stub();
fake_aws_listObjects_stub.onCall(0).returns(fake_aws_truncated);
fake_aws_listObjects_stub.onCall(1).returns(fake_aws_listObjects);
aws_stub.S3.prototype.listObjects = fake_aws_listObjects_stub;
The problem seems to be returns, it doesn't execute the function!!
I also cannot write it like this:
fake_aws_listObjects_stub.onCall(0) = fake_aws_truncated;
Because this would be a wrong hand assignment!
What do I have to change? Here are the sinon docs: http://sinonjs.org/docs/
Thanks!!
I would probably go about it another way.
If you want to stub AWS.S3.prototype.listObjects, I would do that like so:
var stub = sinon.stub(AWS.S3.prototype, 'listObjects');
To call the callback with various values, use stub.yields():
stub.onCall(0).yields(null, {
Contents : [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/1:::2.jpg"}],
IsTruncated : true,
NextMarker : "nextMarker"
});
stub.onCall(1).yields(null, {
Contents : [{Key: "3fb252ba-0724-438c-93b6-8cd0fd972a8e/image/2:::3.jpg"}]
});
To test your code, you just call listObjects like before:
var s3 = new AWS.S3();
s3.listObjects(params, function(err, value) {
...`value` is now one of the fixtures you declared above...
});
To restore to the original version of the method, use one of these:
stub.restore();
// OR:
AWS.S3.prototype.listObjects.restore();
Related
This question already has answers here:
How to access the correct `this` inside a callback
(13 answers)
Closed 6 years ago.
so here is a situation that i have. I have a constructor function with many properties and methods. here are the properties:
var Brain = function(){
this.util = require('util');
this.fs = require('fs');
this.assert = require('assert');
this.Sequelize = require('sequelize');
this.JsonField = require('sequelize-json');
this.bcrypt = require('bcrypt-nodejs');
this.bodyParser = require('body-parser');
this.fileUpload = require('express-fileupload');
// Custom Modules
this.ModelsModule = require('./models');
this.TombModule = require('./tomb');
}
a few of the methods are defined to call a given callback and pass data to it, for example:
Brain.prototype.db_read = function(request, response, data, callback) {
var self = this;
self.ModelsModule[data.Model].findOne(data.where)
.then(function(obj) {
// console.log(obj);
callback(request, response, obj);
})
.catch(function(error){
console.log(error);
});
}
Here is the thing - the callback function is always going to be another method of the same constructor function. here is another method that would be a callback:
Brain.prototype.login = function(request, response, user) {
var self = this;
// console.log('form-data --- ', request.body);
if(user == null || user == undefined) {
console.log('Account Load: Failed');
return response.render( self.TombModule.pages['login'], {error: 'Invalid Credentials'} );
}
else {
// console.log(user.dataValues);
if( self.bcrypt.compareSync(request.body.pswrd, user.dataValues.pswrd) == false ) {
console.log('Account Load: Failed');
return response.render( self.TombModule.pages['login'], {error: 'Invalid Credentials'} );
}
console.log('Account Load: Successful');
request.session.you = {
id: user.dataValues.id,
f_name: user.dataValues.f_name,
m_initial: user.dataValues.m_initial,
l_name: user.dataValues.l_name,
icon: user.dataValues.icon,
background: user.dataValues.background,
email: user.dataValues.email,
phone: user.dataValues.phone,
fax: user.dataValues.fax,
uv: user.dataValues.uniqueValue
};
return response.redirect('/home');
}
}
In my app.js a new instance of Brain is created.
const RoutinesModule = require('./routines');
const brain = new RoutinesModule.Brain();
The Entire chain of events starts from an express POST route:
app.post('/login', function(request, response){
var data = {
Model: 'Users',
where: {where: {email: request.body.email}}
}
brain.db_read(request, response, data, brain.login);
});
Notice that the callback, the last parameter, for Brain.db_read is Brain.login, which is another method of the same constructor. here is where the problem is happening.
When POST requests to /login hits the app.js, it's going to query the database and give the results to any given function to handle it, in this case Brain.login
inside of Brain.db_read(), var self = this; works. it points to itself, the instance of the Brain. however, when it calls the callback which is Brain.login, the statement inside of Brain.login, var self = this; does not work. it results in undefined, causing an error.
Why is that happening? why is var self = this; inside of the Brain.login resulting in undefined?
Ultimately what i am trying to do is create a set of main functions to handle database operations(CRUD) instead of doing database operations inside of each individual function, which is/could be an indefinite amount.
I could easily just require that module in that function definition but i would strongly prefer to access its property for dynamic, scalable, and efficiency means.
Thanks!
You're passing the method, brain.login, as a function that has no owner. You're just passing the function reference. You need to do brain.login.bind(brain).
I would like to pass the current context or an attribute to functions in async.waterfall. How to:
pass this
an attribute (here options object)
This is what I already have:
var _authenticate = function (cbAsync) {
var licenseId = options.licenseId; //options is undefined
};
module.exports = new Command('createOrga')
.description('creates an organization')
.option('-f, --file <file>', 'the structure file including full path')
.action(function (options) {
options.confirm = options.confirm || true; // No confirmation needed!
options.organizationUUID = (uuid.v4()).toUpperCase();
options.licenseId = (uuid.v4()).toUpperCase();
//How to pass options object to _authenticate function????
async.waterfall([ _authenticate ], function(err) {
if ( err ) {
console.warn('Error in creating new organization: ',err);
}
else {
console.info('Successfully created new organization: ' + organizationUUID);
}
});
}
}
You could use Function.prototype.bind() to pass variables.
async.waterfall([ _authenticate.bind(undefined, options)], function(err) {
//your code
});
Because the bound variables are pass first, your callback then has to look like this:
var _authenticate = function (options, cbAsync) {
var licenseId = options.licenseId; //options is undefined
};
This is probably a noob JavaScript question, but I'm looking to know if my solution to a problem I am having is 'correct'
I have created the following sample application that recreates my error:
Firstly in index.js
var processor = require('./fileProcessor/processor.js');
var container = {
source: "source.txt",
destination: "destination.txt"
};
new processor().process(container);
I create my container object which has the name of the source file and the name of the destination file. This is passed into the process function of the processor:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
this.process = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, this.process);
} else {
file.write(container, this.process);
}
}
};
};
As you can see this calls the read and write functions passing in the container and the process function as the callback, the fileProcessor looks like this:
var fs = require('fs');
module.exports = function() {
this.read = function(container, callback) {
fs.readFile(container.source, function (err, data) {
if(err) throw err;
container.body = data;
callback(container);
});
};
this.write = function(container, callback) {
fs.writeFile(container.destination, container.body, function(err) {
if(err) {
return console.log(err);
}
container.finished = true;
callback(container);
});
};
};
In simple terms the processor calls file.read, which reads the file and calls back into the process function, which then calls the write function. However at the end of the write function an error is thrown:
callback(container);
^
TypeError: object is not a function
Obviously when passing in this.process to file.write(container, this.process); the this isn't the this I intend it to be!
If I update my processor by adding a processFunction variable:
var fileProcessor = require('./fileProcessor.js');
module.exports = function Processor() {
var processFunction = function(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
this.process = function(container) {
processFunction(container);
};
};
Everything works fine. Is this a good way to do this or is there a better solution?
I think this is a fine way to do it. There is one possible modification that you might make. Since you are creating a new name in your scope just for the purpose of recursing, you could just name your function and refer to it by its name inside of the function.
module.exports = function Processor() {
this.process = function processFunction(container) {
var file = new fileProcessor();
if(container.finished === undefined) {
if(container.body === undefined) {
file.read(container, processFunction);
} else {
file.write(container, processFunction);
}
}
};
};
Then you can avoid creating a name (processFunction) that will be visible outside the function.
Take a look here for reference:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function#Named_function_expression
I have two files: BaseController.js and EventRecordController.js. EventRecord needs to inherit a few methods from BaseController.
BaseController
var Q = require('q'),
util = require('../util');
exports.BaseController = function(req, res) {
this.req = res;
this.res = res;
this.fields = {};
this.error = {
code: 200,
message: 'BAD REQUEST: The parameters provided were invalid. See response body for error messages.',
specific_message: ''
};
};
// Utility method to handle returning errors that are thrown.
exports.BaseController.prototype.handle_errors = function(error) {
if(this.error.code === 500) {
util.internal_error(this.res, this.response_type);
} else {
var response = util.build_error_response(this.response_type, this.error.code, this.error.message, this.error.specific_message);
util.send_response(this.res, this.response_type, this.error.code, response);
}
};
// Check to see if a user is authenticated and whether they are using a correct response type.
exports.BaseController.prototype.validate_response_type_and_authenticate = function() {
var deferred = Q.defer();
util.validate_response_type_and_authenticate(this.req, this.res, function(auth_data, response_type) {
this.auth_data = auth_data;
this.company_user_uid = this.auth_data.data.company.uid;
this.response_type = response_type;
this.v3_token = this.auth_data.data.token;
deferred.resolve();
});
return deferred.promise;
};
EventRecordController
var base_controller = require("./BaseController"),
Q = require('q'),
util = require('../util'),
validator = require('validator');
exports.EventRecordController = function(req, res) {
function EventRecord(req, res) {
base_controller.BaseController.apply(this, arguments);
}
// Inherit from BaseController, then fix constructor.
EventRecord.prototype = new base_controller.BaseController();
EventRecord.prototype.constructor = EventRecord;
EventRecord.run = function() {
console.log(this.error);
};
return EventRecord;
};
When I run the following code, this.error logs as undefined from within the run() method.
var event_record_controller = require("./controllers/EventRecordController"),
util = require('./util'),
validator = require('validator');
exports.record = function(req, res) {
var controller = new event_record_controller.EventRecordController(req, res);
controller.run();
};
I think I'm missing something obvious here, but my experience with prototype based inheritance is limited.
this.error is undefined because run is being called directly on the constructor, which doesn't have an error, rather than one of its instances.
Methods that are attached directly to the constructor aren't inherited. For that, they should be attached to the prototype:
// "static" method available only through the constructor itself
EventRecord.run = function() {
console.log(this.error);
};
// "class" method inherited by instances of `EventRecord`
EventRecord.prototype.run = function () {
console.log(this.error);
};
But, you also don't yet have an instance of EventRecord to call .run() on.
When a constructor returns an object, the instance that was created by using new will be discarded. So, calling new EventRecordController() is just returning the function EventRecord.
var controller = new event_record_controller.EventRecordController(req, res);
console.log(typeof controller); // function
console.log(controller.name); // "EventRecord"
controller = new controller(req, res);
console.log(typeof controller); // object
You could revise EventRecordController to return an instance of EventRecord:
// ...
return new EventRecord(req, res);
Though, you might consider consolidating the 2 constructors rather than having one generate the other:
exports.EventRecordController = function(req, res) {
base_controller.BaseController.apply(this, arguments);
};
util.inherits(exports.EventRecordController, base_controller.BaseController);
exports.EventRecordController.prototype.run = function () {
console.log(this.error);
};
I'm using a proxy class as the data I have is a reference to a Firebase location that stores my object but I want to act as if I have the object itself. I've got something that works fine but I would like to improve it, the key criteria being to reduce repetition. I suspect something is possible by inspecting the Map class and using apply() but I don't know quite how to do that (or if there is a better solution).
I think it would also be useful if the solution could be generalised to support any class, not just the Map class.
var Map = function() {
...
};
var MapProxy = function(mapRef) {
this.mapRef = mapRef;
};
Map.prototype.addToken = function(portrait, newLocation) {
...
};
Map.prototype.removeToken = function(token) {
...
};
Map.prototype.moveToken = function(token, newLocation) {
...
};
MapProxy.prototype.addToken = function(portrait, newLocation) {
var mapRef = this.mapRef;
mapRef.once('value', function(data) {
var map = new Map();
map.init(mapRef, data.val());
map.addToken(portrait, newLocation);
});
};
MapProxy.prototype.removeToken = function(token) {
var mapRef = this.mapRef;
mapRef.once('value', function(data) {
var map = new Map();
map.init(mapRef, data.val());
map.removeToken(token);
});
};
MapProxy.prototype.moveToken = function(token, newLocation) {
var mapRef = this.mapRef;
mapRef.once('value', function(data) {
var map = new Map();
map.init(mapRef, data.val());
map.moveToken(token, newLocation);
});
};
var mapProxy = new MapProxy(mapRef);
Think I solved it myself in the end.
var FirebaseProxy = function(classToProxy, firebaseRef) {
var key,
self = this;
self.proxy = classToProxy;
self.firebaseRef = firebaseRef;
for (key in self.proxy.prototype) {
if (typeof self.proxy.prototype[key] === 'function') {
(function(inner_key) {
self[inner_key] = function ()
{
var args = arguments;
self.firebaseRef.once('value', function(data) {
var proxiedInstance = new self.proxy();
if (typeof proxiedInstance.init === 'function') {
proxiedInstance.init(self.firebaseRef, data.val());
}
proxiedInstance[inner_key].apply(proxiedInstance, args);
});
}
})(key);
}
}
}
I don't think I completely follow what you're trying to accomplish. Could you forego the proxy and just use something like this?
var Map = function(mapRef) {
mapRef.on('value', function(snap) {
this.init(snap.val());
});
};
Map.prototype.init = function(data) {
// update internal state with new data from Firebase ...
};
...
Since 'value' will fire every time the data at mapRef changes, your map object will always have the latest data.
It's worth noting that if you're going to be needing the latest map data on a regular basis, you should probably use .on(), not .once(). .once() will go and retrieve the data from the servers every time you ask for it, while .on() will always have the latest data cached (since it subscribes to updates). So it'll be faster and use less bandwidth.