tschaub / mock-fs

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

Bug: malfunction with dynamic require() #312

Open erbhargavvyas opened 3 years ago

erbhargavvyas commented 3 years ago

With mock-fs if I create a mock file system it still seeks the actual disk for the dynamic require statement. The malfunction (or inconsistency) is if the "path" is actually present on the filesystem, then it reads from the mocked file system.

Take the below example. If any one foo.json is missing (from actual disk or from mockFs() ) then it fails. But it reads the mocked one, i.e. it prints 10.

expectation The expectation is after mocking, it should not seek the actual file system for the require(). And if that is not possible then the require() should load from the disk only and not from the mocked one.

The following is my project structure

/mockfsdemo |-index.js |-rules |-foo.json

And the following are my files.


foo.json

{
    "foo": "100"
}


index.js

const mockFs = require("mock-fs");
const fs = require("fs");
const path = require("path");

mockFs({
    rules: {
        "foo.json": '{"foo":10}',
    },
});

var m = require(path.join(process.cwd(), "rules", "foo.json"));
console.log(m);

3cp commented 3 years ago

The expectation is after mocking, it should not seek the actual file system for the require()

It looks to me the result is inline with the expection. Is not that exactly what you are seeing: the mocked 10 instead of 100?

3cp commented 3 years ago

About require() checking real file, regardless whether you have a mock, I recall the issue has been raised before. The require() uses some internal nodejs API to check existence of the module, not through those fs APIs we mocked.

erbhargavvyas commented 3 years ago

No, the result is not as per expectation. Either of the following would be expected.

Option 1: the require() loads from the mocked FS irrespective of the file available or not on the disk.

Option 2: the require() seeks and loads from the actual file system only and this library can state that it does not support 'require()'.

The current behavior is mixed and hence confusing that it loads from the mocked fs but the file has to be available on real fs.

tlouisse commented 3 years ago

In case it helps anyone: this is what you can do when both require (via mock-require) and fs need to be mocked:

const mockFs = require('mock-fs');
const mockRequire = require('mock-require');

function mock(obj) {
  mockFs(obj);

  Object.entries(obj).forEach(([key, value]) => {
    if (key.endsWith('.json')) {
      mockRequire(key, JSON.parse(value));
    } else {
      mockRequire(key, value);
    }
  });
}

mock.restore = () => {
  mockFs.restore();
  mockRequire.stopAll();
};

Inside your test, you would run:

mock({
    '/path/to.json': "{ "mocked": "data" }",
})

and:

mock.restore()