@wp-tester/results 0.0.1 → 0.0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/streaming.d.ts +198 -0
- package/dist/streaming.d.ts.map +1 -0
- package/dist/streaming.js +620 -0
- package/dist/streaming.js.map +1 -0
- package/dist/streaming.spec.d.ts +5 -0
- package/dist/streaming.spec.d.ts.map +1 -0
- package/dist/streaming.spec.js +217 -0
- package/dist/streaming.spec.js.map +1 -0
- package/dist/summary.d.ts +13 -0
- package/dist/summary.d.ts.map +1 -0
- package/dist/summary.js +40 -0
- package/dist/summary.js.map +1 -0
- package/dist/teamcity-parser.d.ts +70 -0
- package/dist/teamcity-parser.d.ts.map +1 -0
- package/dist/teamcity-parser.js +256 -0
- package/dist/teamcity-parser.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vitest-streaming-reporter.d.ts +67 -0
- package/dist/vitest-streaming-reporter.d.ts.map +1 -0
- package/dist/vitest-streaming-reporter.js +236 -0
- package/dist/vitest-streaming-reporter.js.map +1 -0
- package/package.json +5 -4
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for StreamingReporter
|
|
3
|
+
*/
|
|
4
|
+
import { describe, it, expect, beforeEach } from "vitest";
|
|
5
|
+
import { StreamingReporter } from "./streaming.js";
|
|
6
|
+
class MockWriter {
|
|
7
|
+
constructor() {
|
|
8
|
+
this.lines = [];
|
|
9
|
+
this.currentOutput = [];
|
|
10
|
+
}
|
|
11
|
+
write(text) {
|
|
12
|
+
// Handle ANSI clear codes
|
|
13
|
+
if (text === "\x1b[1A\x1b[2K") {
|
|
14
|
+
// Clear last line
|
|
15
|
+
this.currentOutput.pop();
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
this.lines.push(text);
|
|
19
|
+
this.currentOutput.push(text);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
writeLine(text) {
|
|
23
|
+
this.lines.push(text + "\n");
|
|
24
|
+
this.currentOutput.push(text + "\n");
|
|
25
|
+
}
|
|
26
|
+
getOutput() {
|
|
27
|
+
return this.lines.join("");
|
|
28
|
+
}
|
|
29
|
+
getCurrentOutput() {
|
|
30
|
+
return this.currentOutput.join("");
|
|
31
|
+
}
|
|
32
|
+
clear() {
|
|
33
|
+
this.lines = [];
|
|
34
|
+
this.currentOutput = [];
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
describe("StreamingReporter", () => {
|
|
38
|
+
let writer;
|
|
39
|
+
let reporter;
|
|
40
|
+
beforeEach(() => {
|
|
41
|
+
writer = new MockWriter();
|
|
42
|
+
reporter = new StreamingReporter({
|
|
43
|
+
writer,
|
|
44
|
+
showRunBoundaries: false, // Disable header for cleaner tests
|
|
45
|
+
showSummary: false, // Disable summary for cleaner tests
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
it("should handle a simple test pass", () => {
|
|
49
|
+
reporter.onEvent({ type: "run:start" });
|
|
50
|
+
reporter.onEvent({ type: "suite:start", name: "My Suite" });
|
|
51
|
+
reporter.onEvent({ type: "test:start", name: "test 1", suiteName: "My Suite" });
|
|
52
|
+
reporter.onEvent({ type: "test:pass", name: "test 1", duration: 100, suiteName: "My Suite" });
|
|
53
|
+
reporter.onEvent({ type: "suite:end", name: "My Suite" });
|
|
54
|
+
const output = writer.getOutput();
|
|
55
|
+
expect(output).toContain("My Suite");
|
|
56
|
+
expect(output).toContain("test 1");
|
|
57
|
+
expect(output).toContain("✓");
|
|
58
|
+
});
|
|
59
|
+
it("should handle parallel file execution without interference", () => {
|
|
60
|
+
reporter.onEvent({ type: "run:start" });
|
|
61
|
+
// Start two files in parallel
|
|
62
|
+
reporter.onEvent({ type: "file:start", fileId: "file1", fileName: "test1.spec.ts" });
|
|
63
|
+
reporter.onEvent({ type: "file:start", fileId: "file2", fileName: "test2.spec.ts" });
|
|
64
|
+
// File 1 starts a suite
|
|
65
|
+
reporter.onEvent({ type: "suite:start", name: "Suite 1", fileId: "file1" });
|
|
66
|
+
// File 2 starts a suite (parallel)
|
|
67
|
+
reporter.onEvent({ type: "suite:start", name: "Suite 2", fileId: "file2" });
|
|
68
|
+
// File 1 starts a test
|
|
69
|
+
reporter.onEvent({ type: "test:start", name: "test 1", suiteName: "Suite 1", fileId: "file1" });
|
|
70
|
+
// File 2 starts a test (parallel)
|
|
71
|
+
reporter.onEvent({ type: "test:start", name: "test 2", suiteName: "Suite 2", fileId: "file2" });
|
|
72
|
+
// File 1 test passes
|
|
73
|
+
reporter.onEvent({ type: "test:pass", name: "test 1", duration: 100, suiteName: "Suite 1", fileId: "file1" });
|
|
74
|
+
// File 2 test passes
|
|
75
|
+
reporter.onEvent({ type: "test:pass", name: "test 2", duration: 150, suiteName: "Suite 2", fileId: "file2" });
|
|
76
|
+
// End suites
|
|
77
|
+
reporter.onEvent({ type: "suite:end", name: "Suite 1", fileId: "file1" });
|
|
78
|
+
reporter.onEvent({ type: "suite:end", name: "Suite 2", fileId: "file2" });
|
|
79
|
+
// End files
|
|
80
|
+
reporter.onEvent({ type: "file:end", fileId: "file1" });
|
|
81
|
+
reporter.onEvent({ type: "file:end", fileId: "file2" });
|
|
82
|
+
const output = writer.getCurrentOutput();
|
|
83
|
+
// Both suites should be present
|
|
84
|
+
expect(output).toContain("Suite 1");
|
|
85
|
+
expect(output).toContain("Suite 2");
|
|
86
|
+
// Both tests should be present
|
|
87
|
+
expect(output).toContain("test 1");
|
|
88
|
+
expect(output).toContain("test 2");
|
|
89
|
+
// Both should show as passed
|
|
90
|
+
const passMarks = output.match(/✓/g);
|
|
91
|
+
expect(passMarks).toHaveLength(2);
|
|
92
|
+
// Verify counts
|
|
93
|
+
const counts = reporter.getCounts();
|
|
94
|
+
expect(counts.total).toBe(2);
|
|
95
|
+
expect(counts.passed).toBe(2);
|
|
96
|
+
expect(counts.failed).toBe(0);
|
|
97
|
+
});
|
|
98
|
+
it("should handle test failures with error messages", () => {
|
|
99
|
+
reporter.onEvent({ type: "run:start" });
|
|
100
|
+
reporter.onEvent({ type: "suite:start", name: "Suite" });
|
|
101
|
+
reporter.onEvent({ type: "test:start", name: "failing test", suiteName: "Suite" });
|
|
102
|
+
reporter.onEvent({
|
|
103
|
+
type: "test:fail",
|
|
104
|
+
name: "failing test",
|
|
105
|
+
duration: 50,
|
|
106
|
+
message: "Expected 1 to equal 2",
|
|
107
|
+
suiteName: "Suite"
|
|
108
|
+
});
|
|
109
|
+
reporter.onEvent({ type: "suite:end", name: "Suite" });
|
|
110
|
+
const output = writer.getOutput();
|
|
111
|
+
expect(output).toContain("failing test");
|
|
112
|
+
expect(output).toContain("✗");
|
|
113
|
+
expect(output).toContain("Expected 1 to equal 2");
|
|
114
|
+
const counts = reporter.getCounts();
|
|
115
|
+
expect(counts.failed).toBe(1);
|
|
116
|
+
});
|
|
117
|
+
it("should handle skipped tests", () => {
|
|
118
|
+
reporter.onEvent({ type: "run:start" });
|
|
119
|
+
reporter.onEvent({ type: "suite:start", name: "Suite" });
|
|
120
|
+
reporter.onEvent({
|
|
121
|
+
type: "test:skip",
|
|
122
|
+
name: "skipped test",
|
|
123
|
+
message: "Not implemented yet",
|
|
124
|
+
suiteName: "Suite"
|
|
125
|
+
});
|
|
126
|
+
reporter.onEvent({ type: "suite:end", name: "Suite" });
|
|
127
|
+
const output = writer.getOutput();
|
|
128
|
+
expect(output).toContain("skipped test");
|
|
129
|
+
expect(output).toContain("○");
|
|
130
|
+
expect(output).toContain("Not implemented yet");
|
|
131
|
+
const counts = reporter.getCounts();
|
|
132
|
+
expect(counts.skipped).toBe(1);
|
|
133
|
+
});
|
|
134
|
+
it("should generate correct CTRF report", () => {
|
|
135
|
+
reporter.onEvent({ type: "run:start", toolName: "test-runner" });
|
|
136
|
+
reporter.onEvent({ type: "suite:start", name: "Suite" });
|
|
137
|
+
reporter.onEvent({ type: "test:pass", name: "test 1", duration: 100, suiteName: "Suite" });
|
|
138
|
+
reporter.onEvent({ type: "test:fail", name: "test 2", duration: 50, message: "Error", suiteName: "Suite" });
|
|
139
|
+
reporter.onEvent({ type: "suite:end", name: "Suite" });
|
|
140
|
+
reporter.onEvent({ type: "run:end" });
|
|
141
|
+
const report = reporter.getReport();
|
|
142
|
+
expect(report.reportFormat).toBe("CTRF");
|
|
143
|
+
expect(report.results.tool.name).toBe("test-runner");
|
|
144
|
+
expect(report.results.summary.tests).toBe(2);
|
|
145
|
+
expect(report.results.summary.passed).toBe(1);
|
|
146
|
+
expect(report.results.summary.failed).toBe(1);
|
|
147
|
+
expect(report.results.tests).toHaveLength(2);
|
|
148
|
+
const passedTest = report.results.tests.find(t => t.status === "passed");
|
|
149
|
+
expect(passedTest?.name).toBe("Suite::test 1");
|
|
150
|
+
expect(passedTest?.duration).toBe(100);
|
|
151
|
+
const failedTest = report.results.tests.find(t => t.status === "failed");
|
|
152
|
+
expect(failedTest?.name).toBe("Suite::test 2");
|
|
153
|
+
expect(failedTest?.message).toBe("Error");
|
|
154
|
+
});
|
|
155
|
+
it("should handle interleaved parallel test events", () => {
|
|
156
|
+
reporter.onEvent({ type: "run:start" });
|
|
157
|
+
// Simulate realistic parallel execution with interleaved events
|
|
158
|
+
reporter.onEvent({ type: "file:start", fileId: "file1" });
|
|
159
|
+
reporter.onEvent({ type: "suite:start", name: "Suite A", fileId: "file1" });
|
|
160
|
+
reporter.onEvent({ type: "file:start", fileId: "file2" });
|
|
161
|
+
reporter.onEvent({ type: "test:start", name: "test A1", suiteName: "Suite A", fileId: "file1" });
|
|
162
|
+
reporter.onEvent({ type: "suite:start", name: "Suite B", fileId: "file2" });
|
|
163
|
+
reporter.onEvent({ type: "test:start", name: "test B1", suiteName: "Suite B", fileId: "file2" });
|
|
164
|
+
reporter.onEvent({ type: "test:pass", name: "test A1", duration: 100, suiteName: "Suite A", fileId: "file1" });
|
|
165
|
+
reporter.onEvent({ type: "test:start", name: "test A2", suiteName: "Suite A", fileId: "file1" });
|
|
166
|
+
reporter.onEvent({ type: "test:pass", name: "test B1", duration: 150, suiteName: "Suite B", fileId: "file2" });
|
|
167
|
+
reporter.onEvent({ type: "test:pass", name: "test A2", duration: 80, suiteName: "Suite A", fileId: "file1" });
|
|
168
|
+
reporter.onEvent({ type: "suite:end", name: "Suite A", fileId: "file1" });
|
|
169
|
+
reporter.onEvent({ type: "suite:end", name: "Suite B", fileId: "file2" });
|
|
170
|
+
reporter.onEvent({ type: "file:end", fileId: "file1" });
|
|
171
|
+
reporter.onEvent({ type: "file:end", fileId: "file2" });
|
|
172
|
+
const counts = reporter.getCounts();
|
|
173
|
+
expect(counts.total).toBe(3);
|
|
174
|
+
expect(counts.passed).toBe(3);
|
|
175
|
+
const output = writer.getOutput();
|
|
176
|
+
expect(output).toContain("Suite A");
|
|
177
|
+
expect(output).toContain("Suite B");
|
|
178
|
+
expect(output).toContain("test A1");
|
|
179
|
+
expect(output).toContain("test A2");
|
|
180
|
+
expect(output).toContain("test B1");
|
|
181
|
+
});
|
|
182
|
+
it("should handle nested suites", () => {
|
|
183
|
+
reporter.onEvent({ type: "run:start" });
|
|
184
|
+
reporter.onEvent({ type: "suite:start", name: "Outer Suite" });
|
|
185
|
+
reporter.onEvent({ type: "suite:start", name: "Inner Suite" });
|
|
186
|
+
reporter.onEvent({ type: "test:pass", name: "nested test", duration: 50, suiteName: "Inner Suite" });
|
|
187
|
+
reporter.onEvent({ type: "suite:end", name: "Inner Suite" });
|
|
188
|
+
reporter.onEvent({ type: "suite:end", name: "Outer Suite" });
|
|
189
|
+
const output = writer.getOutput();
|
|
190
|
+
expect(output).toContain("Outer Suite");
|
|
191
|
+
expect(output).toContain("Inner Suite");
|
|
192
|
+
expect(output).toContain("nested test");
|
|
193
|
+
});
|
|
194
|
+
it("should clean up running tests when suite ends", () => {
|
|
195
|
+
reporter.onEvent({ type: "run:start" });
|
|
196
|
+
reporter.onEvent({ type: "suite:start", name: "Suite" });
|
|
197
|
+
reporter.onEvent({ type: "test:start", name: "hanging test", suiteName: "Suite" });
|
|
198
|
+
// End suite without test completion - should clean up running test
|
|
199
|
+
reporter.onEvent({ type: "suite:end", name: "Suite" });
|
|
200
|
+
// Test should be marked as pending (not running)
|
|
201
|
+
const output = writer.getCurrentOutput();
|
|
202
|
+
expect(output).toContain("hanging test");
|
|
203
|
+
expect(output).toContain("○"); // pending status
|
|
204
|
+
});
|
|
205
|
+
it("should clean up all running tests when run ends", () => {
|
|
206
|
+
reporter.onEvent({ type: "run:start" });
|
|
207
|
+
reporter.onEvent({ type: "suite:start", name: "Suite" });
|
|
208
|
+
reporter.onEvent({ type: "test:start", name: "hanging test", suiteName: "Suite" });
|
|
209
|
+
// End run without completing test
|
|
210
|
+
reporter.onEvent({ type: "run:end" });
|
|
211
|
+
// Final output should not have any running tests
|
|
212
|
+
const output = writer.getCurrentOutput();
|
|
213
|
+
expect(output).toContain("hanging test");
|
|
214
|
+
expect(output).toContain("○"); // marked as pending, not running
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
//# sourceMappingURL=streaming.spec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"streaming.spec.js","sourceRoot":"","sources":["../src/streaming.spec.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAC1D,OAAO,EAAE,iBAAiB,EAAqB,MAAM,gBAAgB,CAAC;AAEtE,MAAM,UAAU;IAAhB;QACE,UAAK,GAAa,EAAE,CAAC;QACrB,kBAAa,GAAa,EAAE,CAAC;IA8B/B,CAAC;IA5BC,KAAK,CAAC,IAAY;QAChB,0BAA0B;QAC1B,IAAI,IAAI,KAAK,gBAAgB,EAAE,CAAC;YAC9B,kBAAkB;YAClB,IAAI,CAAC,aAAa,CAAC,GAAG,EAAE,CAAC;QAC3B,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAChC,CAAC;IACH,CAAC;IAED,SAAS,CAAC,IAAY;QACpB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;QAC7B,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACvC,CAAC;IAED,SAAS;QACP,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,gBAAgB;QACd,OAAO,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,KAAK;QACH,IAAI,CAAC,KAAK,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,aAAa,GAAG,EAAE,CAAC;IAC1B,CAAC;CACF;AAED,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,IAAI,MAAkB,CAAC;IACvB,IAAI,QAA2B,CAAC;IAEhC,UAAU,CAAC,GAAG,EAAE;QACd,MAAM,GAAG,IAAI,UAAU,EAAE,CAAC;QAC1B,QAAQ,GAAG,IAAI,iBAAiB,CAAC;YAC/B,MAAM;YACN,iBAAiB,EAAE,KAAK,EAAE,mCAAmC;YAC7D,WAAW,EAAE,KAAK,EAAE,oCAAoC;SACzD,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,GAAG,EAAE;QAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAC5D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QAChF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;QAC9F,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QAE1D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;QACrC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,4DAA4D,EAAE,GAAG,EAAE;QACpE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAExC,8BAA8B;QAC9B,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;QACrF,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,EAAE,CAAC,CAAC;QAErF,wBAAwB;QACxB,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAE5E,mCAAmC;QACnC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAE5E,uBAAuB;QACvB,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhG,kCAAkC;QAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAEhG,qBAAqB;QACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAE9G,qBAAqB;QACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAE9G,aAAa;QACb,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAE1E,YAAY;QACZ,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;QAEzC,gCAAgC;QAChC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QAEpC,+BAA+B;QAC/B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEnC,6BAA6B;QAC7B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAElC,gBAAgB;QAChB,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QACnF,QAAQ,CAAC,OAAO,CAAC;YACf,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,cAAc;YACpB,QAAQ,EAAE,EAAE;YACZ,OAAO,EAAE,uBAAuB;YAChC,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,uBAAuB,CAAC,CAAC;QAElD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,OAAO,CAAC;YACf,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,cAAc;YACpB,OAAO,EAAE,qBAAqB;YAC9B,SAAS,EAAE,OAAO;SACnB,CAAC,CAAC;QACH,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAEvD,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;QAC9B,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,qBAAqB,CAAC,CAAC;QAEhD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC;QACjE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QAC3F,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5G,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAEtC,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QAEpC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QACrD,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC9C,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAE7C,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QACzE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEvC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC;QACzE,MAAM,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,eAAe,CAAC,CAAC;QAC/C,MAAM,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QAExC,gEAAgE;QAChE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC5E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/G,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACjG,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC/G,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC9G,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAC1E,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QACxD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC;QAExD,MAAM,MAAM,GAAG,QAAQ,CAAC,SAAS,EAAE,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAE9B,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;QACpC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IACtC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,GAAG,EAAE;QACrC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAC/D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;QACrG,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAC7D,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,CAAC;QAE7D,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,CAAC;QAClC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;IAC1C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+CAA+C,EAAE,GAAG,EAAE;QACvD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QAEnF,mEAAmE;QACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QAEvD,iDAAiD;QACjD,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,iBAAiB;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC;QACxC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,CAAC;QACzD,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC;QAEnF,kCAAkC;QAClC,QAAQ,CAAC,OAAO,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;QAEtC,iDAAiD;QACjD,MAAM,MAAM,GAAG,MAAM,CAAC,gBAAgB,EAAE,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,iCAAiC;IAClE,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Summary Output
|
|
3
|
+
*
|
|
4
|
+
* Provides formatted test summary output using clack/prompts for consistent CLI display.
|
|
5
|
+
*/
|
|
6
|
+
import type { Summary } from "ctrf";
|
|
7
|
+
/**
|
|
8
|
+
* Print test summary to console
|
|
9
|
+
*
|
|
10
|
+
* @param summary - The test summary from a CTRF report
|
|
11
|
+
*/
|
|
12
|
+
export declare function printSummary(summary: Summary): void;
|
|
13
|
+
//# sourceMappingURL=summary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.d.ts","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAapC;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqBnD"}
|
package/dist/summary.js
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Summary Output
|
|
3
|
+
*
|
|
4
|
+
* Provides formatted test summary output using clack/prompts for consistent CLI display.
|
|
5
|
+
*/
|
|
6
|
+
import pc from "picocolors";
|
|
7
|
+
/**
|
|
8
|
+
* Format duration in human-readable format
|
|
9
|
+
*/
|
|
10
|
+
function formatDuration(ms) {
|
|
11
|
+
if (ms < 1000) {
|
|
12
|
+
return `${Math.round(ms)}ms`;
|
|
13
|
+
}
|
|
14
|
+
return `${(ms / 1000).toFixed(2)}s`;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Print test summary to console
|
|
18
|
+
*
|
|
19
|
+
* @param summary - The test summary from a CTRF report
|
|
20
|
+
*/
|
|
21
|
+
export function printSummary(summary) {
|
|
22
|
+
const duration = summary.stop - summary.start;
|
|
23
|
+
console.log("");
|
|
24
|
+
if (summary.passed > 0) {
|
|
25
|
+
console.log(pc.green(` ✓ ${summary.passed} passed`));
|
|
26
|
+
}
|
|
27
|
+
if (summary.failed > 0) {
|
|
28
|
+
console.log(pc.red(` ✗ ${summary.failed} failed`));
|
|
29
|
+
}
|
|
30
|
+
if (summary.skipped > 0) {
|
|
31
|
+
console.log(pc.yellow(` ○ ${summary.skipped} skipped`));
|
|
32
|
+
}
|
|
33
|
+
if (summary.pending > 0) {
|
|
34
|
+
console.log(pc.yellow(` ○ ${summary.pending} pending`));
|
|
35
|
+
}
|
|
36
|
+
console.log("");
|
|
37
|
+
console.log(pc.dim(` ${summary.tests} tests in ${formatDuration(duration)}`));
|
|
38
|
+
console.log("");
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../src/summary.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,MAAM,YAAY,CAAC;AAE5B;;GAEG;AACH,SAAS,cAAc,CAAC,EAAU;IAChC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;QACd,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,IAAI,CAAC;IAC/B,CAAC;IACD,OAAO,GAAG,CAAC,EAAE,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;AACtC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAAgB;IAC3C,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC;IAE9C,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,KAAK,CAAC,OAAO,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC,MAAM,SAAS,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,OAAO,CAAC,OAAO,GAAG,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,OAAO,OAAO,CAAC,OAAO,UAAU,CAAC,CAAC,CAAC;IAC3D,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAChB,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,KAAK,aAAa,cAAc,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC;IAC/E,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamCity Format Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses PHPUnit's TeamCity output format for real-time test result streaming.
|
|
5
|
+
* TeamCity format is designed for streaming and emits structured messages
|
|
6
|
+
* as tests execute.
|
|
7
|
+
*
|
|
8
|
+
* Format reference:
|
|
9
|
+
* ##teamcity[testSuiteStarted name='SuiteName' ...]
|
|
10
|
+
* ##teamcity[testStarted name='testName' ...]
|
|
11
|
+
* ##teamcity[testFinished name='testName' duration='123']
|
|
12
|
+
* ##teamcity[testFailed name='testName' message='error' details='trace']
|
|
13
|
+
* ##teamcity[testIgnored name='testName' message='reason']
|
|
14
|
+
* ##teamcity[testSuiteFinished name='SuiteName']
|
|
15
|
+
*/
|
|
16
|
+
import type { StreamEvent } from "./streaming.js";
|
|
17
|
+
import type { StreamingReporter } from "./streaming.js";
|
|
18
|
+
/**
|
|
19
|
+
* TeamCity stream parser that converts PHPUnit output to StreamEvents
|
|
20
|
+
*/
|
|
21
|
+
export declare class TeamCityParser {
|
|
22
|
+
private buffer;
|
|
23
|
+
private currentSuite;
|
|
24
|
+
private testStartTimes;
|
|
25
|
+
private completedTests;
|
|
26
|
+
private reporter;
|
|
27
|
+
private onEvent;
|
|
28
|
+
/**
|
|
29
|
+
* Create a parser that sends events to a StreamingReporter
|
|
30
|
+
*/
|
|
31
|
+
static withReporter(reporter: StreamingReporter): TeamCityParser;
|
|
32
|
+
/**
|
|
33
|
+
* Create a parser with a custom event handler
|
|
34
|
+
*/
|
|
35
|
+
static withEventHandler(onEvent: (event: StreamEvent) => void): TeamCityParser;
|
|
36
|
+
/**
|
|
37
|
+
* Emit an event to the reporter or handler
|
|
38
|
+
*/
|
|
39
|
+
private emit;
|
|
40
|
+
/**
|
|
41
|
+
* Process a chunk of data from PHPUnit output
|
|
42
|
+
* Handles partial lines by buffering
|
|
43
|
+
*/
|
|
44
|
+
write(chunk: string): void;
|
|
45
|
+
/**
|
|
46
|
+
* Flush any remaining buffered data
|
|
47
|
+
*/
|
|
48
|
+
flush(): void;
|
|
49
|
+
/**
|
|
50
|
+
* Process a single line of output
|
|
51
|
+
*/
|
|
52
|
+
private processLine;
|
|
53
|
+
/**
|
|
54
|
+
* Handle a parsed TeamCity message
|
|
55
|
+
*/
|
|
56
|
+
private handleMessage;
|
|
57
|
+
/**
|
|
58
|
+
* Reset the parser state
|
|
59
|
+
*/
|
|
60
|
+
reset(): void;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Create a WritableStream that parses TeamCity format and emits events
|
|
64
|
+
*/
|
|
65
|
+
export declare function createTeamCityParserStream(reporter: StreamingReporter): WritableStream<string>;
|
|
66
|
+
/**
|
|
67
|
+
* Parse TeamCity output and return events (for testing or one-shot parsing)
|
|
68
|
+
*/
|
|
69
|
+
export declare function parseTeamCityOutput(output: string): StreamEvent[];
|
|
70
|
+
//# sourceMappingURL=teamcity-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teamcity-parser.d.ts","sourceRoot":"","sources":["../src/teamcity-parser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAClD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAwExD;;GAEG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,YAAY,CAAuB;IAC3C,OAAO,CAAC,cAAc,CAAkC;IACxD,OAAO,CAAC,cAAc,CAA0B;IAChD,OAAO,CAAC,QAAQ,CAAkC;IAClD,OAAO,CAAC,OAAO,CAA+C;IAE9D;;OAEG;IACH,MAAM,CAAC,YAAY,CAAC,QAAQ,EAAE,iBAAiB,GAAG,cAAc;IAMhE;;OAEG;IACH,MAAM,CAAC,gBAAgB,CACrB,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,GACpC,cAAc;IAMjB;;OAEG;IACH,OAAO,CAAC,IAAI;IASZ;;;OAGG;IACH,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAa1B;;OAEG;IACH,KAAK,IAAI,IAAI;IAOb;;OAEG;IACH,OAAO,CAAC,WAAW;IAcnB;;OAEG;IACH,OAAO,CAAC,aAAa;IA6FrB;;OAEG;IACH,KAAK,IAAI,IAAI;CAMd;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CACxC,QAAQ,EAAE,iBAAiB,GAC1B,cAAc,CAAC,MAAM,CAAC,CAWxB;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW,EAAE,CAQjE"}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TeamCity Format Parser
|
|
3
|
+
*
|
|
4
|
+
* Parses PHPUnit's TeamCity output format for real-time test result streaming.
|
|
5
|
+
* TeamCity format is designed for streaming and emits structured messages
|
|
6
|
+
* as tests execute.
|
|
7
|
+
*
|
|
8
|
+
* Format reference:
|
|
9
|
+
* ##teamcity[testSuiteStarted name='SuiteName' ...]
|
|
10
|
+
* ##teamcity[testStarted name='testName' ...]
|
|
11
|
+
* ##teamcity[testFinished name='testName' duration='123']
|
|
12
|
+
* ##teamcity[testFailed name='testName' message='error' details='trace']
|
|
13
|
+
* ##teamcity[testIgnored name='testName' message='reason']
|
|
14
|
+
* ##teamcity[testSuiteFinished name='SuiteName']
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* Unescape TeamCity string values
|
|
18
|
+
* TeamCity uses special escaping for certain characters:
|
|
19
|
+
* - |' -> '
|
|
20
|
+
* - |n -> newline
|
|
21
|
+
* - |r -> carriage return
|
|
22
|
+
* - |[ -> [
|
|
23
|
+
* - |] -> ]
|
|
24
|
+
* - || -> |
|
|
25
|
+
*/
|
|
26
|
+
function unescapeTeamCityValue(value) {
|
|
27
|
+
return value
|
|
28
|
+
.replace(/\|'/g, "'")
|
|
29
|
+
.replace(/\|n/g, "\n")
|
|
30
|
+
.replace(/\|r/g, "\r")
|
|
31
|
+
.replace(/\|\[/g, "[")
|
|
32
|
+
.replace(/\|\]/g, "]")
|
|
33
|
+
.replace(/\|\|/g, "|");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Parse a single TeamCity message line
|
|
37
|
+
*/
|
|
38
|
+
function parseTeamCityLine(line) {
|
|
39
|
+
// Match the TeamCity format: ##teamcity[messageName attr1='value1' attr2='value2']
|
|
40
|
+
const match = line.match(/^##teamcity\[(\w+)\s*(.*)\]$/);
|
|
41
|
+
if (!match) {
|
|
42
|
+
return null;
|
|
43
|
+
}
|
|
44
|
+
const [, type, attributesStr] = match;
|
|
45
|
+
// Parse attributes (name='value' pairs)
|
|
46
|
+
// Values can contain escaped characters like |' (quote), |n (newline), || (pipe)
|
|
47
|
+
// The pattern matches: non-quote/non-pipe chars OR pipe followed by any char (or lookahead for quote)
|
|
48
|
+
// The lookahead (?=') handles edge case of pipes at end of value before closing quote
|
|
49
|
+
const attributes = {};
|
|
50
|
+
const attrRegex = /(\w+)='((?:[^'|]|\|(?:.|(?=')))*?)'/g;
|
|
51
|
+
let attrMatch;
|
|
52
|
+
while ((attrMatch = attrRegex.exec(attributesStr)) !== null) {
|
|
53
|
+
const [, key, value] = attrMatch;
|
|
54
|
+
attributes[key] = unescapeTeamCityValue(value);
|
|
55
|
+
}
|
|
56
|
+
return {
|
|
57
|
+
type: type,
|
|
58
|
+
attributes,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* TeamCity stream parser that converts PHPUnit output to StreamEvents
|
|
63
|
+
*/
|
|
64
|
+
export class TeamCityParser {
|
|
65
|
+
constructor() {
|
|
66
|
+
this.buffer = "";
|
|
67
|
+
this.currentSuite = null;
|
|
68
|
+
this.testStartTimes = new Map();
|
|
69
|
+
this.completedTests = new Set(); // Track tests that already reported result
|
|
70
|
+
this.reporter = null;
|
|
71
|
+
this.onEvent = null;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a parser that sends events to a StreamingReporter
|
|
75
|
+
*/
|
|
76
|
+
static withReporter(reporter) {
|
|
77
|
+
const parser = new TeamCityParser();
|
|
78
|
+
parser.reporter = reporter;
|
|
79
|
+
return parser;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Create a parser with a custom event handler
|
|
83
|
+
*/
|
|
84
|
+
static withEventHandler(onEvent) {
|
|
85
|
+
const parser = new TeamCityParser();
|
|
86
|
+
parser.onEvent = onEvent;
|
|
87
|
+
return parser;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Emit an event to the reporter or handler
|
|
91
|
+
*/
|
|
92
|
+
emit(event) {
|
|
93
|
+
if (this.reporter) {
|
|
94
|
+
this.reporter.onEvent(event);
|
|
95
|
+
}
|
|
96
|
+
if (this.onEvent) {
|
|
97
|
+
this.onEvent(event);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Process a chunk of data from PHPUnit output
|
|
102
|
+
* Handles partial lines by buffering
|
|
103
|
+
*/
|
|
104
|
+
write(chunk) {
|
|
105
|
+
this.buffer += chunk;
|
|
106
|
+
// Process complete lines
|
|
107
|
+
const lines = this.buffer.split("\n");
|
|
108
|
+
// Keep the last incomplete line in the buffer
|
|
109
|
+
this.buffer = lines.pop() || "";
|
|
110
|
+
for (const line of lines) {
|
|
111
|
+
this.processLine(line);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Flush any remaining buffered data
|
|
116
|
+
*/
|
|
117
|
+
flush() {
|
|
118
|
+
if (this.buffer.trim()) {
|
|
119
|
+
this.processLine(this.buffer);
|
|
120
|
+
this.buffer = "";
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Process a single line of output
|
|
125
|
+
*/
|
|
126
|
+
processLine(line) {
|
|
127
|
+
const trimmed = line.trim();
|
|
128
|
+
if (!trimmed.startsWith("##teamcity[")) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const message = parseTeamCityLine(trimmed);
|
|
132
|
+
if (!message) {
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
this.handleMessage(message);
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Handle a parsed TeamCity message
|
|
139
|
+
*/
|
|
140
|
+
handleMessage(message) {
|
|
141
|
+
const { type, attributes } = message;
|
|
142
|
+
const name = attributes.name || "Unknown";
|
|
143
|
+
switch (type) {
|
|
144
|
+
case "testSuiteStarted":
|
|
145
|
+
this.currentSuite = name;
|
|
146
|
+
this.emit({
|
|
147
|
+
type: "suite:start",
|
|
148
|
+
name,
|
|
149
|
+
});
|
|
150
|
+
break;
|
|
151
|
+
case "testSuiteFinished":
|
|
152
|
+
this.emit({
|
|
153
|
+
type: "suite:end",
|
|
154
|
+
name,
|
|
155
|
+
});
|
|
156
|
+
if (this.currentSuite === name) {
|
|
157
|
+
this.currentSuite = null;
|
|
158
|
+
}
|
|
159
|
+
break;
|
|
160
|
+
case "testStarted":
|
|
161
|
+
this.testStartTimes.set(name, Date.now());
|
|
162
|
+
this.emit({
|
|
163
|
+
type: "test:start",
|
|
164
|
+
name,
|
|
165
|
+
suiteName: this.currentSuite || undefined,
|
|
166
|
+
});
|
|
167
|
+
break;
|
|
168
|
+
case "testFinished": {
|
|
169
|
+
// In TeamCity format, testFailed/testIgnored is followed by testFinished
|
|
170
|
+
// Skip if we already reported this test as failed/skipped
|
|
171
|
+
if (this.completedTests.has(name)) {
|
|
172
|
+
this.completedTests.delete(name);
|
|
173
|
+
break;
|
|
174
|
+
}
|
|
175
|
+
const startTime = this.testStartTimes.get(name);
|
|
176
|
+
const duration = attributes.duration
|
|
177
|
+
? parseInt(attributes.duration, 10)
|
|
178
|
+
: startTime
|
|
179
|
+
? Date.now() - startTime
|
|
180
|
+
: 0;
|
|
181
|
+
this.testStartTimes.delete(name);
|
|
182
|
+
this.emit({
|
|
183
|
+
type: "test:pass",
|
|
184
|
+
name,
|
|
185
|
+
suiteName: this.currentSuite || undefined,
|
|
186
|
+
duration,
|
|
187
|
+
});
|
|
188
|
+
break;
|
|
189
|
+
}
|
|
190
|
+
case "testFailed": {
|
|
191
|
+
const startTime = this.testStartTimes.get(name);
|
|
192
|
+
const duration = attributes.duration
|
|
193
|
+
? parseInt(attributes.duration, 10)
|
|
194
|
+
: startTime
|
|
195
|
+
? Date.now() - startTime
|
|
196
|
+
: 0;
|
|
197
|
+
this.testStartTimes.delete(name);
|
|
198
|
+
this.completedTests.add(name); // Mark as completed to skip testFinished
|
|
199
|
+
this.emit({
|
|
200
|
+
type: "test:fail",
|
|
201
|
+
name,
|
|
202
|
+
suiteName: this.currentSuite || undefined,
|
|
203
|
+
duration,
|
|
204
|
+
message: attributes.message,
|
|
205
|
+
trace: attributes.details,
|
|
206
|
+
});
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
case "testIgnored": {
|
|
210
|
+
this.testStartTimes.delete(name);
|
|
211
|
+
this.completedTests.add(name); // Mark as completed to skip testFinished
|
|
212
|
+
this.emit({
|
|
213
|
+
type: "test:skip",
|
|
214
|
+
name,
|
|
215
|
+
suiteName: this.currentSuite || undefined,
|
|
216
|
+
message: attributes.message,
|
|
217
|
+
});
|
|
218
|
+
break;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Reset the parser state
|
|
224
|
+
*/
|
|
225
|
+
reset() {
|
|
226
|
+
this.buffer = "";
|
|
227
|
+
this.currentSuite = null;
|
|
228
|
+
this.testStartTimes.clear();
|
|
229
|
+
this.completedTests.clear();
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a WritableStream that parses TeamCity format and emits events
|
|
234
|
+
*/
|
|
235
|
+
export function createTeamCityParserStream(reporter) {
|
|
236
|
+
const parser = TeamCityParser.withReporter(reporter);
|
|
237
|
+
return new WritableStream({
|
|
238
|
+
write(chunk) {
|
|
239
|
+
parser.write(chunk);
|
|
240
|
+
},
|
|
241
|
+
close() {
|
|
242
|
+
parser.flush();
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Parse TeamCity output and return events (for testing or one-shot parsing)
|
|
248
|
+
*/
|
|
249
|
+
export function parseTeamCityOutput(output) {
|
|
250
|
+
const events = [];
|
|
251
|
+
const parser = TeamCityParser.withEventHandler((event) => events.push(event));
|
|
252
|
+
parser.write(output);
|
|
253
|
+
parser.flush();
|
|
254
|
+
return events;
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=teamcity-parser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"teamcity-parser.js","sourceRoot":"","sources":["../src/teamcity-parser.ts"],"names":[],"mappings":"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"}
|