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

Problem using console.log with jest and mock-fs #234

Open
kristianmandrup opened this issue Mar 5, 2018 · 20 comments
Open

Problem using console.log with jest and mock-fs #234

kristianmandrup opened this issue Mar 5, 2018 · 20 comments

Comments

@kristianmandrup
Copy link

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??

@tschaub
Copy link
Owner

tschaub commented Apr 2, 2018

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.

@kristianmandrup
Copy link
Author

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 :)

@taylorjdawson
Copy link

I am also experiencing this issue. How is the overlay option coming?

@taylorjdawson
Copy link

@kristianmandrup if you add the file and directory that it says it can't find to your mock fs then it works for me.

@Sujimoshi
Copy link

Sujimoshi commented Dec 13, 2018

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 = []
}

taktran added a commit to Financial-Times/nori that referenced this issue Feb 11, 2019
Need to wait for a logger to be implemented before we can carry on with
tests, due to tschaub/mock-fs#234
@RamzesTheSecond
Copy link

Any update on this issue?

@auser
Copy link

auser commented Jun 11, 2019

Any updates here?

@tschaub
Copy link
Owner

tschaub commented Jun 11, 2019

Nothing from me on this. I have not continued work on the overlay option I mentioned above.

@lwyj123
Copy link

lwyj123 commented Sep 18, 2019

Any updates?

@hongaar
Copy link

hongaar commented Nov 3, 2019

Using

process.stdout.write(message + '\n')

doesn't have this problem.

@mwcz
Copy link

mwcz commented Nov 5, 2019

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)

@mwcz
Copy link

mwcz commented Nov 8, 2019

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");

@elentok
Copy link

elentok commented Jan 14, 2020

Any updates?

@iamogbz
Copy link

iamogbz commented Apr 10, 2020

By the look of #142, the overlay option is still a work in progress

@silvenon
Copy link

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
  })
})

@dlindenkreuz
Copy link

@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');
  // ...
});

@silvenon
Copy link

silvenon commented Jul 4, 2020

That will only work for that file, though, so it depends on what you want 😉

@Nokel81
Copy link

Nokel81 commented Oct 5, 2020

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)

domharrington added a commit to readmeio/api that referenced this issue Feb 3, 2021
mock-fs has limitations which means you can use console.log during test runs
which is not ideal! Ended up doing something like this to get it to work:

tschaub/mock-fs#234 (comment)
erunion pushed a commit to readmeio/api that referenced this issue Feb 3, 2021
mock-fs has limitations which means you can use console.log during test runs
which is not ideal! Ended up doing something like this to get it to work:

tschaub/mock-fs#234 (comment)
@marikaner
Copy link

marikaner commented Feb 9, 2021

I have the same issue, because I am using lstat in my code.

erunion pushed a commit to readmeio/api that referenced this issue Mar 24, 2021
* refactor: switch to using memfs instead of mock-fs

mock-fs has limitations which means you can use console.log during test runs
which is not ideal! Ended up doing something like this to get it to work:

tschaub/mock-fs#234 (comment)

* feat: automatically parse the api response based on content-type

This allows us to remove the `.then(res => res.json())` line from our
code samples.

```
const sdk = require('api')('@readme/5f7ceacf43621b0311080a58');

sdk.getAPISpecification({perPage: '10', page: '1'})
  .then(res => console.log(res))
  .catch(err => console.error(err));
```

We only perform the parsing if it's a successful response. If there's an error
case then we return with the original response object so you can access
the status as well as the actual body.

The code and tests for this have been stolen verbatim from the explorer:
https://github.com/readmeio/api-explorer/blob/77b90ebed4673f168354cdcd730e34b7ee016360/packages/api-explorer/src/lib/parse-response.js#L13-L30

BREAKING CHANGE: this is a breaking change.

* chore: relax commitlint rules on body and footer length

Taken from main codebase

* feat: remove res.json() line from the httpsnippet client

* fix: always output `.then(res => console.log(res))` in code sample

Since we dont know if the response is json or not, we can't make
assumptions. In an ideal world we'd conditionally do this based
on the accept header in the response, but Operation.getHeaders() only
returns with an array of headers and not their actual values. I think
this is good enough for now!

#240 (comment)
@tamj0rd2
Copy link

tamj0rd2 commented Apr 2, 2021

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

4141done added a commit to 4141done/njs-tools that referenced this issue Oct 11, 2022
Uses [Jest](https://jestjs.io/) as a test runner and sets up a basic test that will always pass. The goal here is to just get the test runner working.

It also includes an integration with [`mock-fs`](https://github.com/tschaub/mock-fs) to allow us to work in an ephemeral filesystem. This is important since the bundles does reading and generation of files.

Looks like this when run:
```
10/11/2022 02:02:28 PM > npm test

> [email protected] test
> NODE_OPTIONS=--experimental-vm-modules jest

(node:50779) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
 PASS  test/transpilation/transpile.test.mjs
  ✓ bundle: produces the default export required by njs

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.23 s, estimated 1 s
Ran all test suites.
```

Throughout this project I use ES6 modules.  These are generally well supported in the version of nodejs required by this package, but jest is being conservative so I had to do a few things to make jest work:

1. Supply a config file that adds `.mjs` files to the test match pattern
2. Set `transform: {}`  in the config file.  Apparently jest transforms files (which I don't like anyway)
3. Run the test runner with `NODE_OPTIONS=--experimental-vm-modules`
4. There's a bug in `mock-fs` which combined with jest that eats the `console` for some reason. `consoleMock.mjs` was added for this reason.  [Bug](tschaub/mock-fs#234)

Mocha is what I'm used to, but I'm wanting to proceed with Jest as a learning exercise because:
1. Many of my JS-focused colleagues prefer this tool and having something that's familiar is good
2. Some of the mocking features it has look a little nicer than the mocha plugins I'd have to use
4141done added a commit to 4141done/njs-tools that referenced this issue Oct 11, 2022
Uses [Jest](https://jestjs.io/) as a test runner and sets up a basic test that will always pass. The goal here is to just get the test runner working.

It also includes an integration with [`mock-fs`](https://github.com/tschaub/mock-fs) to allow us to work in an ephemeral filesystem. This is important since the bundles does reading and generation of files.

Looks like this when run:
```
10/11/2022 02:02:28 PM > npm test

> [email protected] test
> NODE_OPTIONS=--experimental-vm-modules jest

(node:50779) ExperimentalWarning: VM Modules is an experimental feature. This feature could change at any time
(Use `node --trace-warnings ...` to show where the warning was created)
 PASS  test/transpilation/transpile.test.mjs
  ✓ bundle: produces the default export required by njs

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        0.23 s, estimated 1 s
Ran all test suites.
```

Throughout this project I use ES6 modules.  These are generally well supported in the version of nodejs required by this package, but jest is being conservative so I had to do a few things to make jest work:

1. Supply a config file that adds `.mjs` files to the test match pattern
2. Set `transform: {}`  in the config file.  Apparently jest transforms files (which I don't like anyway)
3. Run the test runner with `NODE_OPTIONS=--experimental-vm-modules`
4. There's a bug in `mock-fs` which combined with jest that eats the `console` for some reason. `consoleMock.mjs` was added for this reason.  [Bug](tschaub/mock-fs#234)

Mocha is what I'm used to, but I'm wanting to proceed with Jest as a learning exercise because:
1. Many of my JS-focused colleagues prefer this tool and having something that's familiar is good
2. Some of the mocking features it has look a little nicer than the mocha plugins I'd have to use
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

No branches or pull requests