Skip to content

Commit 2da52ad

Browse files
committed
fix(jest-console): buffer console output in CustomConsole for reporters
CustomConsole.getBuffer() returned undefined, causing TestResult.console to be empty when verbose mode was active. Reporters relying on TestResult.console (e.g. custom reporters) received no console data. Added buffer tracking to CustomConsole so it both prints live to stdout (preserving verbose UX) and populates the buffer for reporters. Closes #6441
1 parent 746b143 commit 2da52ad

4 files changed

Lines changed: 90 additions & 5 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
## main
22

3+
### Fixes
4+
5+
- `[jest-console]` `CustomConsole` now buffers console output so `TestResult.console` is populated for reporters when `verbose` is enabled ([#16155](https://github.com/jestjs/jest/pull/16155))
6+
37
## 30.4.2
48

59
### Fixes

packages/jest-console/src/CustomConsole.ts

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,22 @@ import {
1515
inspect,
1616
} from 'node:util';
1717
import chalk from 'chalk';
18-
import {clearLine, formatTime} from 'jest-util';
19-
import type {LogCounters, LogMessage, LogTimers, LogType} from './types';
18+
import {ErrorWithStack, clearLine, formatTime, invariant} from 'jest-util';
19+
import type {
20+
ConsoleBuffer,
21+
LogCounters,
22+
LogMessage,
23+
LogTimers,
24+
LogType,
25+
} from './types';
2026

2127
type Formatter = (type: LogType, message: LogMessage) => string;
2228

2329
export default class CustomConsole extends Console {
2430
private readonly _stdout: WriteStream;
2531
private readonly _stderr: WriteStream;
2632
private readonly _formatBuffer: Formatter;
33+
private readonly _buffer: ConsoleBuffer = [];
2734
private _counters: LogCounters = {};
2835
private _timers: LogTimers = {};
2936
private _groupDepth = 0;
@@ -46,15 +53,31 @@ export default class CustomConsole extends Console {
4653
super.log(
4754
this._formatBuffer(type, ' '.repeat(this._groupDepth) + message),
4855
);
56+
this._addToBuffer(type, message);
4957
}
5058

5159
private _logError(type: LogType, message: string) {
5260
clearLine(this._stderr);
5361
super.error(
5462
this._formatBuffer(type, ' '.repeat(this._groupDepth) + message),
5563
);
64+
this._addToBuffer(type, message);
5665
}
5766

67+
private readonly _addToBuffer = (type: LogType, message: string) => {
68+
const rawStack = new ErrorWithStack(undefined, this._addToBuffer).stack;
69+
70+
invariant(rawStack != null, 'always have a stack trace');
71+
72+
const origin = rawStack.split('\n').slice(3).filter(Boolean).join('\n');
73+
74+
this._buffer.push({
75+
message: ' '.repeat(this._groupDepth) + message,
76+
origin,
77+
type,
78+
});
79+
};
80+
5881
override assert(value: unknown, message?: string | Error): asserts value {
5982
try {
6083
assert.ok(value, message);
@@ -159,7 +182,7 @@ export default class CustomConsole extends Console {
159182
this._logError('warn', format(firstArg, ...args));
160183
}
161184

162-
getBuffer(): undefined {
163-
return undefined;
185+
getBuffer(): ConsoleBuffer | undefined {
186+
return this._buffer.length > 0 ? this._buffer : undefined;
164187
}
165188
}

packages/jest-console/src/__tests__/CustomConsole.test.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,4 +241,62 @@ describe('CustomConsole', () => {
241241
expect(_console.Console).toBeDefined();
242242
});
243243
});
244+
245+
describe('getBuffer', () => {
246+
test('should return undefined when no messages have been logged', () => {
247+
expect(_console.getBuffer()).toBeUndefined();
248+
});
249+
250+
test('should return buffer with log entries after logging', () => {
251+
_console.log('Hello world!');
252+
253+
const buffer = _console.getBuffer();
254+
expect(buffer).toBeDefined();
255+
expect(buffer).toHaveLength(1);
256+
expect(buffer![0].message).toBe('Hello world!');
257+
expect(buffer![0].type).toBe('log');
258+
expect(buffer![0].origin).toBeDefined();
259+
});
260+
261+
test('should buffer error messages', () => {
262+
_console.error('Some error');
263+
264+
const buffer = _console.getBuffer();
265+
expect(buffer).toBeDefined();
266+
expect(buffer).toHaveLength(1);
267+
expect(buffer![0].message).toBe('Some error');
268+
expect(buffer![0].type).toBe('error');
269+
});
270+
271+
test('should buffer warn messages', () => {
272+
_console.warn('Some warning');
273+
274+
const buffer = _console.getBuffer();
275+
expect(buffer).toBeDefined();
276+
expect(buffer).toHaveLength(1);
277+
expect(buffer![0].message).toBe('Some warning');
278+
expect(buffer![0].type).toBe('warn');
279+
});
280+
281+
test('should accumulate multiple log entries', () => {
282+
_console.log('first');
283+
_console.error('second');
284+
_console.warn('third');
285+
286+
const buffer = _console.getBuffer();
287+
expect(buffer).toHaveLength(3);
288+
expect(buffer![0].type).toBe('log');
289+
expect(buffer![1].type).toBe('error');
290+
expect(buffer![2].type).toBe('warn');
291+
});
292+
293+
test('should still print to stdout/stderr while buffering', () => {
294+
_console.log('to stdout');
295+
_console.error('to stderr');
296+
297+
expect(_stdout).toBe('to stdout\n');
298+
expect(_stderr).toBe('to stderr\n');
299+
expect(_console.getBuffer()).toHaveLength(2);
300+
});
301+
});
244302
});

packages/jest-reporters/src/DefaultReporter.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -227,7 +227,7 @@ export default class DefaultReporter extends BaseReporter {
227227
}
228228

229229
this.log(getResultHeader(result, this._globalConfig, config));
230-
if (result.console) {
230+
if (result.console && !this._globalConfig.verbose) {
231231
this.log(
232232
` ${TITLE_BULLET}Console\n\n${getConsoleOutput(result.console, config, this._globalConfig)}`,
233233
);

0 commit comments

Comments
 (0)