• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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