Skip to content

Commit

Permalink
lib: add afterEach hook option to each benchmark
Browse files Browse the repository at this point in the history
Fixes: #31
  • Loading branch information
RafaelGSS committed Dec 30, 2024
1 parent 11c1108 commit 7575b7e
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 7 deletions.
9 changes: 8 additions & 1 deletion lib/clock.js
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ let i = 0;
let ${varNames.context} = {};
`;

const hasAfterEach = bench.afterEach ? true : false;
let benchFnCall = `${awaitOrEmpty}${varNames.bench}.fn()`;
const wrapFunctions = [];
for (const p of bench.plugins) {
Expand All @@ -126,11 +127,17 @@ let ${varNames.context} = {};
return `${n}(${prev})`;
}, benchFnCall);

let awaitOrEmptyAfterEach = "";
if (hasAfterEach && types.isAsyncFunction(bench.afterEach)) {
awaitOrEmptyAfterEach = "await ";
}
code += `
const startedAt = ${varNames.timer}.now();
for (; i < count; i++)
for (; i < count; i++) {
${benchFnCall};
${hasAfterEach ? `${awaitOrEmptyAfterEach}${varNames.bench}.afterEach();` : ""}
}
const duration = Number(${varNames.timer}.now() - startedAt);
`;
Expand Down
28 changes: 23 additions & 5 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,17 @@ class Benchmark {
plugins;
repeatSuite;

constructor(name, fn, minTime, maxTime, plugins, repeatSuite) {
constructor(
name,
fn,
{ minTime, maxTime, plugins, repeatSuite, afterEach }) {
this.name = name;
this.fn = fn;
this.minTime = minTime;
this.maxTime = maxTime;
this.plugins = plugins;
this.repeatSuite = repeatSuite;
this.afterEach = afterEach;

this.hasArg = this.fn.length >= 1;
if (this.fn.length > 1) {
Expand Down Expand Up @@ -130,13 +134,27 @@ class Suite {
}
validateFunction(fn, "fn");

// Validate afterEach usage with workers
if (options.afterEach) {
validateFunction(options.afterEach, "options.afterEach");
if (this.#useWorkers) {
throw new Error(
`The "afterEach" hook is not supported when using Worker Threads. ` +
`Remove "afterEach" from the benchmark "${name}" or set "useWorkers: false".`
);
}
}

const benchmark = new Benchmark(
name,
fn,
options.minTime,
options.maxTime,
this.#plugins,
options.repeatSuite,
{
minTime: options.minTime,
maxTime: options.maxTime,
plugins: this.#plugins,
repeatSuite: options.repeatSuite,
afterEach: options.afterEach,
}
);
this.#benchmarks.push(benchmark);
return this;
Expand Down
3 changes: 3 additions & 0 deletions test/fixtures/cached.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
module.exports = {
foo: 'bar'
}
70 changes: 70 additions & 0 deletions test/hooks.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
const { describe, it } = require("node:test");
const assert = require("node:assert");
const path = require("node:path");
const { Suite } = require("../lib/index");

describe("afterEach hook", () => {
it("should call afterEach after every iteration in unmanaged benchmarks", async () => {
let afterEachCallCount = 0;
const suite = new Suite({ reporter: () => {} });

suite.add(
"unmanaged with afterEach",
{
afterEach: () => {
afterEachCallCount++;
},
},
() => {
const sum = 1 + 2; // Benchmark logic
return sum;
}
);

await suite.run();

// Validate afterEach was called correctly
assert.ok(afterEachCallCount > 0, "afterEach was not called");
});

it("should be called after each iteration of a benchmark", async () => {
const suite = new Suite({ reporter: () => {} });
const cachedModule = path.resolve(path.join(__dirname, "./fixtures/cached.js"));

suite.add(
"unmanaged with afterEach",
{
afterEach: () => {
delete require.cache[cachedModule]
},
},
() => {
assert.ok(require.cache[cachedModule] === undefined);
require(cachedModule);
assert.ok(require.cache[cachedModule] !== undefined);
}
);

await suite.run();
assert.ok(require.cache[cachedModule] === undefined);
});

it("should throw error when afterEach is used with Worker Threads", () => {
const suite = new Suite({ reporter: () => {}, useWorkers: true });

assert.throws(() => {
suite.add(
"worker with afterEach",
{
afterEach: () => {
console.log("This will fail");
},
},
() => {
const result = 42; // Some logic
return result;
}
);
}, /The "afterEach" hook is not supported when using Worker Threads/);
});
});
2 changes: 1 addition & 1 deletion test/plugin-api-doc.js
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ describe("plugin API", async () => {
"getReport(string)",
"getResult(string)",
"isSupported()",
"onCompleteBenchmark([number, number, object], {fn, fnStr, hasArg, isAsync, maxTime, minTime, name, plugins, repeatSuite})",
"onCompleteBenchmark([number, number, object], {afterEach, fn, fnStr, hasArg, isAsync, maxTime, minTime, name, plugins, repeatSuite})",
"toJSON(string)",
"toString()",
]);
Expand Down

0 comments on commit 7575b7e

Please sign in to comment.