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