1// Copyright Joyent, Inc. and other Node contributors. 2// 3// Permission is hereby granted, free of charge, to any person obtaining a 4// copy of this software and associated documentation files (the 5// "Software"), to deal in the Software without restriction, including 6// without limitation the rights to use, copy, modify, merge, publish, 7// distribute, sublicense, and/or sell copies of the Software, and to permit 8// persons to whom the Software is furnished to do so, subject to the 9// following conditions: 10// 11// The above copyright notice and this permission notice shall be included 12// in all copies or substantial portions of the Software. 13// 14// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20// USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22'use strict'; 23if (module !== require.main) { 24 // Signal we've been loaded as a module. 25 // The following console.log() is part of the test. 26 console.log('Loaded as a module, exiting with status code 42.'); 27 process.exit(42); 28} 29 30const common = require('../common'); 31const assert = require('assert'); 32const child = require('child_process'); 33const path = require('path'); 34const fixtures = require('../common/fixtures'); 35const nodejs = `"${process.execPath}"`; 36 37if (process.argv.length > 2) { 38 console.log(process.argv.slice(2).join(' ')); 39 process.exit(0); 40} 41 42// Assert that nothing is written to stdout. 43child.exec(`${nodejs} --eval 42`, common.mustSucceed((stdout, stderr) => { 44 assert.strictEqual(stdout, ''); 45 assert.strictEqual(stderr, ''); 46})); 47 48// Assert that "42\n" is written to stderr. 49child.exec(`${nodejs} --eval "console.error(42)"`, 50 common.mustSucceed((stdout, stderr) => { 51 assert.strictEqual(stdout, ''); 52 assert.strictEqual(stderr, '42\n'); 53 })); 54 55// Assert that the expected output is written to stdout. 56['--print', '-p -e', '-pe', '-p'].forEach((s) => { 57 const cmd = `${nodejs} ${s} `; 58 59 child.exec(`${cmd}42`, common.mustSucceed((stdout, stderr) => { 60 assert.strictEqual(stdout, '42\n'); 61 assert.strictEqual(stderr, ''); 62 })); 63 64 child.exec(`${cmd} '[]'`, common.mustSucceed((stdout, stderr) => { 65 assert.strictEqual(stdout, '[]\n'); 66 assert.strictEqual(stderr, ''); 67 })); 68}); 69 70// Assert that module loading works. 71{ 72 // Replace \ by / because Windows uses backslashes in paths, but they're still 73 // interpreted as the escape character when put between quotes. 74 const filename = __filename.replace(/\\/g, '/'); 75 76 child.exec(`${nodejs} --eval "require('${filename}')"`, 77 common.mustCall((err, stdout, stderr) => { 78 assert.strictEqual(err.code, 42); 79 assert.strictEqual( 80 stdout, 'Loaded as a module, exiting with status code 42.\n'); 81 assert.strictEqual(stderr, ''); 82 })); 83} 84 85// Check that builtin modules are pre-defined. 86child.exec(`${nodejs} --print "os.platform()"`, 87 common.mustSucceed((stdout, stderr) => { 88 assert.strictEqual(stderr, ''); 89 assert.strictEqual(stdout.trim(), require('os').platform()); 90 })); 91 92// Module path resolve bug regression test. 93child.exec(`${nodejs} --eval "require('./test/parallel/test-cli-eval.js')"`, 94 { cwd: path.resolve(__dirname, '../../') }, 95 common.mustCall((err, stdout, stderr) => { 96 assert.strictEqual(err.code, 42); 97 assert.strictEqual( 98 stdout, 'Loaded as a module, exiting with status code 42.\n'); 99 assert.strictEqual(stderr, ''); 100 })); 101 102// Missing argument should not crash. 103child.exec(`${nodejs} -e`, common.mustCall((err, stdout, stderr) => { 104 assert.strictEqual(err.code, 9); 105 assert.strictEqual(stdout, ''); 106 assert.strictEqual(stderr.trim(), 107 `${process.execPath}: -e requires an argument`); 108})); 109 110// Empty program should do nothing. 111child.exec(`${nodejs} -e ""`, common.mustSucceed((stdout, stderr) => { 112 assert.strictEqual(stdout, ''); 113 assert.strictEqual(stderr, ''); 114})); 115 116// "\\-42" should be interpreted as an escaped expression, not a switch. 117child.exec(`${nodejs} -p "\\-42"`, common.mustSucceed((stdout, stderr) => { 118 assert.strictEqual(stdout, '-42\n'); 119 assert.strictEqual(stderr, ''); 120})); 121 122child.exec(`${nodejs} --use-strict -p process.execArgv`, 123 common.mustSucceed((stdout, stderr) => { 124 assert.strictEqual( 125 stdout, "[ '--use-strict', '-p', 'process.execArgv' ]\n" 126 ); 127 assert.strictEqual(stderr, ''); 128 })); 129 130// Regression test for https://github.com/nodejs/node/issues/3574. 131{ 132 let emptyFile = fixtures.path('empty.js'); 133 if (common.isWindows) { 134 emptyFile = emptyFile.replace(/\\/g, '\\\\'); 135 } 136 137 child.exec(`${nodejs} -e 'require("child_process").fork("${emptyFile}")'`, 138 common.mustSucceed((stdout, stderr) => { 139 assert.strictEqual(stdout, ''); 140 assert.strictEqual(stderr, ''); 141 })); 142 143 // Make sure that monkey-patching process.execArgv doesn't cause child_process 144 // to incorrectly munge execArgv. 145 child.exec( 146 `${nodejs} -e "process.execArgv = ['-e', 'console.log(42)', 'thirdArg'];` + 147 `require('child_process').fork('${emptyFile}')"`, 148 common.mustSucceed((stdout, stderr) => { 149 assert.strictEqual(stdout, '42\n'); 150 assert.strictEqual(stderr, ''); 151 })); 152} 153 154// Regression test for https://github.com/nodejs/node/issues/8534. 155{ 156 const script = ` 157 // console.log() can revive the event loop so we must be careful 158 // to write from a 'beforeExit' event listener only once. 159 process.once("beforeExit", () => console.log("beforeExit")); 160 process.on("exit", () => console.log("exit")); 161 console.log("start"); 162 `; 163 const options = { encoding: 'utf8' }; 164 const proc = child.spawnSync(process.execPath, ['-e', script], options); 165 assert.strictEqual(proc.stderr, ''); 166 assert.strictEqual(proc.stdout, 'start\nbeforeExit\nexit\n'); 167} 168 169// Regression test for https://github.com/nodejs/node/issues/11948. 170{ 171 const script = ` 172 process.on('message', (message) => { 173 if (message === 'ping') process.send('pong'); 174 if (message === 'exit') process.disconnect(); 175 }); 176 `; 177 const proc = child.fork('-e', [script]); 178 proc.on('exit', common.mustCall((exitCode, signalCode) => { 179 assert.strictEqual(exitCode, 0); 180 assert.strictEqual(signalCode, null); 181 })); 182 proc.on('message', (message) => { 183 if (message === 'pong') proc.send('exit'); 184 }); 185 proc.send('ping'); 186} 187 188[ '-arg1', 189 '-arg1 arg2 --arg3', 190 '--', 191 'arg1 -- arg2', 192].forEach(function(args) { 193 194 // Ensure that arguments are successfully passed to eval. 195 const opt = ' --eval "console.log(process.argv.slice(1).join(\' \'))"'; 196 const cmd = `${nodejs}${opt} -- ${args}`; 197 child.exec(cmd, common.mustCall(function(err, stdout, stderr) { 198 assert.strictEqual(stdout, `${args}\n`); 199 assert.strictEqual(stderr, ''); 200 assert.strictEqual(err, null); 201 })); 202 203 // Ensure that arguments are successfully passed to print. 204 const popt = ' --print "process.argv.slice(1).join(\' \')"'; 205 const pcmd = `${nodejs}${popt} -- ${args}`; 206 child.exec(pcmd, common.mustCall(function(err, stdout, stderr) { 207 assert.strictEqual(stdout, `${args}\n`); 208 assert.strictEqual(stderr, ''); 209 assert.strictEqual(err, null); 210 })); 211 212 // Ensure that arguments are successfully passed to a script. 213 // The first argument after '--' should be interpreted as a script 214 // filename. 215 const filecmd = `${nodejs} -- "${__filename}" ${args}`; 216 child.exec(filecmd, common.mustCall(function(err, stdout, stderr) { 217 assert.strictEqual(stdout, `${args}\n`); 218 assert.strictEqual(stderr, ''); 219 assert.strictEqual(err, null); 220 })); 221}); 222 223// ESModule eval tests 224 225 226// Assert that "42\n" is written to stdout on module eval. 227const execOptions = '--input-type module'; 228child.exec( 229 `${nodejs} ${execOptions} --eval "console.log(42)"`, 230 common.mustSucceed((stdout) => { 231 assert.strictEqual(stdout, '42\n'); 232 })); 233 234// Assert that "42\n" is written to stdout with print option. 235child.exec( 236 `${nodejs} ${execOptions} --print --eval "42"`, 237 common.mustCall((err, stdout, stderr) => { 238 assert.ok(err); 239 assert.strictEqual(stdout, ''); 240 assert.ok(stderr.includes('--print cannot be used with ESM input')); 241 })); 242 243// Assert that error is written to stderr on invalid input. 244child.exec( 245 `${nodejs} ${execOptions} --eval "!!!!"`, 246 common.mustCall((err, stdout, stderr) => { 247 assert.ok(err); 248 assert.strictEqual(stdout, ''); 249 assert.ok(stderr.indexOf('SyntaxError: Unexpected end of input') > 0); 250 })); 251 252// Assert that require is undefined in ESM support 253child.exec( 254 `${nodejs} ${execOptions} --eval "console.log(typeof require);"`, 255 common.mustSucceed((stdout) => { 256 assert.strictEqual(stdout, 'undefined\n'); 257 })); 258 259// Assert that import.meta is defined in ESM 260child.exec( 261 `${nodejs} ${execOptions} --eval "console.log(typeof import.meta);"`, 262 common.mustSucceed((stdout) => { 263 assert.strictEqual(stdout, 'object\n'); 264 })); 265 266// Assert that packages can be imported cwd-relative with --eval 267child.exec( 268 `${nodejs} ${execOptions} ` + 269 '--eval "import \'./test/fixtures/es-modules/mjs-file.mjs\'"', 270 common.mustSucceed((stdout) => { 271 assert.strictEqual(stdout, '.mjs file\n'); 272 })); 273 274 275// Assert that packages can be dynamic imported initial cwd-relative with --eval 276child.exec( 277 `${nodejs} ${execOptions} ` + 278 '--eval "process.chdir(\'..\');' + 279 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', 280 common.mustSucceed((stdout) => { 281 assert.strictEqual(stdout, '.mjs file\n'); 282 })); 283 284child.exec( 285 `${nodejs} ` + 286 '--eval "process.chdir(\'..\');' + 287 'import(\'./test/fixtures/es-modules/mjs-file.mjs\')"', 288 common.mustSucceed((stdout) => { 289 assert.strictEqual(stdout, '.mjs file\n'); 290 })); 291 292// Regression test for https://github.com/nodejs/node/issues/45336 293child.execFile(process.execPath, 294 ['-p', 295 'Object.defineProperty(global, "fs", { configurable: false });' + 296 'fs === require("node:fs")'], 297 common.mustSucceed((stdout) => { 298 assert.match(stdout, /^true/); 299 })); 300