streamich / memfs

JavaScript file system utilities
http://streamich.github.io/memfs/
Apache License 2.0
1.76k stars 129 forks source link

Resolve a path as not found #110

Closed ianwalter closed 5 years ago

ianwalter commented 6 years ago

This is amazing and works really well for testing because it allows you to mock the filesystem while falling back to the actual filesystem when a path hasn't been mocked, especially for requires:

ufs
  .use({ ...fs })
  .use(vol)

But there doesn't seem to be a way to add a file in memfs so that it is mocked and doesn't fall back to the actual filesystem (so it will not be overwritten when tests run) but also does not show up as existing when calling something like fs.existsSync('foo.txt'). I would like to propose allowing a user to set a path to something, maybe undefined, to achieve this:

// foo.txt resolves when performing the lookup but still throws an error when being read 
// as if it doesn't exist.
const vol = Volume.fromJSON({ 'foo.txt': undefined })  

If you use undefined, you'll have to be careful not to run into the specification of a directory using null that you added today (thanks again).

I hope this doesn't sound too much like an edge case. I think it's pretty important for use in testing.

pizzafroide commented 6 years ago

I'm not sure to understand this use case quite well, but I think what you want to do is made possible by spyfs.

import fs from 'fs';
import { vol, fs as memfs } from 'memfs';
import { ufs } from 'unionfs';
import { spy } from 'spyfs';

vol.fromJSON({
  '/foo': 'bar',
});

ufs.use(fs).use(memfs);

const sfs = spy(ufs, ({ method, args, resolve, reject }) => {
  if (args[0] === '/foo') {
    if (method === 'existsSync') resolve(true);
    else reject(new Error("Can't touch this!"));
  }
});

console.log('existsSync:', sfs.existsSync('/foo'));
try {
  console.log('readFileSync:', sfs.readFileSync('/foo'));
} catch (e) {
  console.error('readFileSync error:', e.message);
}

The code above will output:

existsSync: true
readFileSync error: Can't touch this!

Is that what you expected?

ianwalter commented 5 years ago

@pizzafroide Yes, I think it is. Thanks for your help!