tschaub / mock-fs

Configurable mock for the fs module
https://npmjs.org/package/mock-fs
Other
906 stars 86 forks source link

Using mock-fs with Jest results in open handles #341

Closed jloleysens closed 2 years ago

jloleysens commented 2 years ago

Hello!

When using mock-fs in combination with jest an open handle FSREQCALLBACK is created which (potentially) prevents Jest from exiting cleanly. This can be detected using jest --detectOpenHandles (docs). This seems to happen at import/require of mock-fs, not when calling mockFs() to actually mock the fs.

The following is output from Jest:

yarn jest my.test.js --detectOpenHandles
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.328 s
Ran all test suites matching /my.test.js/i.

Jest has detected the following 1 open handle potentially keeping Jest from exiting:

  ●  FSREQCALLBACK

    > 1 | const mockFs = require('mock-fs');
        |                                                                           ^
      2 |
      3 |
      4 | test('nothing', () => {});

      at Object.<anonymous>.exports.getReadFileContextPrototype (node_modules/mock-fs/lib/readfilecontext.js:22:6)
      at Object.<anonymous> (node_modules/mock-fs/lib/index.js:57:34)
      at Object.<anonymous> (my.test.js:1:98)
      at TestScheduler.scheduleTests (node_modules/@jest/core/build/TestScheduler.js:333:13)
      at runJest (node_modules/@jest/core/build/runJest.js:401:19)
      at _run10000 (node_modules/@jest/core/build/cli/index.js:320:7)
      at runCLI (node_modules/@jest/core/build/cli/index.js:173:3)
Minimal example to reproduce ```js // my.test.js const mockFs = require('mock-fs'); test('nothing', () => {}); ```

Any advice on how this might be avoided/worked around would be greatly appreciated! Thanks in advance!

3cp commented 2 years ago

There are quite few known issues with jest+mock-fs, you can find some in this repo's issues. As jest also modifies nodejs internals quite a lot, it's not surprising it doesn't play well with mock-fs which modifies fs internals too.

Personally I would avoid using jest and mock-fs together.

jloleysens commented 2 years ago

OK, upon slightly closer inspection it looks like it has something to do with how the readfile context is collected exports.getReadFileContextPrototype and the call to fs.readFile('/ignore.txt.... Which I don't think is specific to Jest.

The following change (calling the original open binding in addition to grabbing the proto) seems to fix the issue.

diff --git 1/readfilecontext2.js 2/readfilecontext.js
index 4bd66ee..f876db8 100644
--- 1/readfilecontext2.js
+++ 2/readfilecontext.js
@@ -17,6 +17,7 @@ exports.getReadFileContextPrototype = function() {
   let proto;
   fsBinding.open = (_path, _flags, _mode, req) => {
     proto = Object.getPrototypeOf(req.context);
+    originalOpen.apply(fsBinding, [_path, _flags, _mode, req])
   };

   fs.readFile('/ignored.txt', () => {});

Is this an acceptable change?

3cp commented 2 years ago

That looks like a good solution to bypass the jest issue. Pls fire a PR, thx.