5

I am working on a NodeJS (v. 8.12.0, EcmaScript 6) project, whose project structure is similar to:

project_root/
    src/
        utils/
            protocol_messages/
                helpers.js
    tests/
        unit/
            utils/
                protocol_messages/
                    helpers.js

I am writing tests using Mocha as a test framework.

Question
In the helpers.js under tests/unit/utils/protocol_messages/, what's the proper way of importing the module-under-test?

To elaborate:
I want to avoid the relative path in: require('../../../../../src/utils/protocol_messages/helpers').
It works, but it's ugly, and if the project structure changes, I would have to rewrite the test imports, as well.

(I am new to Javascript so I might be doing several things wrong.)

Update
Solutions provided in this question:

  1. require.main.require: in a comment to this answer, "This solution will not work if code covered with unit tests like Mocha test".
  2. Extracting my utils to a node module doesn't make sense for me, since the code is very application specific.
  3. Having an extra node_modules under my src/ project root of a NodeJS project doesn't seem to make sense.
  4. Using a Javascript transpiler when I am using only features available in NodeJS and writing CommonJS projects seems a bit of an overkill.

If I am mistaken on any of the above points, please point it out, as I am at a loss. It seems to me like NodeJS doesn't not provide a native way to import CommonJS modules with absolute paths.

Chris
  • 3,619
  • 8
  • 44
  • 64
  • Possible duplicate of [How to make node.js require absolute? (instead of relative)](https://stackoverflow.com/questions/10860244/how-to-make-node-js-require-absolute-instead-of-relative) and possible answer [here](https://stackoverflow.com/questions/10860244/how-to-make-node-js-require-absolute-instead-of-relative/47265728#47265728) – Troopers Sep 24 '18 at 12:05
  • @Troopers Hey, I've addressed the possible duplicate with some comments – Chris Sep 24 '18 at 13:09
  • [In my answer](https://stackoverflow.com/questions/10860244/how-to-make-node-js-require-absolute-instead-of-relative/47265728#47265728), `babel` is not used as transpiler (excepted if you want use the es6 module syntax) it is only used as loader with `babel-plugin-module-resolver` to resolve path – Troopers Sep 24 '18 at 13:19
  • So you mean that using `babel` with `babel-plugin-module-resolver` will not change my code at all, and thus will not generate any more Javascript files? Also, if that's the case, i.e. that this plugin will simply enhance `babel`, I would have to run my project with `babel` instead of `node` right? – Chris Sep 24 '18 at 13:38
  • You can use [babel-register](https://babeljs.io/docs/en/babel-register) to compile on the fly instead of use babel as transpiler in build time. Your last question has no sense : `babel` is a transpiler and `node` a runner. Your project run always on `node` but the source code is different if you use `babel` – Troopers Sep 24 '18 at 14:02
  • You could use `require(\`${process.cwd()}/src/utils/protocol_messages/helpers\`);` in _helpers.js_ under `tests/unit/utils/protocol_messages/`. However, this assumes your current working directory is `project_root` when you invoke your mocha tests because [`process.cwd()`](https://nodejs.org/api/process.html#process_process_cwd) returns the current working directory. – RobC Sep 24 '18 at 14:49
  • _"...if the project structure changes, I would have to rewrite the test imports, as well"_ - that unfortunately cannot be avoided, however the suggestion in my previous comment does allow the test `.js` files in the `test` directory to be restructured. – RobC Sep 24 '18 at 15:15

2 Answers2

1

You can use wavy npm package.

This module lets you turn things like require('../../../../foo') into something like require('~/foo'). The way it works is that on postinstall it creates a symlink in app/node_modules/~ to point to app/

Rafal Enden
  • 3,028
  • 1
  • 21
  • 16
1

Assume you need a config.js file present at your project's root in a file which is present at /routes/api/users/profile.js, you do not want to import it as ../../../config.js

  1. Create a directory structure in your project's root directory as described below:
    • /Modules
      • index.js
      • package.json
  2. Modules/index.js
    module.exports.config = require('../config.js')
    
  3. Modules/package.js
    {
        "name": "modules",
        "main": "index.js",
        "version": "1.0.0",
        "dependencies": {}
    }
    
  4. Now run
    npm install ./Modules
    
  5. /routes/api/users/profile.js
    const { config } = require('modules')
    

This way autocomplete feature of your code editor will also work. No more global variables pollution, long relative imports, no dependency on environment variables and the best part is, it will work with pm2 and nodemon.

Kaan
  • 5,434
  • 3
  • 19
  • 41