Skip to content

Commit

Permalink
feat: add JSONReporter
Browse files Browse the repository at this point in the history
  • Loading branch information
RafaelGSS committed Dec 23, 2024
1 parent e422af0 commit e65d296
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 2 deletions.
21 changes: 21 additions & 0 deletions examples/json-report/node.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
const { Suite, jsonReport } = require('../../lib');
const assert = require('node:assert');

const suite = new Suite({
reporter: jsonReport,
});

suite
.add('single with matcher', function () {
const pattern = /[123]/g
const replacements = { 1: 'a', 2: 'b', 3: 'c' }
const subject = '123123123123123123123123123123123123123123123123'
const r = subject.replace(pattern, m => replacements[m])
assert.ok(r);
})
.add('Multiple replaces', function () {
const subject = '123123123123123123123123123123123123123123123123'
const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
assert.ok(r);
})
.run();
8 changes: 7 additions & 1 deletion lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ const { Worker } = require('node:worker_threads');
const { types } = require('node:util');
const path = require('node:path');

const { textReport, chartReport, htmlReport } = require('./report');
const {
textReport,
chartReport,
htmlReport,
jsonReport,
} = require('./report');
const { getInitialIterations, runBenchmark, runWarmup } = require('./lifecycle');
const { debugBench, timer, createFnString } = require('./clock');
const {
Expand Down Expand Up @@ -203,4 +208,5 @@ module.exports = {
chartReport,
textReport,
htmlReport,
jsonReport,
};
2 changes: 2 additions & 0 deletions lib/report.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
const { textReport } = require('./reporter/text');
const { chartReport } = require('./reporter/chart');
const { htmlReport } = require('./reporter/html');
const { jsonReport } = require('./reporter/json');

module.exports = {
chartReport,
textReport,
htmlReport,
jsonReport,
};
28 changes: 28 additions & 0 deletions lib/reporter/json.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict'

const { timer } = require('../clock')

function jsonReport (results) {
const output = results.map((result) => {
const opsSecReported =
result.opsSec < 100
? result.opsSec.toFixed(2)
: result.opsSec.toFixed(0)

return {
name: result.name,
opsSec: Number(opsSecReported),
runsSampled: result.histogram.samples.length,
min: timer.format(result.histogram.min),
max: timer.format(result.histogram.max),
// Report anything the plugins returned
plugins: result.plugins.map((p) => p.report).filter(Boolean)
}
})

console.log(JSON.stringify(output, null, 2))
}

module.exports = {
jsonReport
}
72 changes: 71 additions & 1 deletion test/reporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@ const { describe, it, before } = require('node:test');
const assert = require('node:assert');
const fs = require('node:fs');

const { Suite, chartReport, htmlReport } = require('../lib');
const {
Suite,
chartReport,
htmlReport,
jsonReport,
} = require('../lib');

describe('chartReport outputs benchmark results as a bar chart', async (t) => {
let output = '';
Expand Down Expand Up @@ -107,3 +112,68 @@ describe('htmlReport should create a file', async (t) => {
assert.ok(htmlContent.includes('}}') === false);
});
});

describe('jsonReport should produce valid JSON output', async () => {
let output = ''

before(async () => {
const originalStdoutWrite = process.stdout.write
process.stdout.write = function (data) {
output += data
}

// Create a new Suite with the JSON reporter
const suite = new Suite({
reporter: jsonReport
})

suite
.add('single with matcher', function () {
const pattern = /[123]/g
const replacements = { 1: 'a', 2: 'b', 3: 'c' }
const subject = '123123123123123123123123123123123123123123123123'
const r = subject.replace(pattern, (m) => replacements[m])
assert.ok(r)
})
.add('Multiple replaces', function () {
const subject = '123123123123123123123123123123123123123123123123'
const r = subject.replace(/1/g, 'a').replace(/2/g, 'b').replace(/3/g, 'c')
assert.ok(r)
})

// Run the suite
await suite.run()

// Restore stdout
process.stdout.write = originalStdoutWrite
});

it('should print valid JSON', () => {
// Verify if the output can be parsed as JSON
let data
try {
data = JSON.parse(output)
} catch (err) {
assert.fail(`Output is not valid JSON: ${err.message}`)
}

assert.ok(Array.isArray(data), 'Output should be an array of results')
});

it('should contain the required benchmark fields', () => {
const data = JSON.parse(output)

// We expect the two benchmarks we added: 'single with matcher' and 'Multiple replaces'
assert.strictEqual(data.length, 2, 'Should have results for 2 benchmarks')

for (const entry of data) {
// Ensure each entry has expected keys
assert.ok(typeof entry.name === 'string', 'name should be a string')
assert.ok(typeof entry.opsSec === 'number', 'opsSec should be a number')
assert.ok(typeof entry.runsSampled === 'number', 'runsSampled should be a number')
assert.ok(typeof entry.min === 'string', 'min should be a string (formatted time)')
assert.ok(typeof entry.max === 'string', 'max should be a string (formatted time)')
assert.ok(Array.isArray(entry.plugins), 'plugins should be an array')
}
});
});

0 comments on commit e65d296

Please sign in to comment.