Skip to content
New issue

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

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

Already on GitHub? Sign in 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!

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

Successfully merging a pull request may close this issue.

5 participants