Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

Helper to bypass mock FS & expose real files/directories #304

Merged
merged 31 commits into from
Aug 9, 2020
Merged

Helper to bypass mock FS & expose real files/directories #304

merged 31 commits into from
Aug 9, 2020

Conversation

nonara
Copy link
Contributor

@nonara nonara commented Jul 27, 2020

Adds two new features:

  1. mock.bypass() - Allows executing commands against the actual FS

  2. mock.load() -
    Reads the filesystem to map actual files and directories from the filesystem

    Options: recursive, lazyLoad

    • If lazyLoad is true, file content isn't loaded until they're explicitly read. (keeps memory usage low, making it feasible to load large filesystems)

See readme for more detail

closes #62
closes #213
(possibly others?)

@nonara
Copy link
Contributor Author

nonara commented Jul 27, 2020

Will update README tomorrow and @types/mock-fs as soon as it the PR is approved. Would appreciate a comment to let me know it's been / being reviewed.

Thanks!

- Lazy-loaded files were not able to be written to if they hadn't been read yet
- Descriptors defaulted to writable: false after setting value
- Included mock.createDirectoryInfoFromPaths()
- Included mock.bypass()
@nonara
Copy link
Contributor Author

nonara commented Jul 27, 2020

This can be considered complete (unless changes requested)

Recent updates:

  • Made automatically created directories inherit stats.
    • This lead to discovering an issue with windows permissions. (See my code comment above for detail)
  • Updated readme
  • Made sure non-lazy-loaded files inherit stats

lib/index.js Outdated Show resolved Hide resolved
readme.md Outdated Show resolved Hide resolved
- Added mock.mapFile(), mock.mapDir(), and mock.mapPaths()
- Created improved tests for the new methods (comparing stats with real files, etc)
@nonara
Copy link
Contributor Author

nonara commented Jul 28, 2020

Ok! I think you'll find the new API much more intuitive and flexible! I believe the new readme should be easy to understand, as well.

We now have three new mapper methods: mock.mapPaths(), mock.mapDir(), and mock.mapFile().

I re-wrote everything which also allowed for better tests & better overall architecture.

@nonara nonara changed the title mock.bypass, mock.createDirectoryInfoFromPaths, lazyLoading Helper to bypass mock FS & add expose real files/directories Jul 28, 2020
@nonara
Copy link
Contributor Author

nonara commented Aug 4, 2020

Updated according to last review:

  • Remove enable, disable from exports
  • Add promise support to mock.bypass()
  • Merge mapDir() and mapFile() functions to load()
  • Remove mapPaths()
  • Use path.basename (May affect cygwin, but Linux allows backslashes in filename, which takes precedence)
  • Remove custom error message for non-string parameter to load()
  • Updated tests to accommodate changes
  • Updated readme according to suggestions

Note

mock.bypass() is built to work with Promises, however, async callback functions won't work. That was part of the idea behind enable, disable.

Is this acceptable? Would you like to alter the readme or handle it somehow?

@nonara
Copy link
Contributor Author

nonara commented Aug 4, 2020

Investigating the TypeError with Buffer in Windows Node 12, now. At a bit of a loss on this. I can't see how any changes would have affected that. Will debug offline.

@3cp
Copy link
Collaborator

3cp commented Aug 4, 2020

mock.bypass() is built to work with Promises, however, async callback functions won't work. That was part of the idea behind enable, disable.

I am quite sure your new implementation supports await mock.bypass(async () => {...});, which you can add to unit tests.
Async return value is a promise.

lib/bypass.js Outdated Show resolved Hide resolved
@nonara
Copy link
Contributor Author

nonara commented Aug 4, 2020

I am quite sure your new implementation supports await mock.bypass(async () => {...});, which you can add to unit tests.
Async return value is a promise.

Should clarify - I'm referring to fs functions which utilize callbacks, like fs.stat(). Any further fs access within the callback would not work.

@nonara
Copy link
Contributor Author

nonara commented Aug 4, 2020

I just checked out the current source from upstream master and confirmed that the buffer TypeError is happening on Windows for Node 12.

TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer

@3cp
Copy link
Collaborator

3cp commented Aug 4, 2020

For the buffer thing, can you find the exact line?

Nodejs fs APIs support string/buffer on path, for example in the doc:

fs.access(path[, mode], callback)[src]#

