diff --git a/.vscode/settings.json b/.vscode/settings.json index 0dcce386c953..bb5f7b2d11d9 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -2,8 +2,6 @@ "editor.rulers": [80], "files.exclude": { "**/.git": true, - "**/node_modules": true, - "**/build": true }, "javascript.validate.enable": false, "jest.pathToJest": "yarn jest --", diff --git a/CHANGELOG.md b/CHANGELOG.md index a87c2630548d..a88344c3876b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ - `[@jest/types]` Mark deprecated configuration options as `@deprecated` ([#11913](https://github.com/facebook/jest/pull/11913)) - `[jest-cli]` Improve `--help` printout by removing defunct `--browser` option ([#11914](https://github.com/facebook/jest/pull/11914)) - `[jest-haste-map]` Use distinct cache paths for different values of `computeDependencies` ([#11916](https://github.com/facebook/jest/pull/11916)) +- `[@jest/reporters]` Do not buffer `console.log`s when using verbose reporter [#11054](https://github.com/facebook/jest/pull/11054) ### Chore & Maintenance diff --git a/e2e/__tests__/__snapshots__/consoleDebugging.test.ts.snap b/e2e/__tests__/__snapshots__/consoleDebugging.test.ts.snap new file mode 100644 index 000000000000..9b6414ff5b70 --- /dev/null +++ b/e2e/__tests__/__snapshots__/consoleDebugging.test.ts.snap @@ -0,0 +1,22 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`console debugging with --verbose 1`] = ` + console.log + test + + at Object.log (__tests__/console-debugging.test.js:17:11) + +`; + +exports[`console debugging with --verbose 2`] = ` +PASS __tests__/console-debugging.test.js + ✓ verbose mode prints console output synchronously +`; + +exports[`console debugging with --verbose 3`] = ` +Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 1 passed, 1 total +Time: <> +Ran all test suites. +`; diff --git a/e2e/__tests__/consoleDebugging.test.ts b/e2e/__tests__/consoleDebugging.test.ts new file mode 100644 index 000000000000..4aca32566208 --- /dev/null +++ b/e2e/__tests__/consoleDebugging.test.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +import {wrap} from 'jest-snapshot-serializer-raw'; +import {extractSummary} from '../Utils'; +import runJest from '../runJest'; + +test('console debugging with --verbose', () => { + const {stderr, stdout, exitCode} = runJest('console-debugging', [ + '--noStackTrace', + '--no-cache', + ]); + const {summary, rest} = extractSummary(stderr); + + expect(exitCode).toBe(0); + expect(wrap(stdout)).toMatchSnapshot(); + expect(wrap(rest)).toMatchSnapshot(); + expect(wrap(summary)).toMatchSnapshot(); +}); diff --git a/e2e/console-debugging/__tests__/console-debugging.test.js b/e2e/console-debugging/__tests__/console-debugging.test.js new file mode 100644 index 000000000000..9d801e87b6c5 --- /dev/null +++ b/e2e/console-debugging/__tests__/console-debugging.test.js @@ -0,0 +1,27 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +const stdoutWrite = require('../stdout-spy'); + +process.stdout.write = jest.fn(process.stdout.write); + +test('verbose mode prints console output synchronously', () => { + // test only works consistently without tty + expect(process.stdout.isTTY).not.toBe(true); + + console.log('test'); + + expect(stdoutWrite.text).toMatchInlineSnapshot(` + " console.log + test + + at Object.log (__tests__/console-debugging.test.js:17:11) + + " + `); +}); diff --git a/e2e/console-debugging/jest.config.js b/e2e/console-debugging/jest.config.js new file mode 100644 index 000000000000..87ce2c88899b --- /dev/null +++ b/e2e/console-debugging/jest.config.js @@ -0,0 +1,14 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +require('./stdout-spy'); + +module.exports = { + testEnvironment: 'node', + verbose: true, +}; diff --git a/e2e/console-debugging/package.json b/e2e/console-debugging/package.json new file mode 100644 index 000000000000..0967ef424bce --- /dev/null +++ b/e2e/console-debugging/package.json @@ -0,0 +1 @@ +{} diff --git a/e2e/console-debugging/stdout-spy.js b/e2e/console-debugging/stdout-spy.js new file mode 100644 index 000000000000..737acf1f4678 --- /dev/null +++ b/e2e/console-debugging/stdout-spy.js @@ -0,0 +1,26 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. All Rights Reserved. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +'use strict'; + +const originalStdoutWrite = process.stdout.write.bind(process.stdout); + +global.process.__stdoutWriteMock = global.process.__stdoutWriteMock || null; + +/* + This is a terrible hack to ensure that we monkeyPath stdoutWrite before + the jest reporter does... +*/ +if (!global.process.__stdoutWriteMock) { + global.process.__stdoutWriteMock = (...args) => { + global.process.__stdoutWriteMock.text = args[0]; + originalStdoutWrite(...args); + }; + + process.stdout.write = global.process.__stdoutWriteMock; +} + +module.exports = global.process.__stdoutWriteMock; diff --git a/packages/jest-reporters/package.json b/packages/jest-reporters/package.json index dd0886f9dd53..ee4bf4712ba7 100644 --- a/packages/jest-reporters/package.json +++ b/packages/jest-reporters/package.json @@ -14,6 +14,7 @@ "@jest/test-result": "^27.2.4", "@jest/transform": "^27.2.4", "@jest/types": "^27.2.4", + "@types/node": "*", "chalk": "^4.0.0", "collect-v8-coverage": "^1.0.0", "exit": "^0.1.2", diff --git a/packages/jest-reporters/src/DefaultReporter.ts b/packages/jest-reporters/src/DefaultReporter.ts index 77b1fbe94b46..d9aeee5b210a 100644 --- a/packages/jest-reporters/src/DefaultReporter.ts +++ b/packages/jest-reporters/src/DefaultReporter.ts @@ -43,16 +43,18 @@ export default class DefaultReporter extends BaseReporter { this._err = process.stderr.write.bind(process.stderr); this._status = new Status(); this._bufferedOutput = new Set(); - this._wrapStdio(process.stdout); - this._wrapStdio(process.stderr); + this.__wrapStdio(process.stdout); + this.__wrapStdio(process.stderr); this._status.onChange(() => { - this._clearStatus(); - this._printStatus(); + this.__clearStatus(); + this.__printStatus(); }); } - private _wrapStdio(stream: NodeJS.WritableStream | NodeJS.WriteStream) { - const originalWrite = stream.write; + protected __wrapStdio( + stream: NodeJS.WritableStream | NodeJS.WriteStream, + ): void { + const write = stream.write.bind(stream); let buffer: Array = []; let timeout: NodeJS.Timeout | null = null; @@ -62,11 +64,11 @@ export default class DefaultReporter extends BaseReporter { buffer = []; // This is to avoid conflicts between random output and status text - this._clearStatus(); + this.__clearStatus(); if (string) { - originalWrite.call(stream, string); + write(string); } - this._printStatus(); + this.__printStatus(); this._bufferedOutput.delete(flushBufferedOutput); }; @@ -103,7 +105,7 @@ export default class DefaultReporter extends BaseReporter { } } - private _clearStatus() { + protected __clearStatus(): void { if (isInteractive) { if (this._globalConfig.useStderr) { this._err(this._clear); @@ -113,7 +115,7 @@ export default class DefaultReporter extends BaseReporter { } } - private _printStatus() { + protected __printStatus(): void { const {content, clear} = this._status.get(); this._clear = clear; if (isInteractive) { diff --git a/packages/jest-reporters/src/VerboseReporter.ts b/packages/jest-reporters/src/VerboseReporter.ts index 5d7de322f330..dfe5901ef7bd 100644 --- a/packages/jest-reporters/src/VerboseReporter.ts +++ b/packages/jest-reporters/src/VerboseReporter.ts @@ -29,6 +29,21 @@ export default class VerboseReporter extends DefaultReporter { this._globalConfig = globalConfig; } + // Verbose mode is for debugging. Buffering of output is undesirable. + // See https://github.com/facebook/jest/issues/8208 + protected __wrapStdio( + stream: NodeJS.WritableStream | NodeJS.WriteStream, + ): void { + const write = stream.write.bind(stream); + + stream.write = (chunk: string) => { + this.__clearStatus(); + write(chunk); + this.__printStatus(); + return true; + }; + } + static filterTestResults( testResults: Array, ): Array { diff --git a/yarn.lock b/yarn.lock index 94e28baf81a6..7996e76ba4e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2654,6 +2654,7 @@ __metadata: "@types/istanbul-lib-report": ^3.0.0 "@types/istanbul-lib-source-maps": ^4.0.0 "@types/istanbul-reports": ^3.0.0 + "@types/node": "*" "@types/node-notifier": ^8.0.0 chalk: ^4.0.0 collect-v8-coverage: ^1.0.0