inspect.js
  1  var test = require('tape');
  2  var hasSymbols = require('has-symbols/shams')();
  3  var utilInspect = require('../util.inspect');
  4  var repeat = require('string.prototype.repeat');
  5  
  6  var inspect = require('..');
  7  
  8  test('inspect', function (t) {
  9      t.plan(5);
 10  
 11      var obj = [{ inspect: function xyzInspect() { return '!XYZ¡'; } }, []];
 12      var stringResult = '[ !XYZ¡, [] ]';
 13      var falseResult = '[ { inspect: [Function: xyzInspect] }, [] ]';
 14  
 15      t.equal(inspect(obj), stringResult);
 16      t.equal(inspect(obj, { customInspect: true }), stringResult);
 17      t.equal(inspect(obj, { customInspect: 'symbol' }), falseResult);
 18      t.equal(inspect(obj, { customInspect: false }), falseResult);
 19      t['throws'](
 20          function () { inspect(obj, { customInspect: 'not a boolean or "symbol"' }); },
 21          TypeError,
 22          '`customInspect` must be a boolean or the string "symbol"'
 23      );
 24  });
 25  
 26  test('inspect custom symbol', { skip: !hasSymbols || !utilInspect || !utilInspect.custom }, function (t) {
 27      t.plan(4);
 28  
 29      var obj = { inspect: function stringInspect() { return 'string'; } };
 30      obj[utilInspect.custom] = function custom() { return 'symbol'; };
 31  
 32      var symbolResult = '[ symbol, [] ]';
 33      var stringResult = '[ string, [] ]';
 34      var falseResult = '[ { inspect: [Function: stringInspect]' + (utilInspect.custom ? ', [' + inspect(utilInspect.custom) + ']: [Function: custom]' : '') + ' }, [] ]';
 35  
 36      var symbolStringFallback = utilInspect.custom ? symbolResult : stringResult;
 37      var symbolFalseFallback = utilInspect.custom ? symbolResult : falseResult;
 38  
 39      t.equal(inspect([obj, []]), symbolStringFallback);
 40      t.equal(inspect([obj, []], { customInspect: true }), symbolStringFallback);
 41      t.equal(inspect([obj, []], { customInspect: 'symbol' }), symbolFalseFallback);
 42      t.equal(inspect([obj, []], { customInspect: false }), falseResult);
 43  });
 44  
 45  test('symbols', { skip: !hasSymbols }, function (t) {
 46      t.plan(2);
 47  
 48      var obj = { a: 1 };
 49      obj[Symbol('test')] = 2;
 50      obj[Symbol.iterator] = 3;
 51      Object.defineProperty(obj, Symbol('non-enum'), {
 52          enumerable: false,
 53          value: 4
 54      });
 55  
 56      if (typeof Symbol.iterator === 'symbol') {
 57          t.equal(inspect(obj), '{ a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }', 'object with symbols');
 58          t.equal(inspect([obj, []]), '[ { a: 1, [Symbol(test)]: 2, [Symbol(Symbol.iterator)]: 3 }, [] ]', 'object with symbols in array');
 59      } else {
 60          // symbol sham key ordering is unreliable
 61          t.match(
 62              inspect(obj),
 63              /^(?:{ a: 1, \[Symbol\(test\)\]: 2, \[Symbol\(Symbol.iterator\)\]: 3 }|{ a: 1, \[Symbol\(Symbol.iterator\)\]: 3, \[Symbol\(test\)\]: 2 })$/,
 64              'object with symbols (nondeterministic symbol sham key ordering)'
 65          );
 66          t.match(
 67              inspect([obj, []]),
 68              /^\[ (?:{ a: 1, \[Symbol\(test\)\]: 2, \[Symbol\(Symbol.iterator\)\]: 3 }|{ a: 1, \[Symbol\(Symbol.iterator\)\]: 3, \[Symbol\(test\)\]: 2 }), \[\] \]$/,
 69              'object with symbols in array (nondeterministic symbol sham key ordering)'
 70          );
 71      }
 72  });
 73  
 74  test('maxStringLength', function (t) {
 75      t['throws'](
 76          function () { inspect('', { maxStringLength: -1 }); },
 77          TypeError,
 78          'maxStringLength must be >= 0, or Infinity, not negative'
 79      );
 80  
 81      var str = repeat('a', 1e8);
 82  
 83      t.equal(
 84          inspect([str], { maxStringLength: 10 }),
 85          '[ \'aaaaaaaaaa\'... 99999990 more characters ]',
 86          'maxStringLength option limits output'
 87      );
 88  
 89      t.equal(
 90          inspect(['f'], { maxStringLength: null }),
 91          '[ \'\'... 1 more character ]',
 92          'maxStringLength option accepts `null`'
 93      );
 94  
 95      t.equal(
 96          inspect([str], { maxStringLength: Infinity }),
 97          '[ \'' + str + '\' ]',
 98          'maxStringLength option accepts ∞'
 99      );
100  
101      t.end();
102  });
103  
104  test('inspect options', { skip: !utilInspect.custom }, function (t) {
105      var obj = {};
106      obj[utilInspect.custom] = function () {
107          return JSON.stringify(arguments);
108      };
109      t.equal(
110          inspect(obj),
111          utilInspect(obj, { depth: 5 }),
112          'custom symbols will use node\'s inspect'
113      );
114      t.equal(
115          inspect(obj, { depth: 2 }),
116          utilInspect(obj, { depth: 2 }),
117          'a reduced depth will be passed to node\'s inspect'
118      );
119      t.equal(
120          inspect({ d1: obj }, { depth: 3 }),
121          '{ d1: ' + utilInspect(obj, { depth: 2 }) + ' }',
122          'deep objects will receive a reduced depth'
123      );
124      t.equal(
125          inspect({ d1: obj }, { depth: 1 }),
126          '{ d1: [Object] }',
127          'unlike nodejs inspect, customInspect will not be used once the depth is exceeded.'
128      );
129      t.end();
130  });
131  
132  test('inspect URL', { skip: typeof URL === 'undefined' }, function (t) {
133      t.match(
134          inspect(new URL('https://nodejs.org')),
135          /nodejs\.org/, // Different environments stringify it differently
136          'url can be inspected'
137      );
138      t.end();
139  });