I've written a node.js command line application that uses ECMAScript modules, top-level await, and nullish coalescing operators so it requires at least node 14.
Older node.js versions can't even parse the script and throw a SyntaxException before evaluating anything. I want to print a friendly error telling users to upgrade to a supported version but I can't get around syntax errors.
#!/usr/bin/env node
# entry.cjs
if (process.version.split('.', 1)[0].slice(1) < 14) {
console.log('too old')
process.exit(1)
}
import './index.js'
$ node8 entry.cjs
import './index.js'
^^^^^^
SyntaxError: Unexpected token import
If I switch to require('./index.js') then it fails with modern runtimes because you cannot require() an ES module.
$ node16 entry.cjs
entry.cjs:6
require('./index.js')
^
Error [ERR_REQUIRE_ESM]: require() of ES Module index.js from entry.cjs not supported.
Instead change the require of index.js in entry.cjs to a dynamic import() which is available in all CommonJS modules.
at Object.<anonymous> (entry.cjs:6:1) {
code: 'ERR_REQUIRE_ESM'
}
I thought an dynamic import expression would work because it would only be evaluated after parsing and after the version check, but that is a reserved keyword even in node 8
$ node8 entry.cjs
node entry.cjs
entry.cjs:6
import('./index.js')
^^^^^^
SyntaxError: Unexpected token import
With NPM
You could define a package.json file and have your start command check the node version first, and then run your script
Example from another SO Q&A:
// package.json
{
//...
"scripts": {
"start": "node check-version.js && node index.js"
},
//...
}
// check-version.js
const MIN_VERSION = 14;
const nodeVersion = process.version.replace(/^v/, '');
const [ nodeMajorVersion ] = nodeVersion.split('.');
if (nodeMajorVersion < MIN_VERSION) {
console.warn(`node version ${nodeVersion} is incompatible with this module.`, `Expected version >= ${MIN_VERSION}`);
process.exit(1);
}
Then npm start would gracefully fail if the version is lower than required and run as expected if not. (You could define another name for the script, i.e.: npm run entry)
Without NPM
If you do not wish to use npm/yarn, you could achieve the same result via .sh:
Create entry.sh
#!/bin/sh
node check-version.js && node index.js
chmod 755 entry.sh
./entry.sh
I eventually used a shell wrapper
#!/bin/bash
PROGDIR=$(dirname "$0")
node -r "$PROGDIR"/check-version.cjs "$PROGDIR"/index.js
This could be written as a shebang line if the os supports multiple shebang arguments.
When I'm sending a message from parent.js to child.js in commonJs syntax then it works. In parent.js I have
//parent.js
const cp = require('child_process');
let child = cp.fork('./child.js');
child.on('message', (message) =>{
console.log('Parent got message: '+message);
});
// parent sends a message
child.send('Parent sends message');
in child.js I have:
// child.js
process.on('message', (m) => {
console.log('child got message:', m);
process.send('child sends message');
});
everything works and in console I'm getting:
child got message: Parent sends message
Parent got message: child sends message
but it stops working when I use ES6 import syntax:
import * as cp from 'child_process';
Do I'm doing something wrong, or this is a nodejs bug?
My node version is 16.13.2
Under not working I mean cursor in terminal is blinking, but I'm not getting any message and I'm not getting any error.
The import foo from 'foo' syntax is only supported in ECMAScript Modules. The ECMAScript Modules (or ESM for short) have been supported (without experimental flag) from Node v12 onwards. However, NodeJS has traditionally used CommonJS (CJS) module format (const foo = require('foo');). To support both formats and ensure interoperability between both of them, NodeJS requires you (the developer) to explicitly identify which of the two formats your file is in.
To indicate to NodeJS that your file is in ESM format, you can use one of the following options:
Name your file with .mjs extension instead of .js. By default, NodeJS treats all .js files as CJS modules, only files named .mjs are considered to be ES Modules. The files with import ... in your above example should be named parent.mjs & child.mjs respectively.
Add "type": "module" in your package.json. This will make NodeJS consider all .js files in your project as ES modules. Use this if all (or almost all) files in your project use import ... syntax. If you need to use require('foo'); syntax in any file, it must be named with .cjs extension instead.
Run node process with --input-type=module flag passing the code from STDIN. This option is impractical in most scenarios. Though you could use it by running: node --input-type="module" < parent.js, note that file is not passed as argument here, only its contents are redirected to STDIN of node process.
The Jest "An Async Example" guide starts with:
First, enable Babel support in Jest...
But I miss to see why and where does Jest needs Babel for.
Node.js has supported async functions by default since version 7.6.0, so (as you suspected) Babel is not needed for Jest to run tests using async functions.
I just confirmed this by installing only Jest v24.6.0 and ran this test with Node.js v10.15.1:
test('hi', async () => {
const val = await Promise.resolve('hello');
expect(val).toBe('hello');
});
...and it passed just fine.
On the other hand, Babel is required to use ES6 module syntax.
Many of the examples in the "An Async Example" doc use ES6 module syntax (export default ..., import * as ..., etc.) so Babel is required for any of those examples to work.
console.log statements output nothing at all in Jest. This was working for me yesterday, and all of sudden, it's not working today. I have made zero changes to my config and haven't installed any updates.
I'm not using the --forceExit option. Still seeing this issue.
Jest suppresses the console log message by default. In order to show the console log message, set silent option to false at the command line
set --silent=false in the command line:
npm run test -- --silent=false
You can run both options together like this --watch --verbose false if you want to also be watching the files and see the output.
for one time runs just do --verbose false
As per comment on https://github.com/facebook/jest/issues/2441,
Try setting verbose: false (or removing it) in the jest options in package.json.
This is a pretty old question and still there's no accepted answer. However, none of the suggested solutions worked for me (settings like --silent --verbose etc.). The main problem is that Jest changes the global console object. So, the easiest solution is to not use the global console object.
Instead import dedicated log functions from the console module and work with those:
import { error } from "console";
error("This is an error");
As easy as that.
Try using console.debug() instead.
Run console.debug('Message here', yourValueHere) inside test function and it should show in the console output when running test script. You can verify if it works using Ctrl+F and find Message here in the standard output.
This does the trick of showing output in the console, while it is not an answer quite on how to use console.log I understand.
I am running #testing-library/jest-dom and jest-junit 12.0.0 as devDependencies.
jest-junit has a minimal configuration of
"jest-junit": {
"usePathForSuiteName": "true"
},
in package.json. This is mainly to configure coverage reporting.
jest is configured like this:
"jest": {
"testMatch": [
"**/__tests__/**/*.[jt]s?(x)",
"**/?(*.)+(spec|test).[jt]s?(x)",
"!**/utilities.ts",
],
Check for your command line flags in package.json to see that you don't have --silent in there.
in addition to --verbose option which can cause this as mentioned, be aware that the --watch may also cause this bug.
One of the potential reason that logging is not printing is due to console.log has been mocked. Something as below
// jest-setup.js
global.console = {
// eslint-disable-next-line no-undef
log: jest.fn(), // console.log are ignored in tests
// log: console.log,
// Keep native behaviour for other methods, use those to print out things in your own tests, not `console.log`
error: console.error,
warn: console.warn,
info: console.info,
debug: console.debug,
};
// package.json
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js",
"jsx",
"json",
"node"
],
"setupFilesAfterEnv": [
"#testing-library/jest-native/extend-expect",
"<rootDir>/src/config/jest-setup.js"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.test.{ts,tsx}"
]
},
This is commonly used if you wish to disable console.log in jest
Also be sure that your jest config does not have silent: true. In my case, I didn't realize that someone else had added that to our config.
I don't see it in the list of config options, but the command line flag is documented here.
If using Webstorm with Jest configuration, click on the file name instead of the test name.
Having tried a few of the config options in the previous replies, using console.debug() instead of console.log() worked.
In my case, the issue was caused by [only] flag in:
it.only() or test.only('some text',()=>{})
According to the v27 docs silent is what you want here. verbose false (the default) prevents Jest from outputting the result of every test in a hierarchy while silent true (the default) will:
Prevent tests from printing messages through the console.
Use npx jest --silent false if you want to run Jest with that option from the CLI. Tested this just now with console.log and it works as expected.
Tried the advice given regarding jest config settings to no avail. Instead, in my case, the issue seemed related to not awaiting asynchronous code:
test("test", async () => {
console.log("Does output")
new Promise(resolve => {
// some expectation depending on async code
setTimeout(() => resolve(console.log("Does not output")) , 1)
})
})
Rather, awaiting the promise does output the async log:
test("test", async () => {
console.log("Does output")
await new Promise(resolve => {
// some expectation depending on async code
setTimeout(() => resolve(console.log("Does output")) , 1)
})
})
Possibly related background:
https://github.com/facebook/jest/issues/2441
Try using console.info() which is an alias for console.log(). I tried almost all the above answers but still console.log() didn't worked for me by any means. So, used console.info() which did the work.
This is what worked for me: jest --verbose true
In my case the problem was that the logs where made when the module is required, so before the start of an actual test case. Change from a top-level import to using require inside the test case fixed the problem.
In my case the problem was importing the functions from the compiled version (present in dist folder) instead of the src folder. And therefore it was using the old version. So rebuilding the project and/or importing from src fixed my issue.
On MacOS with jest version 26.6.3 I had to append --silent="false"
renaming my file to index.test.js from index.spec.js did the trick for me.
How can I just use the simple node cli/repl debugger with Jest?
The Jest documentation uses node-inspector, but it is outdated/deprecated as of Node 6.3. I tried the recommended command anyway on Node 7.7.4:
node --debug-brk ./node_modules/.bin/jest --runInBand --no-cache [your_test_file]
But this simply hangs on the following (assumedly waiting on node-inspector):
(node:13452) DeprecationWarning: node --debug is deprecated. Please use node --inspect instead. Debugger listening on 127.0.0.1:5858
I added --inspect as specified by the warning, but even then execution doesn't stop on my debugger statement in Chrome DevTools.
This seems overly complicated for a very simple use case.
I found the following command works:
node debug ./node_modules/.bin/jest --runInBand --no-cache [your_test_file]
...but with some quirky behavior. When the debugger first stops you will see:
break in node_modules/jest/bin/jest.js:10
8 */
9
>10 'use strict';
11
12 require('jest-cli/bin/jest');
debug>
Apparently Jest always injects this breakpoint so that you have time to open Chrome DevTools (irrelevant in our case since we're only going to use cli/repl).
Continue past this breakpoint with c, and after a short time (without any indication of course that things are progressing along) you should see your breakpoint:
break in webpack/assets/react/components/presentation/Feed/Comments/Comment/commentSpec.jsx:12
10 var wrapper = (0, _enzyme.shallow)(_react2.default.createElement(_comment2.default, { loading: true }));
11
>12 debugger;
13 expect(wrapper.find(_button2.default)).to.have.length(1);
14 });
debug>
The last weird thing is you need to type repl to inspect objects as described in Node Debugger and Inspecting variables using node's built-in debugger?
The combination of all these steps was not immediately obvious to me while reading the documentation, so I hope this answer helps someone get over the hurdle faster.
From node v8.4 the debugger keyword within the code is fixed for VM context. Refer this git comment.
1.Type debugger keyword in your Jest code:
describe('Testcase definition', () => {
it('should be defined with subobjects', () => {
debugger; // <-- This keyword breaks on Chrome inspect
expect(true).toBe(true);
});
});
Command to Run:
node --inspect-brk --inspect ./node_modules/.bin/jest -i tests/mytest.test.js
Now open chrome://inspect/#devices on Chrome. Voila!