thlorenz / proxyquireify

browserify >= v2 version of proxyquire. Mocks out browserify's require to allow stubbing out dependencies while testing.
MIT License
151 stars 24 forks source link

Returned proxy fails instanceof test #18

Closed zpchavez closed 9 years ago

zpchavez commented 10 years ago

An instance of a constructor returned by proxyquire does not pass an instanceof test with the parent. In particular, this causes an error when attempting to render a proxy of a React component. Here is a test case for the issue.

parent.js

'use strict';

var Parent = function() {};

Parent.prototype = {'foo' : function() {return 'bar';}};

module.exports = Parent;

foo.js

'use strict';

var Parent = require('./parent');

var Foo = function() {};

Foo.prototype = Parent.prototype;

module.exports = Foo;

foo-test.js

'use strict';

var expect     = require('chai').expect;
var proxyquire = require('proxyquireify')(require);
var Parent     = require('../../application/parent');
var Normal     = require('../../application/foo');
var Proxy      = proxyquire('../../application/foo', {});

describe('Normal require', function() {

    it('returns constructor an instance of which passes instanceof test', function() {
        var normal = new Normal();

        expect(normal instanceof Parent).to.equal(true);
    });

});

describe('Proxyquire', function() {

    it('returns constructor an instance of which passes instanceof test', function() {
        var proxy = new Proxy();

        expect(proxy instanceof Parent).to.equal(true);
    });

});

Thanks

thlorenz commented 10 years ago

I have honestly no idea why that happens nor how to fix it. You should get back the same constructor since you aren't even stubbing any methods.

I'm not sure if I can help, but we could have a look if you push a simple test case to github that I can simply run via: npm install && npm test.

Thanks.

/cc @jhiesey

ellbee commented 10 years ago

I think this is what I would expect to happen. My understanding is that a Proxyquireify call introduces a temporary cache that is used for all require calls made inside it.

The Parent constructor required in foo.js will be the same as the Parent constructor required in foo-test.js, because they are both using the Browserify cache.

The Parent constructor inside the proxyquire call is using the temporary proxyquireify cache. It doesn't find the previously required Parent constructor in its cache, so it requires it again. This creates a new Parent constructor which is different to the Parent constructor in foo-test.js.

zpchavez commented 10 years ago

@ellbee That makes perfect sense. It also doesn't sound like an easy fix.

I suppose it is easy enough in my test to just add Proxy.prototype = Normal.prototype. I made a fork where I added a failing test, but if this is unfixable I will go ahead and delete it.

bendrucker commented 9 years ago

I don't think this behavior can change. If anyone looks more deeply and thinks this case can be made to work we'll reopen.