Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question - dealing with require.exports = ClassConstructor #144

Closed
d1manson opened this issue Nov 21, 2016 · 8 comments
Closed

Question - dealing with require.exports = ClassConstructor #144

d1manson opened this issue Nov 21, 2016 · 8 comments

Comments

@d1manson
Copy link

I originally asked this on SO but got no reply - I'm guessing here would be a better bet....

If I have a module that exports a single class, how can I mock/stub it with proxyquire?

Currently I have the following, which seems to work, but is rather lengthy and doesn't make proper use of proxyquire:

some-class.js

var SomeClass = function(){
  console.log("constructed SomeClass");
}
SomeClass.prototype.shout = function(){
  console.log("HELLO!");
}
module.exports = SomeClass;

my-module.js

var SomeClass = require('some-class');
module.exports.doSomething = function(){
  var a = new SomeClass();
  a.shout();
}

test-my-module.js

// :::: bit I'd like to avoid ::::::
var cls = require('some-class'); 
var SomeClassStub = function(){
  cls.apply(this, arguments);
};
SomeClassStub.prototype = Object.create(originalCls.prototype);
// :::::::::::::::::::::::::::::::::

var myModule = proxyquire('my-module', {
  'some-class': SomeClassStub
});

SomeClassStub.prototype.shout = function(){
  console.log("whisper");
}

myModule.doSomething();

Note that I am fairly new to mocking (and testing!) so I might be missing something obvious, but I was hoping that proxyquire would deal with my problem itself (rather than me needing to use another library or write the above code).

Thanks!

@bendrucker
Copy link
Collaborator

What are you expecting proxyquire to do here for you? Automatically set up a constructor and clone a prototype for you? Because it doesn't do that.

@d1manson
Copy link
Author

Is there a different approach I could be taking?

In particular I don't like the fact that I have to explicitly require the original version of the class - is there no way to use the proxyquire machinery/syntax to do at least some of the work. And make it look simpler?

@bendrucker
Copy link
Collaborator

If you pass in a function as a stub proxyquire will try to extend your stub's prototype with the original:

https://github.com/bendrucker/fill-keys/blob/master/index.js#L10-L12

So if you want to override a class, you have to override the constructor (always) but can provide only the method you intend to override on your stub's prototype. Does that help?

@d1manson
Copy link
Author

d1manson commented Nov 21, 2016

Hmm, I think that's the answer I was looking for. Thanks!
It would be nice though if proxyquire provided the original constructor to the stubbed function so that it can use apply (or whatever) as needed...actually, maybe it is already available as this.prototype.constructor?
If it turns out that I can do what I wanted here, I suggest putting an example in the docs, because I stared at them for a while but couldn't see what I should be doing.

Thanks for the quick replies.

@bendrucker
Copy link
Collaborator

No problem. I agree that class examples would be helpful. Will keep it in mind for future work.

@montrealist
Copy link

Hey @d1manson did you ever figure out how to optimize this with proxyquire? Grappling with the same issue now.

@kenkopelson
Copy link

Hey Ben, thanks for all your great work on proxyquire! Just one question if I may. I'm asking proxyquire to stub some methods in a mongoose model. When the model gets loaded in the underlying module (Node), proxyquire is turning it into an object, and removing it's javascript class nature (constructor). This means I can no longer call "new" on the model object to create a new instance of the model. I was hoping it would just load the Model class/constructor in like normal, and then replace the methods I give it to replace. By rendering the Model class as a javascript object, it basically breaks the code. Can anything be done?

@bendrucker
Copy link
Collaborator

Use noCallThru and provide a full mock if class semantics are important

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants