From 9ddb61ec7ac4cef93d934e2172d05adf247ad436 Mon Sep 17 00:00:00 2001 From: Valery Bugakov Date: Thu, 22 Jun 2017 22:25:40 +0400 Subject: [PATCH 1/2] Ensure that console output is not lost in concurrent reporter --- .../jest-cli/src/reporters/DefaultReporter.js | 23 +++++++++++++++---- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/jest-cli/src/reporters/DefaultReporter.js b/packages/jest-cli/src/reporters/DefaultReporter.js index ee713c92ab01..6046ac8476a4 100644 --- a/packages/jest-cli/src/reporters/DefaultReporter.js +++ b/packages/jest-cli/src/reporters/DefaultReporter.js @@ -35,6 +35,7 @@ class DefaultReporter extends BaseReporter { _globalConfig: GlobalConfig; _out: write; _status: Status; + _bufferedIO: Set; constructor(globalConfig: GlobalConfig) { super(); @@ -43,6 +44,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._bufferedIO = new Set(); this._wrapStdio(process.stdout); this._wrapStdio(process.stderr); this._status.onChange(() => { @@ -57,25 +59,28 @@ class DefaultReporter extends BaseReporter { let buffer = []; let timeout = null; - const doFlush = () => { + const flushBufferedIO = () => { 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._bufferedIO.delete(flushBufferedIO); }; - const flush = () => { + this._bufferedIO.add(flushBufferedIO); + + 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(); + flushBufferedIO(); } else { if (!timeout) { timeout = setTimeout(() => { - doFlush(); + flushBufferedIO(); timeout = null; }, 100); } @@ -85,11 +90,17 @@ class DefaultReporter extends BaseReporter { // $FlowFixMe stream.write = chunk => { buffer.push(chunk); - flush(); + debouncedFlush(); return true; }; } + flushDebouncedIO() { + for (const io of this._bufferedIO) { + io(); + } + } + _clearStatus() { if (isInteractive) { this._out(this._clear); @@ -116,6 +127,7 @@ class DefaultReporter extends BaseReporter { } onRunComplete() { + this.flushDebouncedIO(); this._status.runFinished(); // $FlowFixMe process.stdout.write = this._out; @@ -129,6 +141,7 @@ class DefaultReporter extends BaseReporter { testResult: TestResult, aggregatedResults: AggregatedResult, ) { + this.flushDebouncedIO(); this._status.testFinished( test.context.config, testResult, From 6644b36879a864f346562357340c6af9b0a58651 Mon Sep 17 00:00:00 2001 From: Dmitrii Abramov Date: Fri, 23 Jun 2017 15:38:31 -0700 Subject: [PATCH 2/2] console.log integration test + naming --- ...e_log_output_when_run_in_band.test.js.snap | 24 +++++++++++ ...onsole_log_output_when_run_in_band.test.js | 41 +++++++++++++++++++ .../jest-cli/src/reporters/DefaultReporter.js | 26 ++++++------ 3 files changed, 79 insertions(+), 12 deletions(-) create mode 100644 integration_tests/__tests__/__snapshots__/console_log_output_when_run_in_band.test.js.snap create mode 100644 integration_tests/__tests__/console_log_output_when_run_in_band.test.js 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 6046ac8476a4..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,7 +36,7 @@ class DefaultReporter extends BaseReporter { _globalConfig: GlobalConfig; _out: write; _status: Status; - _bufferedIO: Set; + _bufferedOutput: Set; constructor(globalConfig: GlobalConfig) { super(); @@ -44,7 +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._bufferedIO = new Set(); + this._bufferedOutput = new Set(); this._wrapStdio(process.stdout); this._wrapStdio(process.stderr); this._status.onChange(() => { @@ -59,28 +60,28 @@ class DefaultReporter extends BaseReporter { let buffer = []; let timeout = null; - const flushBufferedIO = () => { + 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._bufferedIO.delete(flushBufferedIO); + this._bufferedOutput.delete(flushBufferedOutput); }; - this._bufferedIO.add(flushBufferedIO); + 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) { - flushBufferedIO(); + flushBufferedOutput(); } else { if (!timeout) { timeout = setTimeout(() => { - flushBufferedIO(); + flushBufferedOutput(); timeout = null; }, 100); } @@ -95,9 +96,10 @@ class DefaultReporter extends BaseReporter { }; } - flushDebouncedIO() { - for (const io of this._bufferedIO) { - io(); + // Don't wait for the debounced call and flush all output immediately. + forceFlushBufferedOutput() { + for (const flushBufferedOutput of this._bufferedOutput) { + flushBufferedOutput(); } } @@ -127,7 +129,7 @@ class DefaultReporter extends BaseReporter { } onRunComplete() { - this.flushDebouncedIO(); + this.forceFlushBufferedOutput(); this._status.runFinished(); // $FlowFixMe process.stdout.write = this._out; @@ -141,7 +143,6 @@ class DefaultReporter extends BaseReporter { testResult: TestResult, aggregatedResults: AggregatedResult, ) { - this.flushDebouncedIO(); this._status.testFinished( test.context.config, testResult, @@ -152,6 +153,7 @@ class DefaultReporter extends BaseReporter { test.context.config, testResult, ); + this.forceFlushBufferedOutput(); } _printTestFileSummary(