I want to log an errors to know from which method/function of class i got error. To log this i want a generic code, by that i can know the method/function name from method it self. below is my code.
In below code, each catch block i want particular method name like SaveData and GetData.
I tried arguments.callee but it's not working in strict mode.
I also tried Object.values(this) but it gives me all methods array so i can't decide at what element my current method name exist.
I want any generic solution because i have hundreds of function in a class and i not want to write each function name in each method.
class MyClass {
/**
* Class default constructor
*/
constructor() {
this.file_path = path.join(__dirname, path.basename(__filename));
}
SaveData = async (req, res) => {
try {
//doing some operation to store data
} catch (err) {
//in catch block i want "SaveData"(method name) so i can pass as parameter in below generic method which i have created somewhere in common file.
log.error(res, err, this.file_path);
}
}
GetData = async (req,res) => {
try {
//doing some operation to get records from db
} catch (err) {
//in catch block i want "GetData"(method name) so i can pass as parameter in below generic method which i have created somewhere in common file.
log.error(res, err, this.file_path);
}
}
}
module.exports = new MyClass();
Related
I'm trying to stub a function using sinon. The function has the following signature
export function getIndexDocument(
svc: MetaHTTPService | ServiceConfig
): MetaPromise<RepoResponseResult<IndexDocument>> {
Is this the right way to sub it
sandbox.stub(getIndexDocument).resolves({} as RepoResponseResult)
I tried that but it returns an error.
Here's how this function is called.
I have a class called AssetsController with the following functions
public async exploreIndexDocument(): Promise<Asset | undefined> {
// it makes an HTTP request and returns a promise that resolves with the following info { repoId: "", assetId: "" }
const {
result: { assignedDirectories }
} = await getIndexDocument(this.serviceConfig).catch(err => {
throw new Error(`Bad repsonse`);
});
return {
repoId: result.repoId;
assetId: result.assetId
}
}
public async function copyAsset(asset) {
const res = await this.exploreIndexDocument();
const repoId = res.repoId;
return asset.copy(repoId);
}
I'm trying to test the function copyAsset, but it calls exploreIndexDocument which calls getIndexDocument. getIndexDocument is imported at the top of the file and lives in the module #ma/http.
getIndexDocument makes an HTTP request.
How can I test copyAsset given that it calls getIndexDocument which makes an HTTP request?
According to the docs, you can't stub an existing function.
You can:
// Create an anonymous sstub function
var stub = sinon.stub();
// Replaces object.method with a stub function. An exception is thrown
// if the property is not already a function.
var stub = sinon.stub(object, "method");
// Stubs all the object’s methods.
var stub = sinon.stub(obj);
What you can't do is stub just a function like:
var stub = sinon.stub(myFunctionHere);
This makes sense because if all you have is a reference to a function, then you can just create a new function to use instead, and then pass that into where ever your test needs it to go.
I think you just want:
const myStub = sandbox.stub().resolves({} as RepoResponseResult)
In your update it sounds like you want to put the stub on the AssetsController class. See this answer for more info on that, but in this case I think you want:
const myStub = sandbox
.stub(AssetsController.prototype, 'exploreIndexDocument')
.resolves({} as RepoResponseResult)
Now anytime an instance of AssetsController calls its exploreIndexDocument method, the stub should be used instead.
Playground
I think most of your problems can be solved by revisiting your architecture. For example, instead of creating an explicit dependency on getIndexDocument within your AssetController class you can simply inject it in. This will allow you to swap implementations depending on the context.
type IndexDocumentProvider = (svc: MetaHTTPService | ServiceConfig) => MetaPromise<RepoResponseResult<IndexDocument>>;
interface AssetControllerOptions {
indexDocumentProvider: IndexDocumentProvider
}
class AssetController {
private _getIndexDocument: IndexDocumentProvider;
public constructor(options: AssetControllerOptions) {
this._getIndexDocument = options.indexDocumentProvider;
}
}
Then you can use this._getIndexDocument wherever and not worry about how to make the original implementation behave like you want in your tests. You can simply provide an implementation that does whatever you'd like.
describe('copyAsset', () => {
it('fails on index document error.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.reject(new Error(':('));
});
....
});
it('copies asset using repo id.', () => {
const controller = new AssetController({
indexDocumentProvider: () => Promise.resolve({ repoId: "420" })
});
...
});
});
You can obviously use stubs instead of just functions or whatever if you need something fancy.
Above we removed an explicit dependency to an implementation and instead replaced it with a contract that must be provided to the controller. The is typically called Inversion of Control and Dependency Injection
I am new to node js and i am actually not able to understand how to call methods inside a class except statically or by creating a new object each time i'm iterating over functions.
This is kind of crazy. For example:
class UserController
{
methodOne (req, res) {
this.methodTwo (req);
}
methodTwo (data) {
return data;
}
}
That's how i want to call my function but, every time i do this, I end up with error of this is undefined.
I know fat arrow functions don't follow the same context like in javascript. But i just wanna make sure if i'm doing it right or not.
And that's how i achieve above code.
class UserController
{
static methodOne (req, res) {
UserController.methodTwo (req);
}
static methodTwo (data) {
// Manipulates request before calling
return UserController.methodThree (data);
}
static methodThree (data) {
return data;
}
}
i.e. calling each method statically with class name UserController.
So if there's any better way to do it, I need you to suggest.
Thanks in advance.
P.S: Above code is just an example guys.
The reason for your problem is that you lost the function context
class UserController {
async methodOne() {
return this.methodTwo()
}
async methodTwo() {
return Promise.resolve("methodtwo")
}
}
const obj = new UserController();
const methodOne = obj.methodOne;
methodOne(); // ----> This will throw the Error
methodOne.call(obj); // ----> This Works
// Or you can call the method directly from the obj
obj.methodOne(); // Works!!
// If you want to cache the method in a variable and preserve its context use `bind()`
const methodOneBound = obj.methodOne.bind(obj);
methodOneBound(); // ----> This works
I'm trying to make a subclass of an image library on github called Jimp. As far as I can tell from the docs, you don't instantiate the class in the usual way. Instead of saying new Jimp(), it seems the class has a static method called read that acts as a constructor. From the docs...
Jimp.read("./path/to/image.jpg").then(function (image) {
// do stuff with the image
}).catch(function (err) {
// handle an exception
});
It looks like from the docs, that that image returned by read() is an instance allowing the caller to do stuff like image.resize( w, h[, mode] ); and so on.
I'd like to allow my subclass callers to begin with a different static method that reads an image and does a bunch of stuff, summarized as follows...
class MyJimpSubclass extends Jimp {
static makeAnImageAndDoSomeStuff(params) {
let image = null;
// read in a blank image and change it
return Jimp.read("./lib/base.png").then(_image => {
console.log(`image is ${_image}`);
image = _image;
let foo = image.bar(); // PROBLEM!
// ...
// ...
.then(() => image);
}
bar() {
// an instance method I wish to add to the subclass
}
// caller
MyJimpSubclass.makeAnImageAndDoSomeStuff(params).then(image => {
//...
});
You might be able to guess that nodejs gets angry on the line let foo = image.bar();, saying
TypeError image.bar is not a function
.
I think this is understandable, because I got that image using Jimp.read(). Of course that won't return an instance of my subclass.
First idea: Change it to MyJimpSubclass.read(). Same problem.
Second idea: Implement my own static read method. Same problem.
static read(params) {
return super.read(params);
}
Third idea: Ask SO
The implementation of Jimp.read refers to Jimp specifically, so you would have to copy and change it in your subclass (ick, but not going to break anything since the constructor is also part of the API) or make a pull request to have it changed to this and have subclassing explicitly supported:
static read(src) {
return new Promise((resolve, reject) => {
void new this(src, (err, image) => {
if (err) reject(err);
else resolve(image);
});
});
}
Alternatively, you could just implement all your functionality as a set of functions on a module. This would be next on my list after making a pull request. Would not recommend a proxy.
const makeAnImageAndDoSomeStuff = (params) =>
Jimp.read("./lib/base.png").then(image => {
console.log(`image is ${image}`);
let foo = bar(image);
// …
return image;
});
function bar(image) {
// …
}
module.exports = {
makeAnImageAndDoSomeStuff,
bar,
};
Even changing the prototype would be better than a proxy (but this is just a worse version of the first option, reimplementing read):
static read(src) {
return super.read(src)
.then(image => {
Object.setPrototypeOf(image, this.prototype);
return image;
});
}
You have a couple of options. The cleanest is probably to make a subclass like you started, but then implement the Jimp static method on it, as well as your own. In this case, it's not really inheritance, so don't use extends.
class MyJimp {
static read(...args) {
return Jimp.read.apply(Jimp, args);
}
static makeAnImage(params) {
return this.read(params)
.then(image => {
// do stuff
return image
});
}
}
From there, I would make an object which has all of the new functions you want to apply to image:
const JimpImageExtension = {
bar: () => { /* do something */ }
};
Finally, in your static methods, get the image and use Object.assign() to apply your new functions to it:
class MyJimp {
static read(...args) {
return Jimp.read.apply(Jimp, args)
.then(image => Object.assign(image, JimpImageExtension));
}
static makeAnImage(params) {
return this.read(params)
.then(image => {
// do stuff
image.bar();
return image;
});
}
}
This should do the trick by applying your extra functions to the image. You just need to make sure that you apply it at every point that can generate an image (if there is more than just read). Since in the other functions, it's using your version of read(), you only need to add the functions in the one.
Another approach would be if Jimp makes their image class accessible, you could also add them to the prototype of that (though usually in libraries like this, that class is frequently inaccessible or not actually a class at all).
This might be a way to do it. Start with your own read method, and have it change the prototype of the returned object.
static read(...params) {
return super.read(...params).then(image) {
image.prototype = MyJimpSubclass;
resolve(image);
}
}
I am try to make a logging service for my TypeScript / Angular 2 App. Unfortunately if i call console.log the line number is wrong. Even if i try to return console.log().
Here is my code:
LoggerService.ts
export class LoggerService {
log(message) {
// Server-side logging
// [...]
if (clientSideLogging) return console.log(message);
}
}
SomewhereElse.ts
this.logger.log('hello world');
-> Shows line number of LoggerService.ts instead of source
You could use the .bind() method to bind window.console to your custom log method and then return the function so that the code is executed within the original scope when it is called.
In doing so, the line number will be preserved when calling the logger service's log method:
class LoggerService {
public log = console.log.bind(window.console);
}
// ...or annotated:
class LoggerService {
public log: (message) => void = console.log.bind(window.console);
}
Then if you want to add in your conditional statement:
class LoggerService {
public log = clientSideLogging ? console.log.bind(window.console) : () => {};
}
Here is an example with the compiled TypeScript code.
Aside from the one-liner solutions mentioned above, if you want to implement additional logic inside of the log method, then you could utilize a getter which will return and call the console.log function that is bound to window.console.
class LoggerService {
public get log (): Function {
// Implemnt server-side logging
return console.log.bind(window.console);
}
}
As you can tell, it is important for the console.log function to be returned since it will not preserve the line numbers when it is called directly within another scope.
Then if you want to add in your conditional statement:
class LoggerService {
public get log (): Function {
const log = console.log.bind(window.console);
// Implemnt server-side logging
return clientSideLogging ? log : () => {};
}
}
Here is an example with the compiled TypeScript code.
You could use .trace() instead of .log().
this.logger.trace('hello world');
This will give you a stack trace to the original line number.
https://developer.mozilla.org/en-US/docs/Web/API/Console/trace
I'm trying to sort out a good simple pattern for node.js with an init method for the use of 'models' when connecting to mongodb collections. Basically, each collection has a 'model'.
Here's what I have, setup as a singleton, any reason not go to with this method or is there more recommended method within the context of node?
module.exports = User;
function User () {
if ( arguments.callee.instance ) {
return arguments.callee.instance;
} else {
arguments.callee.instance = this;
}
//Init our database collection
}
User.findOne = function (user_id) {
}
User.addUser = function () {
}
return new User();
Thank you!
Um, you should put User.prototype.method.
User.prototype.findOne = function (user_id) {
}
User.prototype.addUser = function () {
}
Instead of 'return new User()' you probably meant,
module.exports = new User();
One reason not to export a 'new' User() is if you want to create more than one user in your nodejs program. If you only have one user, then a singleton is fine. Also, if you want to pass data to this module, you may want to do so via a constructor argument, and if you only construct the User in the module, then you can't pass to the constructor in your app.
I use a pattern that assigns module.exports to a function. The first argument of all my exports is an object shared amongst all exports, so they can add events/listeners and talk to each other in various different ways.
For example ('events' and 'app' are psuedo, not based on any real API),
function doLogin(app) {
return function (e) {
// some code to do login
}
}
module.exports = function login (app) {
app.events.on('login', doLogin(app));
}
Now all of the other modules can trigger a login via
app.events.login({'user': '..','pass': '..'});