Proxyquire not stubbing my required class
Asked Answered
S

1

11

I have a class AProvider that requires './b.provider'.

const BProvider = require('./b.provider');

class AProvider {
  static get defaultPath() {
    return `defaults/a/${BProvider.getThing()}`;
  }
}

module.exports = AProvider;

b.provider.js is adjacent to a.provider.js and looks like

global.stuff.whatever = require('../models').get('Whatever'); // I didn't write this!

class BProvider {
  static getThing() {
    return 'some-computed-thing';
  }
}
module.exports = BProvider;

In my test I use proxyquire to mock out ./b.provider as follows:

import { expect } from 'chai';
import proxyquire from 'proxyquire';

describe('A Provider', () => {
  const Provider = proxyquire('../src/a.provider', {
    './b.provider': {
      getThing: () => 'b-thing'
    },
  });

  describe('defaultPath', () => {
    it('has the expected value', () => {
      expect(Provider.defaultPath).to.equal('defaults/a/b-thing')
    });
  });
});

However when I run the test BProvider is still requiring the actual './b.provider' not the stub and BProvider's reference to global.stuff.whatever is throwing an error.

Why isn't this working?

Stilu answered 2/3, 2017 at 8:21 Comment(5)
Have you tried declaring the proxyquire directive in a before statement? Also, not sure if this would help, but this article seems to think using sinon alongside it is necessary: thoughtdelimited.org/thoughts/post.cfm/…Minima
Interesting link. I didn't realise the Require still happened despite proxyquire. In a taxi right now but will test a solution when I get home. Thanks.Stilu
Okay I have worked out the problem and have found an easy solution which I will post below. Thanks @Minima for pointing me in the right direction.Stilu
I tried the post by @Dave Sag and it did not work... however, I found that if I require proxyquire like this const proxyquire = require("proxyquire").noCallThru(); all is good!Bigham
@Minima Hi wanted to read that article, but the link is dead. Can you repoint, please?Lucerne
S
11

The answer as to why this is happening is as follows

proxyquire still requires the underlying code before stubbing it out. It does this to enable callthroughs.

The solution is simply to explicitly disallow callthroughs.

The test becomes:

import { expect } from 'chai';
import proxyquire from 'proxyquire';

describe('A Provider', () => {
  const Provider = proxyquire('../src/a.provider', {
    './b.provider': {
      getThing: () => 'b-thing',
      '@noCallThru': true
    },
  });

  describe('defaultPath', () => {
    it('has the expected value', () => {
      expect(Provider.defaultPath).to.equal('defaults/a/b-thing')
    });
  });
});

Running this test works perfectly.

Stilu answered 2/3, 2017 at 12:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.