diff --git a/integration_tests/__tests__/__snapshots__/console_log_output_when_run_in_band.test.js.snap b/integration_tests/__tests__/__snapshots__/console_log_output_when_run_in_band.test.js.snap new file mode 100644 index 000000000000..2d8e865a6cc6 --- /dev/null +++ b/integration_tests/__tests__/__snapshots__/console_log_output_when_run_in_band.test.js.snap @@ -0,0 +1,24 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`prints console.logs when run with forceExit 1`] = ` +" PASS __tests__/a-banana.js + ✓ banana + +" +`; + +exports[`prints console.logs when run with forceExit 2`] = ` +"Test Suites: 1 passed, 1 total +Tests: 1 passed, 1 total +Snapshots: 0 total +Time: <> +Ran all test suites. +" +`; + +exports[`prints console.logs when run with forceExit 3`] = ` +" console.log __tests__/a-banana.js:2 + Hey + +" +`; diff --git a/integration_tests/__tests__/console_log_output_when_run_in_band.test.js b/integration_tests/__tests__/console_log_output_when_run_in_band.test.js new file mode 100644 index 000000000000..be7afba099e4 --- /dev/null +++ b/integration_tests/__tests__/console_log_output_when_run_in_band.test.js @@ -0,0 +1,41 @@ +/** + * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + */ + +'use strict'; + +const path = require('path'); +const skipOnWindows = require('skipOnWindows'); +const {extractSummary, cleanup, writeFiles} = require('../utils'); +const runJest = require('../runJest'); + +const DIR = path.resolve(__dirname, '../console_log_output_when_run_in_band'); + +skipOnWindows.suite(); + +beforeEach(() => cleanup(DIR)); +afterAll(() => cleanup(DIR)); + +test('prints console.logs when run with forceExit', () => { + writeFiles(DIR, { + '__tests__/a-banana.js': ` + test('banana', () => console.log('Hey')); + `, + 'package.json': '{}', + }); + + const {stderr, stdout, status} = runJest(DIR, [ + '-i', + '--ci=false', + '--forceExit', + ]); + const {rest, summary} = extractSummary(stderr); + expect(status).toBe(0); + expect(rest).toMatchSnapshot(); + expect(summary).toMatchSnapshot(); + expect(stdout).toMatchSnapshot(); +}); diff --git a/packages/jest-cli/src/reporters/DefaultReporter.js b/packages/jest-cli/src/reporters/DefaultReporter.js index ee713c92ab01..ab112da7adb5 100644 --- a/packages/jest-cli/src/reporters/DefaultReporter.js +++ b/packages/jest-cli/src/reporters/DefaultReporter.js @@ -24,6 +24,7 @@ import getConsoleOutput from './getConsoleOutput'; import getResultHeader from './getResultHeader'; type write = (chunk: string, enc?: any, cb?: () => void) => boolean; +type FlushBufferedOutput = () => void; const TITLE_BULLET = chalk.bold('\u25cf '); @@ -35,6 +36,7 @@ class DefaultReporter extends BaseReporter { _globalConfig: GlobalConfig; _out: write; _status: Status; + _bufferedOutput: Set; constructor(globalConfig: GlobalConfig) { super(); @@ -43,6 +45,7 @@ class DefaultReporter extends BaseReporter { this._out = process.stdout.write.bind(process.stdout); 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._status.onChange(() => { @@ -57,25 +60,28 @@ class DefaultReporter extends BaseReporter { let buffer = []; let timeout = null; - const doFlush = () => { + const flushBufferedOutput = () => { const string = buffer.join(''); buffer = []; // This is to avoid conflicts between random output and status text this._clearStatus(); originalWrite.call(stream, string); this._printStatus(); + this._bufferedOutput.delete(flushBufferedOutput); }; - const flush = () => { + this._bufferedOutput.add(flushBufferedOutput); + + const debouncedFlush = () => { // If the process blows up no errors would be printed. // There should be a smart way to buffer stderr, but for now // we just won't buffer it. if (stream === process.stderr) { - doFlush(); + flushBufferedOutput(); } else { if (!timeout) { timeout = setTimeout(() => { - doFlush(); + flushBufferedOutput(); timeout = null; }, 100); } @@ -85,11 +91,18 @@ class DefaultReporter extends BaseReporter { // $FlowFixMe stream.write = chunk => { buffer.push(chunk); - flush(); + debouncedFlush(); return true; }; } + // Don't wait for the debounced call and flush all output immediately. + forceFlushBufferedOutput() { + for (const flushBufferedOutput of this._bufferedOutput) { + flushBufferedOutput(); + } + } + _clearStatus() { if (isInteractive) { this._out(this._clear); @@ -116,6 +129,7 @@ class DefaultReporter extends BaseReporter { } onRunComplete() { + this.forceFlushBufferedOutput(); this._status.runFinished(); // $FlowFixMe process.stdout.write = this._out; @@ -139,6 +153,7 @@ class DefaultReporter extends BaseReporter { test.context.config, testResult, ); + this.forceFlushBufferedOutput(); } _printTestFileSummary(