javascripttestingmeteorproxyquire

Require not behaving as expected


I'm using the proxyquire library, which mocks packages on import.

I'm creating my own proxyquire function, which stubs a variety of packages I use regularly and want to stub regularly (meteor packages, which have a special import syntax):

// myProxyquire.js
import proxyquire from 'proxyquire';

const importsToStub = {
  'meteor/meteor': { Meteor: { defer: () => {} } },
};

const myProxyquire = filePath => proxyquire(filePath, importsToStub);

export default myProxyquire;

Now I want to write a test of a file which uses one of these packages:

// src/foo.js
import { Meteor } from 'meteor/meteor'; // This import should be stubbed

export const foo = () => {
  Meteor.defer(() => console.log('hi')); // This call should be stubbed
  return 'bar';
};

And finally I test it like this:

// src/foo.test.js
import myProxyquire from '../myProxyquire';

// This should be looking in the `src` folder
const { foo } = myProxyquire('./foo'); // error: ENOENT: no such file

describe('foo', () => {
  it("should return 'bar'", () => {
    expect(foo()).to.equal('bar');
  });
});

Note that my last 2 files are nested inside a subfolder src. So when I try to run this test, I get an error saying that the module ./foo couldn't be found, as it is being looked for in the "root" directory, where the myProxyquire.js file is, not the src directory as expected.


Solution

  • You might be able to work around that (expected) behaviour by using a module like caller-path to determine from which file myProxyquire was called, and resolving the passed path relative to that file:

    'use strict'; // this line is important and should not be removed
    
    const callerPath           = require('caller-path');
    const { dirname, resolve } = require('path');
    
    module.exports.default = path => require(resolve(dirname(callerPath()), path));
    

    However, I have no idea of this works with import (and, presumably, transpilers).