Skip to content

Commit 2f1f4fd

Browse files
committed
Merge branch 'feat/dot-colors'
2 parents e182f3b + 12f3ebb commit 2f1f4fd

4 files changed

Lines changed: 101 additions & 115 deletions

File tree

packages/phpunit/docs/printer-presets.md

Lines changed: 0 additions & 112 deletions
This file was deleted.

packages/phpunit/src/Printer/AnsiStyle.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ export interface ColorTheme {
77
info: string;
88
diffExpected: string;
99
diffActual: string;
10+
failedDot: string;
11+
errorDot: string;
12+
skippedDot: string;
1013
}
1114

1215
export const DEFAULT_THEME: ColorTheme = {
@@ -16,6 +19,9 @@ export const DEFAULT_THEME: ColorTheme = {
1619
info: 'dim',
1720
diffExpected: 'red',
1821
diffActual: 'green',
22+
failedDot: 'bgRed.white',
23+
errorDot: 'red.bold',
24+
skippedDot: 'cyan.bold',
1925
};
2026

2127
type StyleEntry = { open: string; close: string };
@@ -126,6 +132,18 @@ export class AnsiStyle {
126132
return this.apply('gray', text);
127133
}
128134

135+
failedDot(text: string): string {
136+
return this.apply(this.theme.failedDot, text);
137+
}
138+
139+
errorDot(text: string): string {
140+
return this.apply(this.theme.errorDot, text);
141+
}
142+
143+
skippedDot(text: string): string {
144+
return this.apply(this.theme.skippedDot, text);
145+
}
146+
129147
diffExpected(text: string): string {
130148
return this.apply(this.theme.diffExpected, text);
131149
}

packages/phpunit/src/Printer/Printer.test.ts

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -791,6 +791,69 @@ describe('Printer suite filtering', () => {
791791
});
792792
});
793793

794+
describe('Printer PRESET_PROGRESS dot colors', () => {
795+
const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject(''));
796+
const file = phpUnitProject('tests/AssertionsTest.php');
797+
const printer = new Printer(phpUnitXML, PRESET_PROGRESS);
798+
799+
beforeEach(() => printer.start());
800+
afterEach(() => printer.close());
801+
802+
it('failed dot F uses bgRed + white', () => {
803+
const output = printer.testFinished({
804+
event: TeamcityEvent.testFailed,
805+
name: 'test_failed',
806+
locationHint: '',
807+
flowId: 1,
808+
id: 'Foo::test_failed',
809+
file,
810+
message: 'Failed asserting that false is true.',
811+
details: [{ file, line: 27 }],
812+
duration: 0,
813+
});
814+
815+
expect(output).toContain('\x1b[41m'); // bgRed
816+
expect(output).toContain('\x1b[37m'); // white (fg)
817+
expect(output).toContain('F');
818+
});
819+
820+
it('ignored dot S uses cyan + bold', () => {
821+
const output = printer.testIgnored({
822+
event: TeamcityEvent.testIgnored,
823+
name: 'test_skipped',
824+
locationHint: '',
825+
flowId: 1,
826+
id: 'Foo::test_skipped',
827+
file,
828+
message: 'Skipped.',
829+
details: [],
830+
duration: 0,
831+
});
832+
833+
expect(output).toContain('\x1b[36m'); // cyan
834+
expect(output).toContain('\x1b[1m'); // bold
835+
expect(output).toContain('S');
836+
});
837+
838+
it('error dot E uses red + bold (not bgRed)', () => {
839+
const output = printer.testFinished({
840+
event: TeamcityEvent.testFailed,
841+
name: 'test_error',
842+
locationHint: '',
843+
flowId: 1,
844+
id: 'Foo::test_error',
845+
file,
846+
message: 'RuntimeException: something broke',
847+
details: [{ file, line: 10 }],
848+
duration: 0,
849+
});
850+
851+
expect(output).toContain('\x1b[31m'); // red
852+
expect(output).toContain('\x1b[1m'); // bold
853+
expect(output).toContain('E');
854+
});
855+
});
856+
794857
describe('Printer inline error display', () => {
795858
const phpUnitXML = new PHPUnitXML().setRoot(phpUnitProject(''));
796859
const file = phpUnitProject('tests/AssertionsTest.php');

packages/phpunit/src/Printer/Printer.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,10 @@ export class Printer {
152152
this.errors.push(result as TestFailed);
153153
}
154154

155-
const statusDot = isFailed ? 'F' : '.';
155+
const isError = isFailed && this.classify(result as TestFailed) === 'error';
156+
const statusDot = isFailed ? (isError ? 'E' : 'F') : '.';
156157
const template = isFailed ? this.format.failed : this.format.finished;
157-
const vars = this.resultVars(result, statusDot);
158+
const vars = this.resultVars(result, statusDot, isError);
158159
const text = this.interpolate(template, vars);
159160

160161
return this.isDotMode ? text : this.line(text);
@@ -370,14 +371,15 @@ export class Printer {
370371
private resultVars(
371372
result: TestFinished | TestFailed | TestIgnored,
372373
statusDot: string,
374+
isError = false,
373375
): Record<string, string | undefined> {
374376
const [icon, label] = this.getIcon(result.event);
375377
const name = this.formatTestName(result);
376378
const colorize = this.getColorizer(result.event);
377379
const isFailed = result.event === TeamcityEvent.testFailed;
378380

379381
return {
380-
status_dot: colorize(statusDot),
382+
status_dot: this.colorizeStatusDot(statusDot, result.event, isError),
381383
icon: colorize(icon),
382384
label: colorize(label),
383385
name: isFailed ? name : this.style.info(name),
@@ -400,6 +402,21 @@ export class Printer {
400402
return this.style.passed.bind(this.style);
401403
}
402404

405+
private colorizeStatusDot(dot: string, event: TeamcityEvent, isError: boolean): string {
406+
if (!this.isDotMode) {
407+
return this.getColorizer(event)(dot);
408+
}
409+
410+
if (event === TeamcityEvent.testFailed) {
411+
return isError ? this.style.errorDot(dot) : this.style.failedDot(dot);
412+
}
413+
if (event === TeamcityEvent.testIgnored) {
414+
return this.style.skippedDot(dot);
415+
}
416+
417+
return this.style.info(dot);
418+
}
419+
403420
private infoVars(
404421
key: keyof IconSet,
405422
result: { text: string },

0 commit comments

Comments
 (0)