Skip to content

Commit

Permalink
Merge pull request #3155 from phated/phated/cjs
Browse files Browse the repository at this point in the history
feat: Load hardhat.config.cjs to partially support ESM projects
  • Loading branch information
fvictorio committed Sep 13, 2022
2 parents c7bfbbc + 17c56bc commit c93960a
Show file tree
Hide file tree
Showing 18 changed files with 291 additions and 2 deletions.
7 changes: 7 additions & 0 deletions packages/hardhat-core/src/internal/core/project-structure.ts
Expand Up @@ -7,12 +7,14 @@ import { getPackageRoot } from "../util/packageInfo";
import { HardhatError } from "./errors";
import { ERRORS } from "./errors-list";
const JS_CONFIG_FILENAME = "hardhat.config.js";
const CJS_CONFIG_FILENAME = "hardhat.config.cjs";
const TS_CONFIG_FILENAME = "hardhat.config.ts";
const CTS_CONFIG_FILENAME = "hardhat.config.cts";

export function isCwdInsideProject() {
return (
findUp.sync(TS_CONFIG_FILENAME) !== null ||
findUp.sync(CJS_CONFIG_FILENAME) !== null ||
findUp.sync(JS_CONFIG_FILENAME) !== null
);
}
Expand All @@ -28,6 +30,11 @@ export function getUserConfigPath() {
return tsConfigPath;
}

const cjsConfigPath = findUp.sync(CJS_CONFIG_FILENAME);
if (cjsConfigPath !== null) {
return cjsConfigPath;
}

