Example: Tests
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { network } from "hardhat";
import { parseEther } from "viem";
const { viem } = await network.connect();
const publicClient = await viem.getPublicClient();
describe("Crowdfunding", function () {
it("Accounts can donate and vote", async function () {
const [owner, beneficiary1, beneficiary2, donor1, donor2] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await crowdfunding.write.addProject(["Project 1", beneficiary1.account.address]);
await crowdfunding.write.addProject(["Project 2", beneficiary2.account.address]);
await crowdfunding.write.donate({ value: parseEther("1"), account: donor1.account.address });
await crowdfunding.write.donate({ value: parseEther("3"), account: donor2.account.address });
await crowdfunding.write.vote([1n], { account: donor1.account.address });
await crowdfunding.write.vote([1n], { account: donor2.account.address });
await crowdfunding.write.closeVoting({ account: owner.account.address });
const winningProject = await crowdfunding.read.getWinningProject();
assert.deepStrictEqual(winningProject, [1n, "Project 2"]);
await crowdfunding.write.withdraw({ account: beneficiary2.account.address });
});
it("Only the owner can add projects", async function () {
const [owner, otherUser] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await crowdfunding.write.addProject(
["Project 1", otherUser.account.address],
{ account: owner.account.address }
);
await assert.rejects(
crowdfunding.write.addProject(["Project 2", otherUser.account.address], { account: otherUser.account.address })
);
});
it("Only donors can vote", async function () {
const [owner, beneficiary, donor] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await crowdfunding.write.addProject(["Project 1", beneficiary.account.address]);
await crowdfunding.write.donate({ value: parseEther("1"), account: donor.account.address });
await crowdfunding.write.vote([0n], { account: donor.account.address });
await assert.rejects(
crowdfunding.write.vote([0n], { account: beneficiary.account.address })
);
await crowdfunding.write.closeVoting({ account: owner.account.address });
});
it("Donors can only vote once", async function () {
const [owner, beneficiary, donor] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await crowdfunding.write.addProject(["Project 1", beneficiary.account.address]);
await crowdfunding.write.addProject(["Project 2", beneficiary.account.address]);
await crowdfunding.write.donate({ value: parseEther("1"), account: donor.account.address });
await crowdfunding.write.vote([0n], { account: donor.account.address });
// can't vote for the same project again
await assert.rejects(
crowdfunding.write.vote([0n], { account: donor.account.address })
);
// can't vote for a different project
await assert.rejects(
crowdfunding.write.vote([1n], { account: donor.account.address })
);
await crowdfunding.write.closeVoting({ account: owner.account.address });
});
it("Only the owner can close the vote", async function () {
const [owner, beneficiary] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await crowdfunding.write.addProject(["Project 1", beneficiary.account.address]);
await assert.rejects(
crowdfunding.write.closeVoting({ account: beneficiary.account.address })
);
await crowdfunding.write.closeVoting({ account: owner.account.address });
});
it("Event should fire when a new project is added", async function () {
const [owner, user1] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
await viem.assertions.emitWithArgs(
crowdfunding.write.addProject(["Project 1", user1.account.address]),
crowdfunding,
"NewProjectAdded",
[0n, "Project 1"]
);
});
it("Event should fire when a new project is added (second approach)", async function () {
const [owner, user1] = await viem.getWalletClients();
const crowdfunding = await viem.deployContract("Crowdfunding");
const blockNumber = await publicClient.getBlockNumber();
await crowdfunding.write.addProject(["Project 1", user1.account.address]);
const events = await publicClient.getContractEvents({
address: crowdfunding.address,
abi: crowdfunding.abi,
eventName: "NewProjectAdded",
fromBlock: blockNumber
});
assert.equal(events.length, 1);
assert.equal(events[0].args.name, "Project 1");
});
});