Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions .changeset/yellow-lands-kiss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@nomicfoundation/hardhat-node-test-runner": patch
"@nomicfoundation/hardhat-mocha": patch
"hardhat": patch
---

Add `onTestRunStart`, `onTestWorkerDone`, and `onTestRunDone` test hooks.
10 changes: 10 additions & 0 deletions .peer-bumps.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,16 @@
"v-next/config"
],
"bumps": [
{
"package": "@nomicfoundation/hardhat-mocha",
"peer": "hardhat",
"reason": "It depends on the new TestHooks#onTestRunStart, TestHooks#onTestWorkerDone, and TestHooks#onTestRunDone hooks"
},
{
"package": "@nomicfoundation/hardhat-node-test-runner",
"peer": "hardhat",
"reason": "It depends on the new TestHooks#onTestRunStart, TestHooks#onTestWorkerDone, and TestHooks#onTestRunDone hooks"
},
{
"package": "@nomicfoundation/hardhat-foundry",
"peer": "hardhat",
Expand Down
3 changes: 1 addition & 2 deletions v-next/hardhat-mocha/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"type": "module",
"exports": {
".": "./dist/src/index.js",
"./coverage": "./dist/src/coverage.js",
"./gas-stats": "./dist/src/gas-stats.js"
"./test-worker-done": "./dist/src/test-worker-done.js"
},
"keywords": [
"ethereum",
Expand Down
7 changes: 0 additions & 7 deletions v-next/hardhat-mocha/src/coverage.ts

This file was deleted.

7 changes: 0 additions & 7 deletions v-next/hardhat-mocha/src/gas-stats.ts

This file was deleted.

43 changes: 12 additions & 31 deletions v-next/hardhat-mocha/src/task-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,6 @@ import { HardhatError } from "@nomicfoundation/hardhat-errors";
import { setGlobalOptionsAsEnvVariables } from "@nomicfoundation/hardhat-utils/env";
import { getAllFilesMatching } from "@nomicfoundation/hardhat-utils/fs";
import debug from "debug";
import {
markTestRunStart as initCoverage,
markTestWorkerDone as saveCoverageData,
markTestRunDone as reportCoverage,
} from "hardhat/internal/coverage";
import {
markTestRunStart as initGasStats,
markTestWorkerDone as saveGasStats,
markTestRunDone as reportGasStats,
} from "hardhat/internal/gas-analytics";

import { createPerformanceTracker } from "./performance.js";

Expand Down Expand Up @@ -121,21 +111,15 @@ const testWithHardhat: NewTaskActionFunction<TestActionArguments> = async (
hre.config.test.mocha.require = hre.config.test.mocha.require ?? [];
hre.config.test.mocha.require.push(unhandledRejectionHook.href);

if (hre.globalOptions.coverage === true) {
const coverage = new URL(
import.meta.resolve("@nomicfoundation/hardhat-mocha/coverage"),
if (
hre.globalOptions.coverage === true ||
hre.globalOptions.gasStats === true
) {
const testWorkerDone = new URL(
import.meta.resolve("@nomicfoundation/hardhat-mocha/test-worker-done"),
);

hre.config.test.mocha.require.push(coverage.href);
}

if (hre.globalOptions.gasStats === true) {
const gasStats = new URL(
import.meta.resolve("@nomicfoundation/hardhat-mocha/gas-stats"),
);

hre.config.test.mocha.require = hre.config.test.mocha.require ?? [];
hre.config.test.mocha.require.push(gasStats.href);
hre.config.test.mocha.require.push(testWorkerDone.href);
}

process.env.NODE_OPTIONS = imports
Expand Down Expand Up @@ -186,8 +170,7 @@ const testWithHardhat: NewTaskActionFunction<TestActionArguments> = async (
perf.endPhase("Test file loading");
perf.startPhase("Test execution");

await initCoverage("mocha");
await initGasStats("mocha");
await hre.hooks.runSequentialHandlers("test", "onTestRunStart", ["mocha"]);

let total = 0;
const testFailures = await new Promise<number>((resolve) => {
Expand All @@ -199,13 +182,11 @@ const testWithHardhat: NewTaskActionFunction<TestActionArguments> = async (
perf.startPhase("Reporting");

if (hre.config.test.mocha.parallel !== true) {
// NOTE: We execute mocha tests in the main process.
await saveCoverageData("mocha");
await saveGasStats("mocha");
await hre.hooks.runSequentialHandlers("test", "onTestWorkerDone", [
"mocha",
]);
}
// NOTE: This might print a coverage report.
await reportCoverage("mocha");
await reportGasStats("mocha");
await hre.hooks.runSequentialHandlers("test", "onTestRunDone", ["mocha"]);

perf.endPhase("Reporting");

Expand Down
9 changes: 9 additions & 0 deletions v-next/hardhat-mocha/src/test-worker-done.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import hre from "hardhat";

export const mochaHooks = {
async afterAll(): Promise<void> {
await hre.hooks.runSequentialHandlers("test", "onTestWorkerDone", [
"mocha",
]);
},
};
3 changes: 1 addition & 2 deletions v-next/hardhat-node-test-runner/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,7 @@
"type": "module",
"exports": {
".": "./dist/src/index.js",
"./coverage": "./dist/src/coverage.js",
"./gas-stats": "./dist/src/gas-stats.js"
"./test-worker-done": "./dist/src/test-worker-done.js"
},
"keywords": [
"ethereum",
Expand Down
7 changes: 0 additions & 7 deletions v-next/hardhat-node-test-runner/src/coverage.ts

This file was deleted.

7 changes: 0 additions & 7 deletions v-next/hardhat-node-test-runner/src/gas-stats.ts

This file was deleted.

33 changes: 9 additions & 24 deletions v-next/hardhat-node-test-runner/src/task-action.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,6 @@ import { hardhatTestReporter } from "@nomicfoundation/hardhat-node-test-reporter
import { setGlobalOptionsAsEnvVariables } from "@nomicfoundation/hardhat-utils/env";
import { getAllFilesMatching } from "@nomicfoundation/hardhat-utils/fs";
import { createNonClosingWriter } from "@nomicfoundation/hardhat-utils/stream";
import {
markTestRunStart as initCoverage,
markTestRunDone as reportCoverage,
} from "hardhat/internal/coverage";
import {
markTestRunStart as initGasStats,
markTestRunDone as reportGasStats,
} from "hardhat/internal/gas-analytics";

interface TestActionArguments {
testFiles: string[];
Expand Down Expand Up @@ -92,20 +84,16 @@ const testWithHardhat: NewTaskActionFunction<TestActionArguments> = async (
const tsx = new URL(import.meta.resolve("tsx/esm"));
imports.push(tsx.href);

if (hre.globalOptions.coverage === true) {
const coverage = new URL(
import.meta.resolve("@nomicfoundation/hardhat-node-test-runner/coverage"),
);
imports.push(coverage.href);
}

if (hre.globalOptions.gasStats === true) {
const gasStats = new URL(
if (
hre.globalOptions.coverage === true ||
hre.globalOptions.gasStats === true
) {
const testWorkerDone = new URL(
import.meta.resolve(
"@nomicfoundation/hardhat-node-test-runner/gas-stats",
"@nomicfoundation/hardhat-node-test-runner/test-worker-done",
),
);
imports.push(gasStats.href);
imports.push(testWorkerDone.href);
}

process.env.NODE_OPTIONS = imports
Expand Down Expand Up @@ -191,14 +179,11 @@ const testWithHardhat: NewTaskActionFunction<TestActionArguments> = async (
};
}

await initCoverage("nodejs");
await initGasStats("nodejs");
await hre.hooks.runSequentialHandlers("test", "onTestRunStart", ["nodejs"]);

const testResults = await runTests();

// NOTE: This might print a coverage report.
await reportCoverage("nodejs");
await reportGasStats("nodejs");
await hre.hooks.runSequentialHandlers("test", "onTestRunDone", ["nodejs"]);

if (testResults.failed > 0) {
process.exitCode = 1;
Expand Down
7 changes: 7 additions & 0 deletions v-next/hardhat-node-test-runner/src/test-worker-done.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { after } from "node:test";

import hre from "hardhat";

after(async () => {
await hre.hooks.runSequentialHandlers("test", "onTestWorkerDone", ["nodejs"]);
});
2 changes: 0 additions & 2 deletions v-next/hardhat/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@
"./types/utils": "./dist/src/types/utils.js",
"./types/solidity": "./dist/src/types/solidity.js",
"./console.sol": "./console.sol",
"./internal/coverage": "./dist/src/internal/builtin-plugins/coverage/exports.js",
"./internal/gas-analytics": "./dist/src/internal/builtin-plugins/gas-analytics/exports.js",
"./utils/contract-names": "./dist/src/utils/contract-names.js",
"./types/runtime": "./dist/src/internal/deprecated-module-imported-from-hardhat2-plugin.js",
"./builtin-tasks/task-names": "./dist/src/internal/deprecated-module-imported-from-hardhat2-plugin.js",
Expand Down

This file was deleted.

45 changes: 0 additions & 45 deletions v-next/hardhat/src/internal/builtin-plugins/coverage/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,50 +1,5 @@
import path from "node:path";

import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";

import { HardhatRuntimeEnvironmentImplementation } from "../../core/hre.js";

export function getCoveragePath(rootPath: string): string {
return path.join(rootPath, "coverage");
}

/**
* NOTE: The following helpers interact with the global HRE instance only;
* This is OK because:
* - They are intended for the internal use only. They are exposed via the
* internal public API only.
* - We know the HRE has been initialized by the time they are used.
*/

export async function markTestRunStart(id: string): Promise<void> {
const { default: hre } = await import("../../../index.js");
if (hre.globalOptions.coverage === true) {
assertHardhatInvariant(
hre instanceof HardhatRuntimeEnvironmentImplementation,
"Expected HRE to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await hre._coverage.clearData(id);
}
}

export async function markTestWorkerDone(id: string): Promise<void> {
const { default: hre } = await import("../../../index.js");
if (hre.globalOptions.coverage === true) {
assertHardhatInvariant(
hre instanceof HardhatRuntimeEnvironmentImplementation,
"Expected HRE to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await hre._coverage.saveData(id);
}
}

export async function markTestRunDone(id: string): Promise<void> {
const { default: hre } = await import("../../../index.js");
if (hre.globalOptions.coverage === true) {
assertHardhatInvariant(
hre instanceof HardhatRuntimeEnvironmentImplementation,
"Expected HRE to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await hre._coverage.report(id);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import type { TestHooks } from "../../../../types/hooks.js";

import { assertHardhatInvariant } from "@nomicfoundation/hardhat-errors";

import { HardhatRuntimeEnvironmentImplementation } from "../../../core/hre.js";

export default async (): Promise<Partial<TestHooks>> => ({
onTestRunStart: async (context, id) => {
if (context.globalOptions.coverage === true) {
assertHardhatInvariant(
context instanceof HardhatRuntimeEnvironmentImplementation,
"Expected context to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await context._coverage.clearData(id);
}
},

onTestWorkerDone: async (context, id) => {
if (context.globalOptions.coverage === true) {
assertHardhatInvariant(
context instanceof HardhatRuntimeEnvironmentImplementation,
"Expected context to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await context._coverage.saveData(id);
}
},

onTestRunDone: async (context, id) => {
if (context.globalOptions.coverage === true) {
assertHardhatInvariant(
context instanceof HardhatRuntimeEnvironmentImplementation,
"Expected context to be an instance of HardhatRuntimeEnvironmentImplementation",
);
await context._coverage.report(id);
}
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const hardhatPlugin: HardhatPlugin = {
clean: () => import("./hook-handlers/clean.js"),
hre: () => import("./hook-handlers/hre.js"),
solidity: () => import("./hook-handlers/solidity.js"),
test: () => import("./hook-handlers/test.js"),
},
npmPackage: "hardhat",
};
Expand Down

This file was deleted.

This file was deleted.

Loading