Skip to content

Commit

Permalink
test: add example test of mocking hre artifacts
Browse files Browse the repository at this point in the history
We add a `createMockHardhatRuntimeEnvironment` that overrides the
standard artifacts built-in plugin and substitutes in a mock version
that can be leveraged in tests and development.

There is a supporting test to show the usage of the mocked artifacts
manager.
  • Loading branch information
kanej committed Sep 12, 2024
1 parent c75c997 commit ee0ebf2
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { Artifact } from "../../src/types/artifacts.js";
import type { HardhatRuntimeEnvironment } from "../../src/types/hre.js";
import type { HardhatPlugin } from "../../src/types/plugins.js";

import assert from "node:assert/strict";
import { describe, it } from "node:test";

import { task } from "../../src/config.js";
import { createMockHardhatRuntimeEnvironment } from "../test-helpers/create-mock-hardhat-runtime-environment.js";

// TODO: This test is an example and should be removed with the completion of
// the build system and the artifacts plugin.
describe("createMockHardhatRuntimeEnvironment", () => {
it("should allow plugins that leverage the artifact hre object", async () => {
// arrange
const exampleArtifact: Artifact = {
_format: "hh-sol-artifact-1",
contractName: "MyContract",
sourceName: "source.sol",
abi: [],
bytecode: "0x",
linkReferences: {},
deployedBytecode: "0x",
deployedLinkReferences: {},
};

const myPlugin: HardhatPlugin = {
id: "my-plugin",
tasks: [
task("hello-artifact-using-world", "Tests artifact loading")
.setAction(async ({}, hre: HardhatRuntimeEnvironment) => {
return hre.artifacts.readArtifact("MyContract");
})
.build(),
],
};

const mockHre = await createMockHardhatRuntimeEnvironment({
plugins: [myPlugin],
});

await mockHre.artifacts.saveArtifact(exampleArtifact);

// act
const helloArtifactUsingWorld = mockHre.tasks.getTask(
"hello-artifact-using-world",
);

const result = await helloArtifactUsingWorld.run({});

// Assert
assert.equal(result, exampleArtifact);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import type { HardhatUserConfig } from "../../src/config.js";
import type { UnsafeHardhatRuntimeEnvironmentOptions } from "../../src/internal/core/types.js";
import type { GlobalOptions } from "../../src/types/global-options.js";
import type { HardhatRuntimeEnvironment } from "../../src/types/hre.js";
import type { HardhatPlugin } from "../../src/types/plugins.js";

import "../../src/internal/builtin-plugins/artifacts/type-extensions.js";

import { createHardhatRuntimeEnvironment } from "../../src/hre.js";
import artifacts from "../../src/internal/builtin-plugins/artifacts/index.js";
import { resolveProjectRoot } from "../../src/internal/core/hre.js";

import { MockArtifactsManager } from "./mock-artifacts-manager.js";

export async function createMockHardhatRuntimeEnvironment(
config: HardhatUserConfig,
userProvidedGlobalOptions: Partial<GlobalOptions> = {},
projectRoot?: string,
unsafeOptions: UnsafeHardhatRuntimeEnvironmentOptions = {},
): Promise<HardhatRuntimeEnvironment> {
const resolvedProjectRoot = await resolveProjectRoot(projectRoot);

return createHardhatRuntimeEnvironment(
{ ...config, plugins: [mockArtifactsPlugin, ...(config.plugins ?? [])] },
userProvidedGlobalOptions,
resolvedProjectRoot,
unsafeOptions,
);
}

const mockArtifactsPlugin: HardhatPlugin = {
id: "mock-artifacts",
dependencies: [async () => artifacts],
hookHandlers: {
hre: async () => {
return {
created: async (
context,
hre,
next,
): Promise<HardhatRuntimeEnvironment> => {
const updatedHre = await next(context, hre);

updatedHre.artifacts = new MockArtifactsManager();

return updatedHre;
},
};
},
},
};
104 changes: 104 additions & 0 deletions v-next/hardhat/test/test-helpers/mock-artifacts-manager.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import type {
ArtifactsManager,
Artifact,
BuildInfo,
CompilerInput,
CompilerOutput,
} from "../../src/types/artifacts.js";

import { HardhatError } from "@ignored/hardhat-vnext-errors";

export class MockArtifactsManager implements ArtifactsManager {
readonly #artifacts: Map<string, Artifact>;

constructor() {
this.#artifacts = new Map();
}

public async readArtifact(
contractNameOrFullyQualifiedName: string,
): Promise<Artifact> {
const artifact = this.#artifacts.get(contractNameOrFullyQualifiedName);

if (artifact === undefined) {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message:
"Unable to find the artifact during mock readArtifact " +
contractNameOrFullyQualifiedName,
});
}

return artifact;
}

public artifactExists(
_contractNameOrFullyQualifiedName: string,
): Promise<boolean> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getAllFullyQualifiedNames(): Promise<string[]> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getBuildInfo(
_fullyQualifiedName: string,
): Promise<BuildInfo | undefined> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getArtifactPaths(): Promise<string[]> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getDebugFilePaths(): Promise<string[]> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getBuildInfoPaths(): Promise<string[]> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public async saveArtifact(artifact: Artifact): Promise<void> {
this.#artifacts.set(artifact.contractName, artifact);
}

public saveBuildInfo(
_solcVersion: string,
_solcLongVersion: string,
_input: CompilerInput,
_output: CompilerOutput,
): Promise<string> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public formArtifactPathFromFullyQualifiedName(
_fullyQualifiedName: string,
): string {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}

public getArtifactPath(
_contractNameOrFullyQualifiedName: string,
): Promise<string> {
throw new HardhatError(HardhatError.ERRORS.INTERNAL.ASSERTION_ERROR, {
message: "Not implemented in MockArtifactsManager",
});
}
}

0 comments on commit ee0ebf2

Please sign in to comment.