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'; 23const common = require('../common'); 24const assert = require('assert'); 25const Stream = require('stream'); 26const requiredConsole = require('console'); 27const Console = requiredConsole.Console; 28 29const out = new Stream(); 30const err = new Stream(); 31 32// Ensure the Console instance doesn't write to the 33// process' "stdout" or "stderr" streams. 34process.stdout.write = process.stderr.write = common.mustNotCall(); 35 36// Make sure that the "Console" function exists. 37assert.strictEqual(typeof Console, 'function'); 38 39assert.strictEqual(requiredConsole, global.console); 40// Make sure the custom instanceof of Console works 41assert.ok(global.console instanceof Console); 42assert.ok(!({} instanceof Console)); 43 44// Make sure that the Console constructor throws 45// when not given a writable stream instance. 46assert.throws( 47 () => { new Console(); }, 48 { 49 code: 'ERR_CONSOLE_WRITABLE_STREAM', 50 name: 'TypeError', 51 message: /stdout/ 52 } 53); 54 55// Console constructor should throw if stderr exists but is not writable. 56assert.throws( 57 () => { 58 out.write = () => {}; 59 err.write = undefined; 60 new Console(out, err); 61 }, 62 { 63 code: 'ERR_CONSOLE_WRITABLE_STREAM', 64 name: 'TypeError', 65 message: /stderr/ 66 } 67); 68 69out.write = err.write = (d) => {}; 70 71{ 72 const c = new Console(out, err); 73 assert.ok(c instanceof Console); 74 75 out.write = err.write = common.mustCall((d) => { 76 assert.strictEqual(d, 'test\n'); 77 }, 2); 78 79 c.log('test'); 80 c.error('test'); 81 82 out.write = common.mustCall((d) => { 83 assert.strictEqual(d, '{ foo: 1 }\n'); 84 }); 85 86 c.dir({ foo: 1 }); 87 88 // Ensure that the console functions are bound to the console instance. 89 let called = 0; 90 out.write = common.mustCall((d) => { 91 called++; 92 assert.strictEqual(d, `${called} ${called - 1} [ 1, 2, 3 ]\n`); 93 }, 3); 94 95 [1, 2, 3].forEach(c.log); 96} 97 98// Test calling Console without the `new` keyword. 99{ 100 const withoutNew = Console(out, err); 101 assert.ok(withoutNew instanceof Console); 102} 103 104// Test extending Console 105{ 106 class MyConsole extends Console { 107 hello() {} 108 // See if the methods on Console.prototype are overridable. 109 log() { return 'overridden'; } 110 } 111 const myConsole = new MyConsole(process.stdout); 112 assert.strictEqual(typeof myConsole.hello, 'function'); 113 assert.ok(myConsole instanceof Console); 114 assert.strictEqual(myConsole.log(), 'overridden'); 115 116 const log = myConsole.log; 117 assert.strictEqual(log(), 'overridden'); 118} 119 120// Instance that does not ignore the stream errors. 121{ 122 const c2 = new Console(out, err, false); 123 124 out.write = () => { throw new Error('out'); }; 125 err.write = () => { throw new Error('err'); }; 126 127 assert.throws(() => c2.log('foo'), /^Error: out$/); 128 assert.throws(() => c2.warn('foo'), /^Error: err$/); 129 assert.throws(() => c2.dir('foo'), /^Error: out$/); 130} 131 132// Console constructor throws if inspectOptions is not an object. 133[null, true, false, 'foo', 5, Symbol()].forEach((inspectOptions) => { 134 assert.throws( 135 () => { 136 new Console({ 137 stdout: out, 138 stderr: err, 139 inspectOptions 140 }); 141 }, 142 { 143 message: 'The "options.inspectOptions" property must be of type object.' + 144 common.invalidArgTypeHelper(inspectOptions), 145 code: 'ERR_INVALID_ARG_TYPE' 146 } 147 ); 148}); 149