Skip to content

Commit 4ecc3d7

Browse files
committed
feat(histogram data): expose histogram sample data to custom reporters via sampleData property
1 parent 97d65a7 commit 4ecc3d7

File tree

2 files changed

+86
-1
lines changed

2 files changed

+86
-1
lines changed

lib/lifecycle.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,14 +134,17 @@ async function runBenchmark(bench, initialIterations, repeatSuite, minSamples) {
134134

135135
const opsSec = totalIterations / (totalTimeSpent / timer.scale);
136136

137+
const sampleData = histogram.samples;
138+
137139
return {
138140
opsSec,
139141
iterations: totalIterations,
140142
// StatisticalHistogram is not a serializable object
141143
histogram: {
142-
samples: histogram.samples.length,
144+
samples: sampleData.length,
143145
min: histogram.min,
144146
max: histogram.max,
147+
sampleData,
145148
},
146149
name: bench.name,
147150
plugins: parsePluginsResult(bench.plugins, bench.name),

test/reporter.js

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,88 @@ describe("htmlReport should create a file", async (t) => {
135135
});
136136
});
137137

138+
describe("custom reporter should have access to histogram data", async () => {
139+
let output = "";
140+
141+
before(async () => {
142+
const originalStdoutWrite = process.stdout.write;
143+
process.stdout.write = (data) => {
144+
output += data;
145+
};
146+
147+
function customReporter(results) {
148+
const json = [];
149+
for (const result of results) {
150+
// Calculate the median of result.histogram.sampleData:
151+
const sorted = [...result.histogram.sampleData].sort((a, b) => a - b);
152+
const median =
153+
sorted.length % 2 === 0
154+
? (sorted[sorted.length / 2 - 1] + sorted[sorted.length / 2]) / 2
155+
: sorted[Math.floor(sorted.length / 2)];
156+
157+
json.push({
158+
name: result.name,
159+
low: result.histogram.sampleData.filter((v) => v <= median),
160+
high: result.histogram.sampleData.filter((v) => v >= median),
161+
median,
162+
});
163+
}
164+
console.log(JSON.stringify(json, null, 2));
165+
}
166+
167+
// Create a new Suite with the custom reporter
168+
const suite = new Suite({
169+
reporter: customReporter,
170+
});
171+
172+
suite
173+
.add("single with matcher", () => {
174+
const pattern = /[123]/g;
175+
const replacements = { 1: "a", 2: "b", 3: "c" };
176+
const subject = "123123123123123123123123123123123123123123123123";
177+
const r = subject.replace(pattern, (m) => replacements[m]);
178+
assert.ok(r);
179+
})
180+
.add("Multiple replaces", () => {
181+
const subject = "123123123123123123123123123123123123123123123123";
182+
const r = subject
183+
.replace(/1/g, "a")
184+
.replace(/2/g, "b")
185+
.replace(/3/g, "c");
186+
assert.ok(r);
187+
});
188+
189+
// Run the suite
190+
await suite.run();
191+
192+
// Restore stdout
193+
process.stdout.write = originalStdoutWrite;
194+
});
195+
196+
it("should print valid JSON", () => {
197+
// Verify if the output can be parsed as JSON
198+
let data;
199+
try {
200+
data = JSON.parse(output);
201+
} catch (err) {
202+
assert.fail(`Output is not valid JSON: ${err.message}`);
203+
}
204+
205+
assert.ok(Array.isArray(data), "Output should be an array of results");
206+
});
207+
208+
it("should calculate median correctly", () => {
209+
const data = JSON.parse(output);
210+
for (const result of data) {
211+
assert.strictEqual(
212+
result.low.length,
213+
result.high.length,
214+
"Same number of samples above and below median",
215+
);
216+
}
217+
});
218+
});
219+
138220
describe("jsonReport should produce valid JSON output", async () => {
139221
let output = "";
140222

0 commit comments

Comments
 (0)