tschaub / mock-fs

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

createReadStream causes ENOENT when unit tests are run in jest #382

Open crasu opened 10 months ago

crasu commented 10 months ago

While debugging an issue in my tests I converted this unit test from spec to jest:

describe('fs.createReadStream(path, [options])', function () {
    beforeEach(function () {
      mock({
        'dir/source': 'source content',
      });
    });
    afterEach(mock.restore);

    test('creates a readable stream', function (done) {
      const stream = fs.createReadStream('dir/source');
      done();
    });
});

I get the following error message when running with spec:

Error: ENOENT: no such file or directory, open 'dir/source'
Emitted 'error' event on ReadStream instance at:
    at emitErrorNT (node:internal/streams/destroy:151:8)
    at emitErrorCloseNT (node:internal/streams/destroy:116:3)
    at processTicksAndRejections (node:internal/process/task_queues:82:21) {
  errno: -2,
  code: 'ENOENT',
  syscall: 'open',
  path: 'dir/source'
}

I am running node 18.18.2.

Does anyone understand why this works with spec but not with jest? Wrapping this in setTimeout(.., 0) works.

isocroft commented 1 month ago

Hello @crasu ,

You seem to be doing it wrong i guess

This is how it (mock-fs) should be setup:

describe('fs.createReadStream(path, [options])', function () {
    beforeEach(function () {
      mock({
        'dir': {
                  'source.txt': 'source content'
               }
      });
    });
    afterEach(mock.restore);

       const readTextFileStream = (file) => {
           const result = [];
           return new Promise((resolve, reject) => {
            fs.createReadStream(file)
              .on("data", (data) => {
                 result.push(data);
               }).on("end", () => {
                   resolve(result.join(''))
               }).on("error", reject);
             });
        };

    test('creates a readable stream', async function (done) {
      const stream = await readTextFileStream('./dir/source.txt')
      done();
    });
});
crasu commented 2 weeks ago

@isocroft Thank you for answering this. Why do I need to wrap fs.createReadStream in a promise? This is very similar to wrapping this in setTimeout(.., 0). Why does this work in spec?