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

Feature-Request: support/instrument lazy requires #213

Closed
osher opened this issue Jul 20, 2017 · 6 comments · Fixed by #304
Closed

Feature-Request: support/instrument lazy requires #213

osher opened this issue Jul 20, 2017 · 6 comments · Fixed by #304

Comments

@osher
Copy link

osher commented Jul 20, 2017

The breaking change of lazy-require is a real game-changer, and for the worst.

My use cases are around data-driven system that load modules dynamically - which is a core concept in many of the system I work on: modules implement strategies, and are loaded dynamically on run-time, instead of loading everything on process startup - which could be a thousand of different strategy files.

Can you think of a way to do that?
Maybe a way to support an option to intercepts reads from node_modules, and pass them to the real fs?
Or exclude paths in general, regardless to node_modules?

If you can decide on a way you can do that - I can work on it and do the PR if that helps

@osher
Copy link
Author

osher commented Jul 20, 2017

From the docs:

The code below makes it so the fs module is temporarily backed by a mock file system with a few files and directories.

I can also propose to support a mode that instead make backed-by a mock files-system - make some paths on the real file-system shadowed by mocks by a provided pattern-set?
we can discuss if the pattern includes or excludes given paths, I'm open to anything and will love to work with you, really

@rprieto
Copy link

rprieto commented Nov 26, 2017

I agree, took me a while to figure out what was happening. It was a tests for a module that uses micromatch:

mock({
  'file.txt': 'hello'
})
// this is just a regex matcher, it doesn't use the file system at all.... or does it?
micromatch('file.txt', '*.txt')

The problem is that micromatch uses lazy-cache which requires packages on demand. The tests then fails with:

Error: ENOENT, no such file or directory 'node_modules/use/node_modules/define-property'

Unfortunately I have no control over that. I also can't restore() the filesystem before this happens, because the call to micromatch() is part of the function being tested.

Switching to mock-fs@3.x.x fixes the issue. I like the idea of passing-through any calls that reference ./node_modules. Note it's not just reads, it could be fs.stat etc. Another option could be a generic pass-through like:

mock({
  'file.txt': 'hello'
  'node_modules': mock.passthrough()
})

@rprieto
Copy link

rprieto commented Nov 26, 2017

Update: a workaround for version 4 is to ensure (if possible) that all dynamic modules are loaded before you start mocking the file system. This worked for me:

it('bootstraps micromatch', () => {
  // this will work because we haven't called mock() yet
  // and it loads all the packages we'll need later
  require('micromatch').match('file.txt', '**/**')
})

it('works now', () => {
  mock({
    'file.txt': 'hello'
  })
  micromatch('file.txt', '*.txt')
})
 

@noamokman
Copy link

Similar problem here,
Can't console.log in a jest test because it internally requires something.
Maybe we can add an option:

mock({
  'file.txt': 'hello',
}, {
     enableLazyLoad: true
});

@ronp001
Copy link

ronp001 commented Sep 3, 2018

I wrote a small utility that provides a slightly different workaround: it simplifies the copying of selected portions of the real filesystem into the mocked fs.

The downside is that, unlike the workaround by @rprieto, it doesn't import all dependencies automatically. The upside is that it gives you a lot of flexibility in what you copy to the mocked fs (doesn't have to be a package).

For example (in TypeScript):

import * as mockfs from 'mock-fs'
import { MockFSHelper, AbsPath } from "@ronp001/ts-utils"

let simfs = {
  'file.txt': 'hello',
}

// the helper copies contents from the real filesystem into the simfs definition
// must be called before activating mockfs()
const helper = new MockFSHelper(simfs)
helper.addDirContents(new AbsPath('./node_modules/callsites')) 

mockfs(simfs)

To use this you'll need @ronp001/ts-utils as a dependency:

yarn add --dev @ronp001/ts-utils

see here for a real-world example

@nonara
Copy link
Contributor

nonara commented Jul 27, 2020

Just a heads up - I believe #304 should alleviate people's frustrations.

We add the ability to automatically create dir/files from the filesystem, with options recursive and lazyLoad.
And as a bonus, there's a function to selectively bypass the mock system.

Have a look at the updated readme entries:

https://github.com/nonara/mock-fs#mapping-real-files--directories
https://github.com/nonara/mock-fs#bypassing-the-mock-file-system

Feel free to share your thoughts or questions!

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

Successfully merging a pull request may close this issue.

5 participants