Skip to content

Commit 1fde8fe

Browse files
committed
fix: do not use stdio nor global cache dir during console tests
1 parent 2e049fa commit 1fde8fe

File tree

3 files changed

+115
-22
lines changed

3 files changed

+115
-22
lines changed

v-next/hardhat/src/internal/builtin-plugins/console/index.ts

+5
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ const hardhatPlugin: HardhatPlugin = {
77
tasks: [
88
task("console", "Opens a hardhat console")
99
.setAction(import.meta.resolve("./task-action.js"))
10+
.addOption({
11+
name: "history",
12+
description: "Path to a history file",
13+
defaultValue: "console-history.txt",
14+
})
1015
.addVariadicArgument({
1116
name: "commands",
1217
description: "Commands to run in the console",

v-next/hardhat/src/internal/builtin-plugins/console/task-action.ts

+27-15
Original file line numberDiff line numberDiff line change
@@ -11,35 +11,47 @@ const log = debug("hardhat:core:tasks:console");
1111

1212
interface ConsoleActionArguments {
1313
commands: string[];
14+
history: string;
15+
// We accept ReplOptions as an argument to allow tests overriding the IO streams
16+
options?: repl.ReplOptions;
1417
}
1518

1619
const consoleAction: NewTaskActionFunction<ConsoleActionArguments> = async (
17-
{ commands },
20+
{ commands, history, options },
1821
_hre,
1922
) => {
20-
const globalCacheDir = await getCacheDir();
23+
// Resolve the history path if it is not empty
24+
let historyPath: string | undefined;
25+
if (history !== "") {
26+
const globalCacheDir = await getCacheDir();
27+
historyPath = path.isAbsolute(history)
28+
? history
29+
: path.resolve(globalCacheDir, history);
30+
}
2131

2232
return new Promise<REPLServer>((resolve) => {
2333
// Start a new REPL server with the default options
24-
const replServer = repl.start();
25-
26-
// Set up the REPL history file in the global cache directory
27-
const historyPath = path.join(globalCacheDir, "console-history.txt");
28-
replServer.setupHistory(historyPath, (err: Error | null) => {
29-
if (err !== null) {
30-
log(`Failed to setup REPL history: ${err.message}`);
31-
}
34+
const replServer = repl.start(options);
35+
36+
// Resolve the task action promise only when the REPL server exits
37+
replServer.on("exit", () => {
38+
resolve(replServer);
3239
});
3340

41+
// Set up the REPL history file if the historyPath has been set
42+
if (historyPath !== undefined) {
43+
replServer.setupHistory(historyPath, (err: Error | null) => {
44+
// Fail silently if the history file cannot be set up
45+
if (err !== null) {
46+
log(`Failed to setup REPL history: ${err.message}`);
47+
}
48+
});
49+
}
50+
3451
// Execute each command in the REPL server
3552
for (const command of commands) {
3653
replServer.write(`${command}\n`);
3754
}
38-
39-
// Resolve the task action promise when the REPL server exits
40-
replServer.on("exit", () => {
41-
resolve(replServer);
42-
});
4355
});
4456
};
4557

Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
import type { HardhatRuntimeEnvironment } from "@ignored/hardhat-vnext-core/types/hre";
2+
import type repl from "node:repl";
23

34
import assert from "node:assert/strict";
4-
import { before, describe, it } from "node:test";
5+
import fs from "node:fs";
6+
import os from "node:os";
7+
import path from "node:path";
8+
import { PassThrough } from "node:stream";
9+
import { afterEach, before, beforeEach, describe, it } from "node:test";
510

611
import { ensureError } from "@ignored/hardhat-vnext-utils/error";
712

@@ -11,33 +16,56 @@ import { useFixtureProject } from "../../../helpers/project.js";
1116

1217
describe("console/task-action", function () {
1318
let hre: HardhatRuntimeEnvironment;
19+
let options: repl.ReplOptions;
1420

1521
before(async function () {
1622
hre = await createHardhatRuntimeEnvironment({});
1723
});
1824

25+
beforeEach(function () {
26+
const input = new PassThrough();
27+
const output = new PassThrough();
28+
output.pipe(process.stdout);
29+
options = {
30+
input,
31+
output,
32+
};
33+
});
34+
1935
describe("javascript", function () {
2036
useFixtureProject("run-js-script");
2137

2238
it("should throw inside the console if script does not exist", async function () {
2339
const replServer = await consoleAction(
24-
{ commands: ['await import("./scripts/non-existent.js");', ".exit"] },
40+
{
41+
commands: ['await import("./scripts/non-existent.js");', ".exit"],
42+
history: "",
43+
options,
44+
},
2545
hre,
2646
);
2747
ensureError(replServer.lastError);
2848
});
2949

3050
it("should run a script inside the console successfully", async function () {
3151
const replServer = await consoleAction(
32-
{ commands: ['await import("./scripts/success.js");', ".exit"] },
52+
{
53+
commands: [".help", 'await import("./scripts/success.js");', ".exit"],
54+
history: "",
55+
options,
56+
},
3357
hre,
3458
);
3559
assert.equal(replServer.lastError, undefined);
3660
});
3761

3862
it("should throw inside the console if the script throws", async function () {
3963
const replServer = await consoleAction(
40-
{ commands: ['await import("./scripts/throws.js");', ".exit"] },
64+
{
65+
commands: ['await import("./scripts/throws.js");', ".exit"],
66+
history: "",
67+
options,
68+
},
4169
hre,
4270
);
4371
ensureError(replServer.lastError);
@@ -49,26 +77,74 @@ describe("console/task-action", function () {
4977

5078
it("should throw inside the console if script does not exist", async function () {
5179
const replServer = await consoleAction(
52-
{ commands: ['await import("./scripts/non-existent.ts");', ".exit"] },
80+
{
81+
commands: ['await import("./scripts/non-existent.ts");', ".exit"],
82+
history: "",
83+
options,
84+
},
5385
hre,
5486
);
5587
ensureError(replServer.lastError);
5688
});
5789

5890
it("should run a script inside the console successfully", async function () {
5991
const replServer = await consoleAction(
60-
{ commands: ['await import("./scripts/success.ts");', ".exit"] },
92+
{
93+
commands: ['await import("./scripts/success.ts");', ".exit"],
94+
history: "",
95+
options,
96+
},
6197
hre,
6298
);
6399
assert.equal(replServer.lastError, undefined);
64100
});
65101

66102
it("should throw inside the console if the script throws", async function () {
67103
const replServer = await consoleAction(
68-
{ commands: ['await import("./scripts/throws.ts");', ".exit"] },
104+
{
105+
commands: ['await import("./scripts/throws.ts");', ".exit"],
106+
history: "",
107+
options,
108+
},
69109
hre,
70110
);
71111
ensureError(replServer.lastError);
72112
});
73113
});
114+
115+
describe("history", function () {
116+
let cacheDir: string;
117+
let history: string;
118+
119+
beforeEach(function () {
120+
cacheDir = fs.mkdtempSync(
121+
path.resolve(os.tmpdir(), "console-action-test-"),
122+
);
123+
history = path.resolve(cacheDir, "console-history.txt");
124+
});
125+
126+
afterEach(function () {
127+
fs.rmSync(cacheDir, { recursive: true });
128+
});
129+
130+
it("should create a history file", async function () {
131+
assert.ok(
132+
!fs.existsSync(history),
133+
"History file exists before running the console",
134+
);
135+
const replServer = await consoleAction(
136+
{
137+
commands: [".help", ".exit"],
138+
history,
139+
options,
140+
},
141+
hre,
142+
);
143+
assert.equal(replServer.lastError, undefined);
144+
assert.ok(
145+
fs.existsSync(history),
146+
"History file does not exist after running the console",
147+
);
148+
});
149+
});
74150
});

0 commit comments

Comments
 (0)