Unit Test Partial

This commit is contained in:
2024-08-12 06:30:27 +08:00
parent 5df036c2c1
commit fdec58e8b8
6 changed files with 221 additions and 71 deletions
+11 -1
View File
@@ -72,7 +72,9 @@ contract Raffle is VRFConsumerBaseV2Plus, AutomationCompatibleInterface {
function enterRaffle() public payable {
// require(msg.value > i_entranceFee, "ETH too less!");
if (msg.value < i_entranceFee) {
uint256 msgValue = msg.value;
if (msgValue < i_entranceFee) {
revert Raffle__NotEnoughETHEntered();
}
if (s_raffleState != RaffleState.OPEN) {
@@ -240,4 +242,12 @@ contract Raffle is VRFConsumerBaseV2Plus, AutomationCompatibleInterface {
function getRecentWinner() public view returns (address) {
return s_recentWinner;
}
function getRaffleState() public view returns (RaffleState) {
return s_raffleState;
}
function getInterval() public view returns (uint256) {
return i_interval;
}
}
+8 -9
View File
@@ -1,4 +1,4 @@
const { network, ethers } = require("hardhat");
const { network, ethers, deployments } = require("hardhat");
const {
networkConfig,
developmentChains,
@@ -8,13 +8,13 @@ const { verify } = require("../utils/verify");
module.exports = async ({ getNamedAccounts, deployments }) => {
const { deploy, log, get } = deployments;
const { deployer } = await getNamedAccounts();
const { deployer, player } = await getNamedAccounts();
const chainId = network.config.chainId;
let vrfCoordinatorV2_5Address, subscriptionId, vrfCoordinatorV2_5Mock;
const FUND_AMOUNT = ethers.utils.parseEther("1"); // 1 Ether, or 1e18 (10^18) Wei
if (chainId == 31337) {
const FUND_AMOUNT = ethers.utils.parseEther("1"); // 1 Ether, or 1e18 (10^18) Wei
// 31337 is the chainId for localhost
if (developmentChains.includes(network.name)) {
// Mock Auto Create VRF V2.5 Subscription
/* // Deprecated
@@ -37,9 +37,8 @@ module.exports = async ({ getNamedAccounts, deployments }) => {
const createSubReceipt = await createSubTx.wait(1);
subscriptionId = createSubReceipt.events[0].args.subId; // Keep as BigNumber
const formattedSubscriptionId = ethers.BigNumber.from(subscriptionId);
// Fund the subscription
await vrfCoordinatorV2_5MockInstance.fundSubscription(formattedSubscriptionId, FUND_AMOUNT);
await vrfCoordinatorV2_5MockInstance.fundSubscription(subscriptionId, FUND_AMOUNT);
} else {
vrfCoordinatorV2_5Address = networkConfig[chainId]["vrfCoordinatorV2"];
subscriptionId = networkConfig[chainId]["subscriptionId"];
@@ -74,7 +73,7 @@ module.exports = async ({ getNamedAccounts, deployments }) => {
//await vrfCoordinatorV2_5Mock.addConsumer(subscriptionId, raffle.address);
*/
vrfCoordinatorV2_5Mock = await get("VRFCoordinatorV2_5Mock");
vrfCoordinatorV2_5Mock = await deployments.get("VRFCoordinatorV2_5Mock");
vrfCoordinatorV2_5Address = vrfCoordinatorV2_5Mock.address;
// Get the contract instance at the retrieved address
@@ -83,7 +82,7 @@ module.exports = async ({ getNamedAccounts, deployments }) => {
vrfCoordinatorV2_5Address,
);
vrfCoordinatorV2_5MockInstance.addConsumer(subscriptionId, raffle.address);
await vrfCoordinatorV2_5MockInstance.addConsumer(subscriptionId, raffle.address);
}
// Verify the deployment
+1 -1
View File
@@ -92,7 +92,7 @@ module.exports = {
namedAccounts: {
deployer: {
default: 0, // here this will by default take the first account as deployer
1: 0, // similarly on mainnet it will take the first account as deployer. Note though that depending on how hardhat network are configured, the account 0 on one network can be different than on another
//1: 0, // similarly on mainnet it will take the first account as deployer. Note though that depending on how hardhat network are configured, the account 0 on one network can be different than on another
},
player: {
default: 1,
+14 -5
View File
@@ -1,12 +1,12 @@
{
"license": "Unlicense",
"_comment1": "@nomiclabs/hardhat-ethers ^2.2.3",
"_comment2": "@nomicfoundation/hardhat-ethers ^3.0.2",
"devDependencies": {
"@nomicfoundation/hardhat-ethers": "^3.0.2",
"@nomiclabs/hardhat-ethers": "^2.2.3",
"@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers@^0.3.0-beta.13",
"@nomiclabs/hardhat-etherscan": "^3.1.8",
"@nomiclabs/hardhat-waffle": "^2.0.6",
"chai": "^5.1.1",
"dotenv": "^16.4.5",
"chai": "^4.3.4",
"ethereum-waffle": "^4.0.10",
"ethers": "^5.7.2",
"hardhat": "^2.22.8",
@@ -23,7 +23,16 @@
"@chainlink/test-helpers": "^0.0.7-alpha",
"@chainlink/token": "^1.1.0",
"@openzeppelin/contracts": "^5.0.2",
"babel-eslint": "^10.1.0"
"babel-eslint": "^10.1.0",
"dotenv": "^16.4.5"
},
"scripts": {
"test": "yarn hardhat test",
"test-staging": "yarn hardhat test --network sepolia",
"lint": "yarn solhint 'contracts/*.sol'",
"lint:fix": "yarn solhint 'contracts/**/*.sol' --fix",
"format": "yarn prettier --write .",
"coverage": "yarn hardhat coverage"
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
+183
View File
@@ -0,0 +1,183 @@
const { ethers, deployments, getNamedAccounts, network } = require("hardhat");
const { expect, assert } = require("chai");
const {
networkConfig,
developmentChains,
VERIFICATION_BLOCK_CONFIRMATIONS,
} = require("../../helper-hardhat-config");
const isDevelopment = developmentChains.includes(network.name);
// Run on development chain
!developmentChains.includes(network.name)
? describe.skip
: describe("Raffle Unit Test", function () {
let addressMock, addressRaffle, addressDeployer, addressPlayer;
let raffle, vrfCoordinatorV2_5Mock, vrfCoordinatorV2_5Address, player;
let chainId, raffleEntranceFee, interval;
beforeEach(async () => {
const namedAccounts = await getNamedAccounts();
addressDeployer = namedAccounts.deployer;
addressPlayer = namedAccounts.player;
await deployments.fixture(["all"]);
// Implementation for dependencies without "@nomiclabs/hardhat-ethers": "npm:hardhat-deploy-ethers@^0.3.0-beta.13",
addressMock = (await deployments.get("VRFCoordinatorV2_5Mock")).address;
addressRaffle = (await deployments.get("Raffle")).address;
vrfCoordinatorV2_5Mock = await ethers.getContractAt(
"VRFCoordinatorV2_5Mock",
addressMock,
);
raffle = await ethers.getContractAt("Raffle", addressRaffle);
// raffle = await deployments.get("Raffle"); // Wrong, not the contract instance
// raffle = await ethers.getContract("Raffle"); // With hardaht-ethers dependency override
chainId = network.config.chainId;
raffleEntranceFee = await raffle.getEntranceFee();
interval = await raffle.getInterval();
});
describe("constructor", function () {
it("initial correct raffle state", async () => {
const raffleState = await raffle.getRaffleState();
assert.equal(raffleState, 0, "Incorrect raffle state");
});
it("initial correct interval", async () => {
const interval = (await raffle.getInterval()).toString();
const networkConfigInterval = networkConfig[chainId]["keepersUpdateInterval"];
assert.equal(interval, networkConfigInterval, "Incorrect interval");
});
}); //endof constructor
describe("enterRaffle", function () {
it("should revert if not enough payment", async () => {
/*
const entranceFee = networkConfig[chainId]["raffleEntranceFee"];
const entranceFeeString = ethers.utils.formatEther(entranceFee);
const entranceFeeWei = ethers.utils.parseEther(entranceFeeString);
const insufficientPayment = entranceFeeWei.sub(ethers.utils.parseEther("0.01")); // Set payment less than entrance fee
*/
const entranceFee = await raffle.getEntranceFee();
const entranceFeeString = ethers.utils.formatEther(entranceFee);
console.log(entranceFeeString); // 0.01
await expect(raffle.enterRaffle()).to.be.revertedWith(
"Raffle__NotEnoughETHEntered",
);
});
it("records player when they enter", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
const contractPlayer = await raffle.getPlayer(0);
assert.equal(contractPlayer, addressDeployer);
});
it("should emit the correct event on enter", async () => {
await expect(raffle.enterRaffle({ value: raffleEntranceFee })).to.emit(
raffle,
"RaffleEnter",
);
});
it("not allow entrance when raffle is calculating state", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
// Pretend to be a chainlink upkeep
await raffle.performUpkeep([]);
await expect(raffle.enterRaffle({ value: raffleEntranceFee })).to.be.revertedWith(
"Raffle__RaffleNotOpen",
);
});
}); //endof enterRaffle
describe("checkUpkeep", function () {
it("should return false if nobody send any ETH", async () => {
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
// Static call to not spend gas & modify state
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep([]);
assert.isFalse(upkeepNeeded);
});
it("should return true if raffle is in calculating state", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
// Pretend to be a chainlink upkeep
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep([]);
assert.isTrue(upkeepNeeded);
});
it("should return false if raffle is not open", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
await raffle.performUpkeep("0x");
const raffleState = await raffle.getRaffleState();
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep([]);
assert.isFalse(upkeepNeeded);
});
it("returns false if enough time hasn't passed", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() - 5]); // use a higher number here if this test fails
await network.provider.request({ method: "evm_mine", params: [] }); // Alternative to write
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x"); // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert(!upkeepNeeded);
});
it("returns true if enough time has passed, has players, eth, and is open", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
const { upkeepNeeded } = await raffle.callStatic.checkUpkeep("0x"); // upkeepNeeded = (timePassed && isOpen && hasBalance && hasPlayers)
assert(upkeepNeeded);
});
}); //endof checkUpkeep
describe("performUpkeep", function () {
it("it can only run if checkupkeep is true", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
const tx = await raffle.performUpkeep("0x");
assert(tx);
});
it("it should revert if checkupkeep is false", async () => {
await expect(raffle.performUpkeep("0x")).to.be.revertedWith(
"Raffle__UpkeepNotNeeded",
);
});
it("update the raffle sate, emits and event, and call the vrf coordinator", async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.request({ method: "evm_mine", params: [] });
const txResponse = await raffle.performUpkeep("0x");
const txReceipt = await txResponse.wait(1);
const requestId = txReceipt.events[1].args.requestId; // 2nd Event
const currentRaffleState = await raffle.getRaffleState();
assert(requestId.toNumber() > 0);
assert(currentRaffleState == 1);
});
});
describe("fulfillRandomWords", function () {
beforeEach(async () => {
await raffle.enterRaffle({ value: raffleEntranceFee });
await network.provider.send("evm_increaseTime", [interval.toNumber() + 1]);
await network.provider.send("evm_mine", []);
});
it("can only be called after performUpKeep", async () => {
const requestId = 0; // Not using
await expect(
vrfCoordinatorV2_5Mock.fulfillRandomWords(0, raffle.address),
).to.be.revertedWith("InvalidRequest");
});
});
});
+4 -55
View File
@@ -1865,14 +1865,6 @@
"@nomicfoundation/ethereumjs-rlp" "5.0.4"
ethereum-cryptography "0.1.3"
"@nomicfoundation/hardhat-ethers@^3.0.2":
version "3.0.6"
resolved "https://registry.yarnpkg.com/@nomicfoundation/hardhat-ethers/-/hardhat-ethers-3.0.6.tgz#e8ba7f9719de360c03501b85dae4999bb3a7e1c5"
integrity sha512-/xzkFQAaHQhmIAYOQmvHBPwL+NkwLzT9gRZBsgWUYeV+E6pzXsBQsHfRYbAZ3XEYare+T7S+5Tg/1KDJgepSkA==
dependencies:
debug "^4.1.1"
lodash.isequal "^4.5.0"
"@nomicfoundation/[email protected]":
version "0.1.2"
resolved "https://registry.yarnpkg.com/@nomicfoundation/solidity-analyzer-darwin-arm64/-/solidity-analyzer-darwin-arm64-0.1.2.tgz#3a9c3b20d51360b20affb8f753e756d553d49557"
@@ -1921,10 +1913,10 @@
"@nomicfoundation/solidity-analyzer-linux-x64-musl" "0.1.2"
"@nomicfoundation/solidity-analyzer-win32-x64-msvc" "0.1.2"
"@nomiclabs/hardhat-ethers@^2.2.3":
version "2.2.3"
resolved "https://registry.yarnpkg.com/@nomiclabs/hardhat-ethers/-/hardhat-ethers-2.2.3.tgz#b41053e360c31a32c2640c9a45ee981a7e603fe0"
integrity sha512-YhzPdzb612X591FOe68q+qXVXGG2ANZRvDo0RRUtimev85rCrAlv/TLMEZw5c+kq9AbzocLTVX/h2jVIFPL9Xg==
"@nomiclabs/hardhat-ethers@npm:hardhat-deploy-ethers@^0.3.0-beta.13":
version "0.3.0-beta.13"
resolved "https://registry.yarnpkg.com/hardhat-deploy-ethers/-/hardhat-deploy-ethers-0.3.0-beta.13.tgz#b96086ff768ddf69928984d5eb0a8d78cfca9366"
integrity sha512-PdWVcKB9coqWV1L7JTpfXRCI91Cgwsm7KLmBcwZ8f0COSm1xtABHZTyz3fvF6p42cTnz1VM0QnfDvMFlIRkSNw==
"@nomiclabs/hardhat-etherscan@^3.1.8":
version "3.1.8"
@@ -2971,11 +2963,6 @@ assertion-error@^1.1.0:
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b"
integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==
assertion-error@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7"
integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==
assign-symbols@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
@@ -4237,17 +4224,6 @@ chai@^4.0.1, chai@^4.2.0, chai@^4.3.4:
pathval "^1.1.1"
type-detect "^4.1.0"
chai@^5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.1.tgz#f035d9792a22b481ead1c65908d14bb62ec1c82c"
integrity sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==
dependencies:
assertion-error "^2.0.1"
check-error "^2.1.1"
deep-eql "^5.0.1"
loupe "^3.1.0"
pathval "^2.0.0"
[email protected], chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@@ -4317,11 +4293,6 @@ check-error@^1.0.2, check-error@^1.0.3:
dependencies:
get-func-name "^2.0.2"
check-error@^2.1.1:
version "2.1.1"
resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc"
integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==
checkpoint-store@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/checkpoint-store/-/checkpoint-store-1.1.0.tgz#04e4cb516b91433893581e6d4601a78e9552ea06"
@@ -4985,11 +4956,6 @@ deep-eql@^4.1.3:
dependencies:
type-detect "^4.0.0"
deep-eql@^5.0.1:
version "5.0.2"
resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341"
integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==
deep-equal@~1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.1.2.tgz#78a561b7830eef3134c7f6f3a3d6af272a678761"
@@ -8628,11 +8594,6 @@ lodash.debounce@^4.0.8:
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
integrity sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==
lodash.isequal@^4.5.0:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
integrity sha512-pDo3lu8Jhfjqls6GkMgpahsF9kCyayhgykjyLMNFTKWrpVdAQtYyB4muAMWozBB4ig/dtWAmsMxLEI8wuz+DYQ==
lodash.merge@^4.6.2:
version "4.6.2"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
@@ -8700,13 +8661,6 @@ loupe@^2.3.6:
dependencies:
get-func-name "^2.0.1"
loupe@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.1.tgz#71d038d59007d890e3247c5db97c1ec5a92edc54"
integrity sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==
dependencies:
get-func-name "^2.0.1"
lower-case-first@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
@@ -9895,11 +9849,6 @@ pathval@^1.1.1:
resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d"
integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==
pathval@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25"
integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==
pbkdf2@^3.0.17, pbkdf2@^3.0.3, pbkdf2@^3.0.9, pbkdf2@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.1.2.tgz#dd822aa0887580e52f1a039dc3eda108efae3075"