const pathToConfigFile = findUp.sync(JS_CONFIG_FILENAME);
if (pathToConfigFile === null) {
throw new HardhatError(ERRORS.GENERAL.NOT_INSIDE_PROJECT);
Expand Down
88 changes: 87 additions & 1 deletion packages/hardhat-core/test/builtin-tasks/run.ts
Expand Up @@ -8,7 +8,7 @@ import { useEnvironment } from "../helpers/environment";
import { expectHardhatErrorAsync } from "../helpers/errors";
import { useFixtureProject } from "../helpers/project";

describe("run task", function () {
describe("run task (CJS)", function () {
useFixtureProject("project-with-scripts");
useEnvironment();

Expand Down Expand Up @@ -93,3 +93,89 @@ describe("run task", function () {
(process as any).exitCode = undefined;
});
});

describe("run task (ESM)", function () {
useFixtureProject("esm-project-with-scripts");
useEnvironment();

it("Should fail if a script doesn't exist", async function () {
await expectHardhatErrorAsync(
() =>
this.env.run("run", { script: "./does-not-exist", noCompile: true }),
ERRORS.BUILTIN_TASKS.RUN_FILE_NOT_FOUND
);
});

it("Should run the scripts to completion", async function () {
await this.env.run("run", {
script: "./async-script.js",
noCompile: true,
});

assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;
});

it("Should compile before running", async function () {
if (await fsExtra.pathExists("cache")) {
await fsExtra.remove("cache");
}

if (await fsExtra.pathExists("artifacts")) {
await fsExtra.remove("artifacts");
}

await this.env.run("run", {
script: "./successful-script.js",
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;

const artifacts = new Artifacts(path.join(process.cwd(), "artifacts"));
const files = await artifacts.getArtifactPaths();
const expectedFile = path.join(
process.cwd(),
"artifacts/contracts/a.sol/A.json"
);
assert.sameMembers(files, [expectedFile]);

await fsExtra.remove("artifacts");
});

it("Shouldn't compile if asked not to", async function () {
if (await fsExtra.pathExists("cache")) {
await fsExtra.remove("cache");
}

if (await fsExtra.pathExists("artifacts")) {
await fsExtra.remove("artifacts");
}

await this.env.run("run", {
script: "./successful-script.js",
noCompile: true,
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;

assert.isFalse(await fsExtra.pathExists("artifacts"));
});

it("Should return the script's status code on success", async function () {
await this.env.run("run", {
script: "./successful-script.js",
noCompile: true,
});
assert.equal(process.exitCode, 0);
(process as any).exitCode = undefined;
});

it("Should return the script's status code on failure", async function () {
await this.env.run("run", {
script: "./failing-script.js",
noCompile: true,
});
assert.notEqual(process.exitCode, 0);
(process as any).exitCode = undefined;
});
});
@@ -0,0 +1,2 @@
/cache
/artifacts
@@ -0,0 +1,5 @@
import * as process from "process";

if (hardhatArguments.network !== "custom") {
process.exit(1);
}
@@ -0,0 +1,7 @@
import * as process from "process";

setTimeout(() => {
if (global.config === undefined || global.config.solidity === undefined) {
process.exit(123);
}
}, 100);
@@ -0,0 +1,2 @@
contract A {}

@@ -0,0 +1,5 @@
import * as process from "process";

if (process.env.TEST_ENV_VAR !== "test") {
process.exit(123);
}
@@ -0,0 +1,3 @@
import * as process from "process";

process.exit(123);
@@ -0,0 +1,8 @@
module.exports = {
solidity: "0.5.15",
networks: {
custom: {
url: "asd",
},
},
};
@@ -0,0 +1,3 @@
{
"type": "module"
}
@@ -0,0 +1,10 @@
import * as process from "process";

if (
process.argv.length !== 5 ||
process.argv[2] !== "a" ||
process.argv[3] !== "b" ||
process.argv[4] !== "c"
) {
process.exit(12);
}
@@ -0,0 +1,5 @@
import * as process from "process";

if (global.config === undefined || global.config.solidity === undefined) {
process.exit(123123);
}
Empty file.
@@ -0,0 +1,21 @@
task("example2", "example task", async (ret) => 28);

task("example", "example task", async (__, { run }) => run("example2"));

module.exports = {
defaultNetwork: "custom",
networks: {
custom: {
url: "http://127.0.0.1:8545",
},
localhost: {
accounts: [
"0xa95f9e3e7ae4e4865c5968828fe7c03fffa8a9f3bb52d36d26243f4c868ee166",
],
},
},
solidity: "0.5.15",
unknown: {
asd: 123,
},
};
@@ -0,0 +1,3 @@
{
"type": "module"
}
12 changes: 12 additions & 0 deletions packages/hardhat-core/test/internal/core/config/config-loading.ts
Expand Up @@ -36,6 +36,18 @@ describe("config loading", function () {
});
});

describe("can load CJS config path inside an esm project", function () {
useFixtureProject("esm-project");
useEnvironment();

it("should load the default config if none is given", function () {
assert.isDefined(this.env.config.networks.localhost);
assert.deepEqual(this.env.config.networks.localhost.accounts, [
"0xa95f9e3e7ae4e4865c5968828fe7c03fffa8a9f3bb52d36d26243f4c868ee166",
]);
});
});

describe("Config validation", function () {
describe("When the config is invalid", function () {
useFixtureProject("invalid-config");
Expand Down
25 changes: 25 additions & 0 deletions packages/hardhat-core/test/internal/core/project-structure.ts
Expand Up @@ -71,6 +71,31 @@ describe("project structure", () => {
});
});
});

describe("Inside an ESM project", () => {
useFixtureProject("esm-project");
let configPath: string;

before("get root path", async () => {
// TODO: This is no longer needed once PR #71 gets merged
const pathToFixtureRoot = await getRealPath(
path.join(__dirname, "..", "..", "fixture-projects", "esm-project")
);

configPath = await getRealPath(
path.join(pathToFixtureRoot, "hardhat.config.cjs")
);
});

it("should work from the project root", () => {
assert.equal(getUserConfigPath(), configPath);
});

it("should work from deeper inside the project", () => {
process.chdir("contracts");
assert.equal(getUserConfigPath(), configPath);
});
});
});

describe("getRecommendedGitIgnore", () => {
Expand Down
87 changes: 86 additions & 1 deletion packages/hardhat-core/test/internal/util/scripts-runner.ts
Expand Up @@ -7,7 +7,7 @@ import {
import { useEnvironment } from "../../helpers/environment";
import { useFixtureProject } from "../../helpers/project";

describe("Scripts runner", function () {
describe("Scripts runner (CJS)", function () {
useFixtureProject("project-with-scripts");

it("Should pass params to the script", async function () {
Expand Down Expand Up @@ -91,3 +91,88 @@ describe("Scripts runner", function () {
});
});
});

describe("Scripts runner (ESM)", function () {
useFixtureProject("esm-project-with-scripts");

it("Should pass params to the script", async function () {
const [statusCodeWithScriptParams, statusCodeWithNoParams] =
await Promise.all([
runScript("./params-script.js", ["a", "b", "c"]),
runScript("./params-script.js"),
]);

assert.equal(statusCodeWithScriptParams, 0);

// We check here that the script is correctly testing this:
assert.notEqual(statusCodeWithNoParams, 0);
});

it("Should run the script to completion", async function () {
const before = new Date();
const status = await runScript("./async-script.js");
assert.equal(status, 123);
const after = new Date();

assert.isAtLeast(after.getTime() - before.getTime(), 100);
});

it("Should resolve to the status code of the script run", async function () {
assert.deepEqual(await runScript("./failing-script.js"), 123);
});

it("Should pass env variables to the script", async function () {
const [statusCodeWithEnvVars, statusCodeWithNoEnvArgs] = await Promise.all([
runScript("./env-var-script.js", [], [], {
TEST_ENV_VAR: "test",
}),
runScript("./env-var-script.js"),
]);

assert.equal(
statusCodeWithEnvVars,
0,
"Status code with env vars should be 0"
);

assert.notEqual(
statusCodeWithNoEnvArgs,
0,
"Status code with no env vars should not be 0"
);
});

describe("runWithHardhat", function () {
useEnvironment();

it("Should load hardhat/register successfully", async function () {
const [statusCodeWithHardhat, statusCodeWithoutHardhat] =
await Promise.all([
runScriptWithHardhat(
this.env.hardhatArguments,
"./successful-script.js"
),
runScript("./successful-script.js"),
]);

assert.equal(statusCodeWithHardhat, 0);

// We check here that the script is correctly testing this:
assert.notEqual(statusCodeWithoutHardhat, 0);
});

it("Should forward all the hardhat arguments", async function () {
// This is only for testing purposes, as we can't set a hardhat argument
// as the CLA does, and env variables always get forwarded to child
// processes
this.env.hardhatArguments.network = "custom";

const statusCode = await runScriptWithHardhat(
this.env.hardhatArguments,
"./assert-hardhat-arguments.js"
);

assert.equal(statusCode, 0);
});
});
});

0 comments on commit c93960a

Please sign in to comment.