Closed osher closed 4 years ago
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
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()
})
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')
})
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
});
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
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!
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