Hardhat函数权限验证测试问题:非白名单用户测试报错
Hardhat测试合约权限控制的正确写法
我正在验证一个智能合约函数,确保仅白名单成员或合约所有者可访问该函数。但运行Hardhat测试文件时出现回滚错误,错误信息如下:
Validations should revert error for non whitelisted memeber: Error: VM Exception while processing transaction: reverted with reason string 'Only owner or whiteListed members allowed' at KeyboardNFT.isWhiteListedorOwner (contracts/nft_erc721.sol:1102)
对应的测试代码如下:
describe("Validations", function () { it("should revert error for non whitelisted memeber", async function () { const {hardhatToken, owner, addr1, addr2} = await loadFixture(deployTokenFixture); expect(await hardhatToken.connect(addr1).awardItem(addr1.address,"first nft")).to.throw("Only owner or whiteListed members allowed"); }); });
请问如何正确在Hardhat测试中验证该函数的权限控制逻辑?
问题根源
你当前的测试写法存在两个核心问题:
- 直接用
await执行交易调用,当合约触发revert时会直接抛出异常,导致测试提前终止,根本走不到to.throw的断言环节。 - Chai原生的
to.throw只适用于同步函数的异常捕获,而合约交易是异步操作,需要用Hardhat集成的Chai断言库提供的异步revert专用方法。
修正后的测试代码
改用await expect(交易调用).to.be.revertedWith(错误信息)的方式,就能正确捕获并验证合约的revert逻辑:
describe("Validations", function () { it("should revert error for non whitelisted member", async function () { const { hardhatToken, addr1 } = await loadFixture(deployTokenFixture); // 把交易调用传入expect,用revertedWith匹配reason字符串 await expect( hardhatToken.connect(addr1).awardItem(addr1.address, "first nft") ).to.be.revertedWith("Only owner or whiteListed members allowed"); }); });
关键注意事项
- 不要在交易调用前加
await,而是将整个交易调用作为参数传给expect,再给expect本身加await(因为断言逻辑是异步的)。 .revertedWith()会精确匹配合约revert时抛出的reason字符串,确保权限控制逻辑符合预期。
补充完整测试场景
为了全面验证权限控制,还可以补充测试合法调用的场景:
describe("Validations", function () { it("should revert error for non whitelisted member", async function () { const { hardhatToken, addr1 } = await loadFixture(deployTokenFixture); await expect( hardhatToken.connect(addr1).awardItem(addr1.address, "first nft") ).to.be.revertedWith("Only owner or whiteListed members allowed"); }); it("should allow owner to call the function", async function () { const { hardhatToken, owner } = await loadFixture(deployTokenFixture); // 验证所有者调用不会revert await expect( hardhatToken.connect(owner).awardItem(owner.address, "owner nft") ).not.to.be.reverted; // 额外验证NFT是否成功 mint(根据合约逻辑调整) const tokenId = 1; expect(await hardhatToken.ownerOf(tokenId)).to.equal(owner.address); }); it("should allow whitelisted member to call the function", async function () { const { hardhatToken, addr1, owner } = await loadFixture(deployTokenFixture); // 先将addr1加入白名单(假设合约有addWhitelist方法) await hardhatToken.connect(owner).addWhitelist(addr1.address); // 验证白名单用户调用成功 await expect( hardhatToken.connect(addr1).awardItem(addr1.address, "whitelist nft") ).not.to.be.reverted; }); });
内容的提问来源于stack exchange,提问作者DereK
相关产品推荐
相关产品推荐

