-
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Bug]: ReferenceError: Export 'emit' is not defined in module
from Jest internals during suite setup.
#15077
Comments
Update: I can work around the problem a bit more cleanly by putting this: process.emit = process.emit; in a file added to |
This PR is the result of like a day and a half of research, even though the actual effective diff is a single line, and a trivial-looking one at that! To wit: ```js process.emit = process.emit; ``` But what a difference it makes! See <jestjs/jest#15077>, which I filed on Jest, for the gory details.
This comment was marked as off-topic.
This comment was marked as off-topic.
This smells like a missing That said, I've run the provided reproduction command 10 times in a row without seeing a failure 😅 |
Would it help if we did the e.g. const allExports = Object.entries(required);
const exportNames = allExports.map(([name]) => name);
const module = new SyntheticModule(
['default', ...exportNames],
function () {
// @ts-expect-error: TS doesn't know what `this` is
this.setExport('default', required);
for (const [key, value] of allExports) {
// @ts-expect-error: TS doesn't know what `this` is
this.setExport(key, value);
}
},
// should identifier be `node://${moduleName}`?
{context, identifier: moduleName},
); that should at least make us internally consistent. I have no idea where |
Hmm, Seems there's a flag we can pass to have it not do such weird things. We already do, tho: jest/packages/jest-runner/src/runTest.ts Line 235 in 559449e
|
@danfuzz how can I run jest in your repository without going via your script? I wanna try debugging, but the layers of bash scripts is a bit much for me 😅 I just want a |
@SimenB Sorry! The repro instructions predated (by a couple hours) my checking in of the workaround. Give me a moment, and I'll try to put together a branch that still exhibits the problem. |
@SimenB Try this branch: https://github.com/danfuzz/lactoserv/tree/demo-jest-issue-15077 Note: If you're checking it out from a repo with a pre-existing build, do If the
If you want, I can also package up a pre-built tree for you to inspect and use. |
I tried to explain it above, but I guess I didn't do a good enough job: Unlike most core modules,
However, Jest installs My workaround works because I'm pre-emptively storing an "own" binding of |
Update: But in any case, this makes it less clear to me to what extent y'all want to consider it a Jest problem:
Thanks in advance and arrears for your help! [*] And, in case it's not clear, |
Update to the update: I'm not the first person to catch |
Turns out `pem`'s main export will install its own global `process.emit` source map handler, for who-the-muffin-knows-why. But in any case, (a) it shouldn't, but thankfully (b) it's at least possible to avoid it doing that. So this PR avoids the installation and adds a test to make sure it doesn't start happening again. FWIW I was a bit wary when I started using `pem` in the first place, and this experience makes me reluctant to leave it in, in the long term. See <Dexus/pem#389> and <jestjs/jest#15077> for more details. And thanks very much to @SimenB and @nwalters512 for their assistance.
Great you figured it out!
We can do that to at least avoid the weird disconnect
Node aren't interested in making that possible, unfortunately: nodejs/node#31852
I'd say libraries should never use |
If anybody comes to this issue for the "good first issue" label - this is what we want: #15077 (comment) Code is in jest/packages/jest-runtime/src/index.ts Lines 1774 to 1786 in 559449e
|
That's unfortunate :( . |
This PR is a compendium of miscellanea, following up on the last few days' worth of work. Notably, this PR removes our use of the `pem` module from NPM as a dependency, replacing it with `selfsigned`. TBQH the state of `pem` is consistent with being in the early stage of a "supply chain" attack. See <jestjs/jest#15077> and <Dexus/pem#389> for some history / details.
This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 30 days. |
Version
29.7.0
Steps to reproduce
./scripts/ubik run-tests --do=build CertUtil RequestDelay
Expected behavior
Both tests pass.
Actual behavior
With some regularity — but not 100% consistently — the
RequestDelay
test file will fail to load, with Jest writing this to the console:Additional context
Hi! First and foremost, I'm sorry that I haven't been able to distill this to a tiny example. But I hope I can make up for that lack by providing a lot of information about what's going on:
It turns out that that message is being reported by
_importCoreModule()
herejest/packages/jest-runtime/src/index.ts
Line 1771 in 559449e
setExport()
, which is on avm.SyntheticModule
(a Node core library class). The complaint amounts to this: When the module is constructed, the nameemit
was not included in the list ofexport
s, but when the callback came to provide all the exports, the code in fact tried tosetExport('emit', ...)
.The call to
_importCoreModule()
is being passednode:process
for themoduleName
, and indeed the core Nodeprocess
module does not directly defineemit
. However, it indirectly defines it by inheriting fromEventEmitter
. This isn't quite the crux of the problem, though it's related.The set of pre-declared exports is based on a call to
Object.keys()
on the module being wrapped, and the calls tosetExport()
are based on a call toObject.entries()
on the same object. These two methods behave identically with respect to inherited properties, skipping them. So, if the module being wrapped didn't change between the two calls, then everything would be okay.But it turns out that between the call to
Object.keys()
and the call toObject.entries()
, something is directly setting a newemit
property directly on theprocess
module, and that's the most-direct cause of the exception, because nowObject.entries()
is reporting a property that the earlierObject.keys()
didn't see. Near as I can tell, the actual value which was set is a transpiled version of theprocess.emit()
wrapper insource-map-support
, but I haven't yet been able to catch the system in the act of setting it.In the runs where the problem doesn't appear, I think
process.emit
gets set sometime after testing has started but simply (and fortuitously) not when a test is in the middle of loading/wrappingnode:process
specifically. The notable "feature" of the first test in the repro case (CertUtil
) is that it runs pretty slowly, which I'm guessing is significant; it runs slowly but doesn't tend to fail. I'm not sure why the second one (RequestDelay
) ends up being the consistent victim.I figured out that I can work around the problem by explicitly setting
required.emit = required.emit
in_importCoreModule()
when it's givennode:process
to import. However, I suspect that the right solution is to make sure that the patching of the real globalprocess
object happens before any test suites are even loaded.I should add: The failure often — but not always — gets accompanied by a second
ReferenceError
:Note that in this case the test suite in question never actually ran, and I believe that this additional error is happening because the main problem left the test suite in a bit of an inconsistent state.
I hope this helps!
PS: Before I filed this report, I tried asking on the suggested Discord server, but nobody responded.
Environment
The text was updated successfully, but these errors were encountered: