diff --git a/CHANGELOG.md b/CHANGELOG.md index bd1237f2bde2..e189e4cd114d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ ### Fixes +- `[@jest/console]` Print to stderr when calling `console.error` or `console.assert` in verbose mode or using the `jest-runtime` CLI ([#8261](https://github.com/facebook/jest/pull/8261)) - `[expect]` Add negative equality tests for iterables ([#8260](https://github.com/facebook/jest/pull/8260)) - `[jest-haste-map]` Resolve fs watcher EMFILE error ([#8258](https://github.com/facebook/jest/pull/8258)) diff --git a/packages/jest-console/src/CustomConsole.ts b/packages/jest-console/src/CustomConsole.ts index 13bcd0e7ec23..cd109a14e0ab 100644 --- a/packages/jest-console/src/CustomConsole.ts +++ b/packages/jest-console/src/CustomConsole.ts @@ -12,8 +12,8 @@ import chalk from 'chalk'; import {LogCounters, LogMessage, LogTimers, LogType} from './types'; // TODO: Copied from `jest-util`. Import from it in Jest 25 -function clearLine(stream: NodeJS.WritableStream) { - if (process.stdout.isTTY) { +function clearLine(stream: NodeJS.WritableStream & {isTTY?: boolean}) { + if (stream.isTTY) { stream.write('\x1b[999D\x1b[K'); } } @@ -22,6 +22,7 @@ type Formatter = (type: LogType, message: LogMessage) => string; export default class CustomConsole extends Console { private _stdout: NodeJS.WritableStream; + private _stderr: NodeJS.WritableStream; private _formatBuffer: Formatter; private _counters: LogCounters; private _timers: LogTimers; @@ -34,21 +35,27 @@ export default class CustomConsole extends Console { ) { super(stdout, stderr); this._stdout = stdout; + this._stderr = stderr; this._formatBuffer = formatBuffer; this._counters = {}; this._timers = {}; this._groupDepth = 0; } - private _logToParentConsole(message: string) { - super.log(message); - } - private _log(type: LogType, message: string) { - clearLine(this._stdout); - this._logToParentConsole( - this._formatBuffer(type, ' '.repeat(this._groupDepth) + message), + const isErrorType = type === 'error' || type === 'assert'; + const formattedMessage = this._formatBuffer( + type, + ' '.repeat(this._groupDepth) + message, ); + + if (isErrorType) { + clearLine(this._stderr); + super.error(formattedMessage); + } else { + clearLine(this._stdout); + super.log(formattedMessage); + } } assert(value: any, message?: string | Error) { diff --git a/packages/jest-console/src/__tests__/console.test.ts b/packages/jest-console/src/__tests__/CustomConsole.test.ts similarity index 77% rename from packages/jest-console/src/__tests__/console.test.ts rename to packages/jest-console/src/__tests__/CustomConsole.test.ts index 4b994fc6e888..feaab8083a4a 100644 --- a/packages/jest-console/src/__tests__/console.test.ts +++ b/packages/jest-console/src/__tests__/CustomConsole.test.ts @@ -5,47 +5,77 @@ * LICENSE file in the root directory of this source tree. */ +import {Writable} from 'stream'; import chalk from 'chalk'; import CustomConsole from '../CustomConsole'; describe('CustomConsole', () => { let _console; - let _stdout = ''; + let _stdout; + let _stderr; beforeEach(() => { - _console = new CustomConsole(process.stdout, process.stderr); - jest.spyOn(_console, '_logToParentConsole').mockImplementation(message => { - _stdout += message + '\n'; + _stdout = ''; + _stderr = ''; + + const stdout = new Writable({ + write(chunk, encoding, callback) { + _stdout += chunk.toString(); + callback(); + }, }); - _stdout = ''; + const stderr = new Writable({ + write(chunk, encoding, callback) { + _stderr += chunk.toString(); + callback(); + }, + }); + + _console = new CustomConsole(stdout, stderr); + }); + + describe('log', () => { + test('should print to stdout', () => { + _console.log('Hello world!'); + + expect(_stdout).toBe('Hello world!\n'); + }); + }); + + describe('error', () => { + test('should print to stderr', () => { + _console.error('Found some error!'); + + expect(_stderr).toBe('Found some error!\n'); + }); }); describe('assert', () => { test('do not log when the assertion is truthy', () => { _console.assert(true); - expect(_stdout).toMatch(''); + expect(_stderr).toMatch(''); }); test('do not log when the assertion is truthy and there is a message', () => { _console.assert(true, 'ok'); - expect(_stdout).toMatch(''); + expect(_stderr).toMatch(''); }); test('log the assertion error when the assertion is falsy', () => { _console.assert(false); - expect(_stdout).toMatch('AssertionError'); - expect(_stdout).toMatch('false == true'); + expect(_stderr).toMatch('AssertionError'); + expect(_stderr).toMatch('false == true'); }); test('log the assertion error when the assertion is falsy with another message argument', () => { _console.assert(false, 'ok'); - expect(_stdout).toMatch('AssertionError'); - expect(_stdout).toMatch('ok'); + expect(_stderr).toMatch('AssertionError'); + expect(_stderr).toMatch('ok'); }); });