thlorenz / proxyquire

🔮 Proxies nodejs require in order to allow overriding dependencies during testing.
MIT License
2.75k stars 100 forks source link

proxyquiring with an external npm test script #127

Closed zelias500 closed 8 years ago

zelias500 commented 8 years ago

Hi,

I'm having some trouble stubbing out a nested dependency when running my tests using an external script written for npm test purposes. Below is the relevant code:

const API = require('./utils/apiUtils');

app.post('/unique_email', (req, res) => {
    // check db for an email addess
    // if it already exists, tell the DOM to render a password box
    // otherwise send the new company id back to the client
    API.getFreeCompanyUserByEmail(req.body.email).then((user) => {
        if (user.role && user.role !== 'null') {
            // if user exists, send back 'please log in'
            res.status(403).send({message:'please log in'});
        } else {
            // otherwise, send back newly created company
            res.status(200).send({companyId: user.company.id});
        }
    });
});

and the test file:

'use strict';
const test = require('tape');
const proxyquire = require('proxyquire');
const sinon = require('sinon');
const request = require('supertest');

module.exports = function (proxyquireInstance) {
    test('should return 200 when user does not exist in db', (t) => {
        let spy = sinon.spy(function () {
            return Promise.resolve({role: 'null', company: {id: 12345}})
        })
        let mockedAPIFunctions = { getFreeCompanyUserByEmail: spy }

        let routes = proxyquire('../routes', {
            './utils/apiUtils': { getFreeCompanyUserByEmail: spy }
        });

        let app = proxyquire('../server', {
            '../routes': routes
        });

        request(app)
        .post('/unique_email')
        .send({email: '123@456.com'})
        .end((err, res) => {
            t.equal(res.status, 200);
            t.end();
        });

    });
}();

This code works by itself (e.g. node test/test.js) -- proxyquire behaves properly. However, I'm looking to run this test as part of a suite, using test-runner.js (below):

fs.readdir(`${__dirname}`, (err, files) => {
    files.forEach(filename => {
        if (filename !== 'test-runner.js') require(`./${filename}`);
    });
});

Now, proxyquire doesn't seem to properly stub out the API methods I'm looking to replace -- instead, it makes the ajax request that the method normally makes.

The documentation here is a little spotty, so I'm looking for some help. Would really appreciate it!

bendrucker commented 8 years ago

Why are you passing in proxyquireInstance into tests? If you can create a project that minimally reproduces this I'd be happy to try it. Otherwise I don't see how this could be a proxyquire bug.

zelias500 commented 8 years ago

Actually, moving the proxyquireInstance out of the test solved my problem. My thought was to create a new instance inside each test so I could stub out different methods depending on the test, but it's totally possible to do that outside of the test block. Thanks for the help!

bendrucker commented 8 years ago

Sounds good! Proxyquire is like require. It has special semantics and uses the module module. Passing an instance around between modules is pretty guaranteed to behave strangely, just like passing around require.