Problem using console.log with jest and mock-fs
kristianmandrup opened this issue · comments
When using mockFS in a jest test suite, as soon as I add a console.log
anywhere, it breaks with the following:
ENOENT, no such file or directory '/Users/kristianmandrup/repos/project-maker/package-retriever/node_modules/callsites'
38 |
39 | it('tests', () => {
> 40 | console.log('hello')
41 | })
42 |
43 | it('collects files from each path', async () => {
at Binding.<anonymous> (node_modules/mock-fs/lib/binding.js:1060:13)
at maybeCallback (node_modules/mock-fs/lib/binding.js:42:17)
at Binding.Object.<anonymous>.Binding.lstat (node_modules/mock-fs/lib/binding.js:1057:10)
at Object.it (__tests__/collect/collect-files.test.ts:40:13)
Even if I install the callsites
module/package, it still comes out with this strange error!
What could be the cause??
I have started on an overlay
option that should address this problem. Until this is ready, a workaround is to call console.log()
before mocking the filesystem.
Thanks @tschaub, in the meantime I've tried with a jest mock FS plugin, but it suffered from other issues... So looking forward to use an overlay option with this mature lib :)
I am also experiencing this issue. How is the overlay
option coming?
@kristianmandrup if you add the file and directory that it says it can't find to your mock fs then it works for me.
Possible workaround
const fsMock = require('mock-fs')
let logsTemp = []
let logMock
exports.mock = (config) => {
logMock = jest.spyOn(console, 'log').mockImplementation((...args) => {
logsTemp.push(args)
})
fsMock(config)
}
exports.restore = () => {
logMock.mockRestore()
fsMock.restore()
logsTemp.map(el => console.log(...el))
logsTemp = []
}
Any update on this issue?
Any updates here?
Nothing from me on this. I have not continued work on the overlay
option I mentioned above.
Any updates?
Using
process.stdout.write(message + '\n')
doesn't have this problem.
Wow, this had me stumped for almost a full day. Here's the specific error I got, in case it helps match others' search terms.
ENOENT: no such file or directory, lstat '/home/user/foo/node_modules/@jest/source-map/node_modules'
at _callsites (../../node_modules/@jest/source-map/build/getCallsite.js:19:39)
I wound up working around this by writing a simplified version of console, so that test writers can continue to habitually use console.log, and avoiding the cognitive load of having to remember where it's safe to use console.log and where it isn't.
mocks/console.js
function format(entry) {
if (typeof entry === "object") {
try {
return JSON.stringify(entry);
} catch (e) {}
}
return entry;
}
function log(...msgs) {
process.stdout.write(msgs.map(format).join(" ") + "\n");
}
module.exports = {
log,
warn: log,
error: log
};
And "install" it:
global.console = require("./__mocks__/console");
Any updates?
By the look of #142, the overlay option is still a work in progress
For those of you who are using Jest, memfs might be a good alternative for mocking fs
. You can create a __mocks__/fs.js
file:
const { fs } = require('memfs')
module.exports = fs
then in your tests:
const fs = require('fs')
const myFn = require('../my-fn')
jest.mock('fs')
afterEach(() => {
fs.reset()
})
describe('myFn', () => {
it('does something with files', () => {
fs.fromJSON({
// files to create
})
myFn()
// assertions
})
})
@silvenon An even shorter version for mocking fs with memfs (no need for a separate manual mock file):
import fs from 'fs';
jest.mock('fs', () => require('memfs').fs);
it('works', () => {
const data = fs.readFileSync('foo');
// ...
});
That will only work for that file, though, so it depends on what you want 😉
Other work around that I have come up with (if like me you don't like random output) is to add the following line before mockFs
is called:
console = new Console(process.stdout, process.stderr)
I have the same issue, because I am using lstat
in my code.
This is a great solution if you only want to mock a specific folder while having access to the rest of the normal filesystem: streamich/fs-monkey#139 (comment) I haven't had any issues with sourcemaps or logging in my tests since switching to this method