History
path <string> | <Buffer> | <URL>

But Nodejs path APIs only support string.

path.basename(path[, ext])#

History
path <string>

This means if you forward a path got from a fs API to a path API, you need to take care of the buffer thing. I believe you can find there are some treatments in the existing code.

@nonara
Copy link
Contributor Author

nonara commented Aug 4, 2020

It's in regard to fs.symlink() and is happening on master. I don't have a Windows Node 12 environment setup, I just created a new branch to test GH Actions to verify that is was not related to this PR

Error:

  1) fs.symlink(srcpath, dstpath, [type], callback)
       supports Buffer input:
     TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be of type string. Received an instance of Buffer
      at validateString (internal/validators.js:120:11)
      at Object.isAbsolute (path.js:353:5)
      at preprocessSymlinkDestination (internal/fs/utils.js:317:18)
      at Object.symlink (fs.js:1073:19)
      at Context.<anonymous> (test\lib\fs.link-symlink.spec.js:192:8)
      at processImmediate (internal/timers.js:456:21)

Originating code:

https://github.com/tschaub/mock-fs/blob/master/test/lib/fs.link-symlink.spec.js#L191-L204

@3cp
Copy link
Collaborator

3cp commented Aug 4, 2020

I see, could be a regression related to latest nodejs v12.18.3.

@3cp
Copy link
Collaborator

3cp commented Aug 4, 2020

Confirmed it's a win32 only regression in latest nodejs v12, I will try to investigate.

I think we can ignore that failure in this PR.

@nonara nonara requested a review from tschaub August 5, 2020 19:00
@nonara
Copy link
Contributor Author

nonara commented Aug 9, 2020

@3cp How'd it go? Any luck on determining a solution?

@3cp
Copy link
Collaborator

3cp commented Aug 9, 2020

I have not spent time on the win32 problem yet. Will do in coming week.

Copy link
Owner

@tschaub tschaub left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this great contribution @nonara.

I'll follow up with a separate pull request to address the additional comments.

const res = fn();

// Handle promise return
if (typeof res.then === 'function') {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will throw a TypeError if fn returns null or undefined.

// Handle promise return
if (typeof res.then === 'function') {
res.then(exports.enable);
res.catch(exports.enable);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This would be better handled with res.finally(exports.enable).

return res;
} catch (e) {
exports.enable();
throw e;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be in a finally block.


| Option | Type | Default | Description |
| --------- | ------- | ------- | ------------
| lazyLoad | boolean | true | File content isn't loaded until explicitly read
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this could just be called lazy - avoiding a bit of repetition: load(dir, {lazy: true}).

@tschaub tschaub merged commit ee50c67 into tschaub:master Aug 9, 2020
@tschaub tschaub mentioned this pull request Aug 9, 2020
@nonara
Copy link
Contributor Author

nonara commented Aug 9, 2020

Thanks for this great contribution @nonara.

Sure thing! Thanks for taking the time to review.

@3cp
Copy link
Collaborator

3cp commented Aug 9, 2020

The win32 issue is indeed a regression in nodejs code base. I will create a PR or issue there.

@3cp
Copy link
Collaborator

3cp commented Aug 9, 2020

The win32 issue is fixed in nodejs, but not patched in v12 yet. nodejs/node#34514

@harryhorton
Copy link

Any idea when this will be released? Working on a project that could really use it ❤️

@3cp
Copy link
Collaborator

3cp commented Aug 10, 2020

There are some edge cases to be cleaned up (#306 (comment)). I will PR the fix shortly after merging #303.

@dqisme
Copy link

dqisme commented Aug 19, 2020

Hi, thanks for this wonderful upgrade
when will we have this feature in the next release, please?

travi added a commit to form8ion/project that referenced this pull request Aug 22, 2020
travi added a commit to form8ion/project that referenced this pull request Aug 22, 2020
travi added a commit to form8ion/javascript-scaffolder that referenced this pull request Aug 23, 2020
@frederikheld
Copy link

@nonara Many thanks for your effort! That's a great addition to mockFs that will make testing much easier :-)

@nonara
Copy link
Contributor Author

nonara commented Jan 3, 2021

@frederikheld You're very welcome. Thank you for the kind comment!

# for free to join this conversation on GitHub. Already have an account? # to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Feature-Request: support/instrument lazy requires Mount a path to a real directory in the file system?
6 participants