1// Flags: --expose-internals
2'use strict';
3require('../common');
4const fixtures = require('../common/fixtures');
5const assert = require('assert');
6const internalUtil = require('internal/util');
7const { internalBinding } = require('internal/test/binding');
8const {
9  privateSymbols: {
10    arrow_message_private_symbol,
11    decorated_private_symbol,
12  }
13} = internalBinding('util');
14const spawnSync = require('child_process').spawnSync;
15
16const decorateErrorStack = internalUtil.decorateErrorStack;
17
18// Verify that decorateErrorStack does not throw with non-objects.
19decorateErrorStack();
20decorateErrorStack(null);
21decorateErrorStack(1);
22decorateErrorStack(true);
23
24// Verify that a stack property is not added to non-Errors.
25const obj = {};
26decorateErrorStack(obj);
27assert.strictEqual(obj.stack, undefined);
28
29// Verify that the stack is decorated when possible.
30function checkStack(stack) {
31  // Matching only on a minimal piece of the stack because the string will vary
32  // greatly depending on the JavaScript engine. V8 includes `;` because it
33  // displays the line of code (`var foo bar;`) that is causing a problem.
34  // ChakraCore does not display the line of code but includes `;` in the phrase
35  // `Expected ';' `.
36  assert.match(stack, /;/g);
37  // Test that it's a multiline string.
38  assert.match(stack, /\n/g);
39}
40let err;
41const badSyntaxPath =
42  fixtures.path('syntax', 'bad_syntax').replace(/\\/g, '\\\\');
43
44try {
45  require(badSyntaxPath);
46} catch (e) {
47  err = e;
48}
49
50assert(typeof err, 'object');
51checkStack(err.stack);
52
53// Verify that the stack is only decorated once.
54decorateErrorStack(err);
55decorateErrorStack(err);
56checkStack(err.stack);
57
58// Verify that the stack is only decorated once for uncaught exceptions.
59const args = [
60  '-e',
61  `require(${JSON.stringify(badSyntaxPath)})`,
62];
63const result = spawnSync(process.argv[0], args, { encoding: 'utf8' });
64checkStack(result.stderr);
65
66// Verify that the stack is unchanged when there is no arrow message.
67err = new Error('foo');
68let originalStack = err.stack;
69decorateErrorStack(err);
70assert.strictEqual(originalStack, err.stack);
71
72// Verify that the arrow message is added to the start of the stack when it
73// exists.
74const arrowMessage = 'arrow_message';
75err = new Error('foo');
76originalStack = err.stack;
77
78err[arrow_message_private_symbol] = arrowMessage;
79decorateErrorStack(err);
80
81assert.strictEqual(err.stack, `${arrowMessage}${originalStack}`);
82assert.strictEqual(err[decorated_private_symbol], true);
83