Search code examples
babeljsproxyquire

What Path is the Babel Plugin module-alias Actually Using?


I'm trying to use Babel's "module-alias" plug-in with the "proxyquire" testing library, but I'm not having a lot of luck.

Library Backstory

(feel free to skip if you are familiar with both module-alias/proxyquire)

Proxyquire let's you mock out a module's dependencies for testing, like so:

const someFunctionToTest = 
  proxyquire(pathToSomeFunctionToTestsModule, {
    pathToDependency: fakeVersionOfDependency
  });

Babel's module-alias plugin let's you make your import paths more convenient and consistent. For instance, I can specify (in .babelrc):

"plugins": [
  ["module-alias", [
    { "src": "./", "expose": "~" }
  ]],

and then instead of having to type (when importing from a module nested three directories deep) require('../../../someModule') I can just typerequire('~/someModule')`.

The Problem

My problem is, they don't work together. If I havesomeModule that depends on someDependency:

// src/someModule.js
const someDependency = require('~/src/someDependency');
doSomethingWith(someDependency);

and then I want to test someModule with a mock version of someDependency, I should be able to do:

const proxiedSomeModule = 
  proxyquire('~/src/someModule', {
    '~/src/someDependency': fakeVersionOfSomeDependency
  });

... but proxyquire tells me `Error: Cannot find module '~/src/someModule'.

Presumably ("behind the scenes") Babel is converting '~/src/someModule' into its real path, so when Proxyquire looks for the aliased path it can't find it.

The Question

My question is: is there any way I can find out what the real path of '~/src/someModule' is, after Babel converts it (ie. when proxyquire deals with it)? Or alternatively is there any way to get proxyquire to just work with the aliased paths?


Solution

  • It turns out the "real" path (for '~/someModule') generated by module resolver is just the ../../someModule path. However, it also turns out that there is no need to convert paths by hand.

    The module resolver plug-in will convert the arguments to any functions on its transformFunctions list. This means that you can convert any string to its non-aliased form by doing the following:

    1. Define a simple passthrough function, e.g. const resolveModulePath = path => path;
    2. Add that function (along with proxyquire) to the transformFunctions list in .babelrc:

      ["module-resolver", {
        "transformFunctions": ["proxyquire", "resolveModulePath"]
      }]

    3. Wrap any paths which aren't arguments to a function with resolveModulePath:

      proxyquire('~/some/path/someModule', {
        [resolveModulePath('~/some/other/path')]: {
          someFunction: fakeSomeFunction
        }
      })

    Note that the first path in the above doesn't need to be escaped, as its an argument to a transformed function. Only the second path ('~/some/other/path') needs to be wrapped, because it's part of an object which is an argument; the string itself isn't an argument, until it's wrapped.

    For further info see: https://github.com/tleunen/babel-plugin-module-resolver/issues/241#issuecomment-350109168