Code Monkey home page Code Monkey logo

Comments (14)

danfuzz avatar danfuzz commented on June 18, 2024 1

Update to the update: I'm not the first person to catch pem messing with Jest: Dexus/pem#389

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

Update: I can work around the problem a bit more cleanly by putting this:

process.emit = process.emit;

in a file added to setupFilesAfterEnv in the Jest config.

from jest.

unprolix avatar unprolix commented on June 18, 2024

boggle at that workaround.

from jest.

SimenB avatar SimenB commented on June 18, 2024

This smells like a missing await somewhere πŸ€”

That said, I've run the provided reproduction command 10 times in a row without seeing a failure πŸ˜…

from jest.

SimenB avatar SimenB commented on June 18, 2024

Would it help if we did the Object.keys and Object.entries at the same time at the top rather than doing the entries one lazily?

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 emit comes from tho - it's not part of node:process (https://nodejs.org/api/process.html), so something is seemingly messing with it from somewhere.

from jest.

SimenB avatar SimenB commented on June 18, 2024

Hmm, source-map-support does indeed add process.emit like you say: https://github.com/evanw/node-source-map-support/blob/7b5b81eb14c9ee6c6537398262bf7dab8580621c/source-map-support.js#L602-L612

Seems there's a flag we can pass to have it not do such weird things. We already do, tho:

handleUncaughtExceptions: false,

from jest.

SimenB avatar SimenB commented on June 18, 2024

@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 node node_modules/.bin/jest CertUtil RequestDelay (maybe with a --config or something if that's something you use)

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

@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.

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

@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 rm -rf out/tester first, because the build script isn't smart enough to notice that the test harness has changed (since it rarely does).

If the run-tests script is getting in the way of your flow, you can do a separate build and then call jest more directly:

$ ubik dev build
[... build build build ...]
$ rm -rf out/tester
$ ubik run-tests
[... let it build the tester then ...]
^C
$ out/tester/bin/jest --config=/...wherever/lactoserv/src/jest.config.mjs CertUtil RequestDelay
[...]
ReferenceError: You are trying to `import` a file after the Jest environment has been torn down. From code/node_modules/@this/webapp-builtins/tests/RequestDelay.test.js.


 FAIL  out/lactoserv/lib/code/node_modules/@this/webapp-builtins/tests/RequestDelay.test.js
  ● Test suite failed to run

    ReferenceError: Export 'emit' is not defined in module

      at ../../tester/lib/node_modules/jest-runtime/build/index.js:1554:16
          at Array.forEach (<anonymous>)

If you want, I can also package up a pre-built tree for you to inspect and use.

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

I have no idea where emit comes from tho - it's not part of node:process
(https://nodejs.org/api/process.html), so something is seemingly messing with it from somewhere.

I tried to explain it above, but I guess I didn't do a good enough job:

Unlike most core modules, node:process has a nontrivial prototype. Instead of being (more or less) a plain object, it (indirectly) inherits from EventEmitter:

$ node
> process.emit
[Function: emit]
> Object.getPrototypeOf(process)
EventEmitter {}
> Object.hasOwn(process, 'emit')
false
> Object.hasOwn(Object.getPrototypeOf(process), 'emit')
false
> Object.hasOwn(Object.getPrototypeOf(Object.getPrototypeOf(process)), 'emit')
true

Object.keys() and Object.entries() only return the "own" properties of an object, and so process.emit doesn't show up for those… under normal circumstances.

However, Jest installs source-map-support, which does directly store a replacement / override for process.emit directly in the process object. When the error occurs, this installation happens after the Object.keys() in _importCoreModule() but before the Object.entries(). So, the former doesn't list emit, while the latter does. And boom!

My workaround works because I'm pre-emptively storing an "own" binding of emit on process before Jest tries to do much of anything. Eventually source-map-support does its thing and overwrites what the workaround did. The reason this isn't (in effect) a true fix is that it's still the case that source-map-support only manages to do its patching sometime after testing has started. So, if there's a test failure early enough with a test that uses code that came with a source map, the line numbers would be off in the error report.

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

Update: source-map-support in Jest is a red herring. I had looked at my own project dependencies to verify that I wasn't including it before, but I failed to notice that one of my dependencies β€” pem[*] β€” "secretly" bundles it into itself (which is why what I found was a transpiled version of it). That's arguably pretty bad behavior for what should be a little self-contained module (and I will aim to stop it from happening; its bad behavior affects my system when not under test).

But in any case, this makes it less clear to me to what extent y'all want to consider it a Jest problem:

  • It's still the case that modifying a Node core module in the middle of a test can mess the Jest runner up, and (as was suggested above) calling Object.entries() and using that one result to derive the keys to pass to SyntheticModule would avoid the particular blow-up.

  • But also, this is a case of surprising cross-test interference. If Jest is trying to guarantee that each test runs in a pristine global environment, there is something worth addressing here.

Thanks in advance and arrears for your help!

[*] And, in case it's not clear, CertUtil is the only class in my system which imports pem.

from jest.

SimenB avatar SimenB commented on June 18, 2024

Great you figured it out!

  • It's still the case that modifying a Node core module in the middle of a test can mess the Jest runner up, and (as was suggested above) calling Object.entries() and using that one result to derive the keys to pass to SyntheticModule would avoid the particular blow-up.

We can do that to at least avoid the weird disconnect

  • But also, this is a case of surprising cross-test interference. If Jest is trying to guarantee that each test runs in a pristine global environment, there is something worth addressing here.

Node aren't interested in making that possible, unfortunately: nodejs/node#31852

Update to the update: I'm not the first person to catch pem messing with Jest: Dexus/pem#389

I'd say libraries should never use support-source-maps - it's an application or runtime thing to ensure source maps are loaded if that's something they care about.

from jest.

SimenB avatar SimenB commented on June 18, 2024

If anybody comes to this issue for the "good first issue" label - this is what we want: #15077 (comment)

Code is in

const module = new SyntheticModule(
['default', ...Object.keys(required)],
function () {
// @ts-expect-error: TS doesn't know what `this` is
this.setExport('default', required);
for (const [key, value] of Object.entries(required)) {
// @ts-expect-error: TS doesn't know what `this` is
this.setExport(key, value);
}
},
// should identifier be `node://${moduleName}`?
{context, identifier: moduleName},
);

from jest.

danfuzz avatar danfuzz commented on June 18, 2024

Node aren't interested in making that possible, unfortunately: nodejs/node#31852

That's unfortunate :( .

from jest.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.