Jest: `require.main` undefined with createRequire()

Created on 4 Sep 2020  ·  19Comments  ·  Source: facebook/jest

🐛 Bug Report

The require.main of modules that are required from within a test file is undefined, when:

  • those modules were required with a require created with createRequire
  • createRequire was given another module than the current one (observe how parent2.js works as expected)
  • the test file is run with Jest, not Node

Tested with Jest 26.4.2, Node v12.4.0

Why it's an issue

  • I want to use require.main.filename to get the name of the requiring file, as it would work in a node context.

Link to repl or repo (highly encouraged)

https://github.com/sguillia/jest-createRequire-repro

Expected behavior

All files are in the demo repo

child.js

console.log(require.main && require.main.filename)

parent2.js

const Module = require('module')

require = Module.createRequire(__filename)

// Node: Prints path of parent2.js
// Jest: Prints path of parent2.js
require('./child')

parent3.js

const Module = require('module')
const path = require('path')

require = Module.createRequire(path.resolve('./subfolder/sub.js')) // sub.js is empty file

// Node: Prints path of parent3.js
// Jest: Prints null
require('./child')
$ node parent2.js
<path>

$ jest parent2.js
<path>
$ node parent3.js
<path>

$ jest parent3.js
<path>

Actual behavior

$ node parent2.js
<path>

$ jest parent2.js
<path>
$ node parent3.js
<path>

$ jest parent3.js
null

envinfo

  System:
    OS: Linux 4.15 Ubuntu 16.04.7 LTS (Xenial Xerus)
    CPU: (12) x64 Intel(R) Core(TM) i7-8750H CPU @ 2.20GHz
  Binaries:
    Node: 12.4.0 - ~/.nvm/versions/node/v12.4.0/bin/node
    Yarn: 1.22.4 - ~/.nvm/versions/node/v12.4.0/bin/yarn
    npm: 6.14.8 - ~/.nvm/versions/node/v12.4.0/bin/npm
Bug Report Help Wanted

All 19 comments

Happy to take a PR fixing this! Might be just a matter of adding a parent in here?

hey @jeysal, Can I try to fill a PR for this ?

@mohamedsgap sure!

@jeysal I'd love to give it a shot! May I go ahead?

Yep!

I'm trying to add a parent key to the object you suggested here however I get this message saying parent is deprecated:
@deprecated — since 14.6.0 Please use require.main and module.children instead. Should I continue?

@flozender Is that a TypeScript warning? If so, that should be fine.

@jeysal Yes, it is a TypeScript error. My approach is to create a parent module, assign the keys manually, and attach it to the object since the only parameter available to me is modulePath inside of the createRequire function. Is this a viable approach? Thanks for your support.

Hmm, looking at it again, it doesn't seem so simple anymore. createRequire has absolutely no context at the moment, so I'm not sure where to derive either a parent or a main from ... I wonder how Node does this

@jeysal I will try to find out, but if you come across something please let me know. :)

It seems they are 'cheating' with an effectively global variable process.mainModule

How do you suggest I go about this? Should I try to emulate what they're doing?

So for us that would mean dropping the current main in logic jest-runtime that traverses parents, and instead somehow get the module of the test file currently being executed. I'm not yet sure how to figure that out ...

The currently executing test file is in the environment options, but the environment doesn't expose it.
It's in the cacheFS as the only initial entry, but that's "conincidence".
We could throw it on process in jest-runner like Node does.
We could pass it into the runtime in jest-runner.

None of those seem like great options. @SimenB ideas?

I'm down with passing it in in jest-runner when instantiating the runtime. Getting rid of the current recursion for parent would be nice as well.

require.main is the same regardless of being "normal" require or as the result of createRequire?

We should probably populate process.mainModule as well, fwiw

I'd like to help with this, what would be a good starting point?

Other than the jest-runtime index.ts you've already looked at, the place where jest-runner instantiates a new Runtime will be affected :) you can start from those places and should be able to see what changes need to be made :upside_down_face:

You wanna pass the path fo the test file (https://github.com/facebook/jest/blob/c808901f5ddfcbf8be924c850bd757d3ae720876/packages/jest-runner/src/runTest.ts#L79) into the runtime here: https://github.com/facebook/jest/blob/c808901f5ddfcbf8be924c850bd757d3ae720876/packages/jest-runner/src/runTest.ts#L154-L162

then store it on the instance of the runtime, and use that as main

Thanks!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ianp picture ianp  ·  3Comments

paularmstrong picture paularmstrong  ·  3Comments

StephanBijzitter picture StephanBijzitter  ·  3Comments

kgowru picture kgowru  ·  3Comments

jardakotesovec picture jardakotesovec  ·  3Comments