使用Viem与Hardhat测试时,无法向revertWithCustomError传入合约
解决Hardhat+Viem测试自定义错误时
revertWithCustomError不兼容问题 你碰到的问题源于revertWithCustomError是为Ethers合约实例设计的断言方法,它要求合约对象包含interface属性,但Viem生成的合约实例用abi属性替代了interface,导致类型不匹配报错。以下是两种可行的解决方案:
方案一:使用Viem原生方式验证自定义错误
Viem提供了getContractError工具函数,可直接解析交易失败的错误信息,无需依赖Ethers的合约结构:
- 导入Viem的错误解析工具:
import { getContractError } from '@nomicfoundation/hardhat-viem/utils'
- 修改测试代码,捕获错误并断言:
it('Should block the heir', async () => { const { deployedContract, other } = await loadFixture(deployFixture); try { await deployedContract.write.withdraw([BigInt(0)], { account: other.account, }); expect.fail('交易未按预期回滚'); } catch (error) { const contractError = getContractError(error, deployedContract.abi); expect(contractError?.name).to.equal('Unauthorized'); } });
方案二:混用Ethers合约实例做断言
如果更习惯revertWithCustomError的语法,可以同时获取Ethers风格的合约实例,用它满足断言的参数要求:
- 在部署Fixture中添加Ethers合约实例:
async function deployFixture() { const [owner, other] = await hre.viem.getWalletClients(); const deployedContract = await hre.viem.deployContract("Inheritance", [], { value: BigInt('50'), }); const ethersContract = await hre.ethers.getContractAt("Inheritance", deployedContract.address); return { owner, other, deployedContract, ethersContract, }; };
- 测试时用Ethers合约作为
revertWithCustomError的第一个参数:
it('Should block the heir', async () => { const { deployedContract, other, ethersContract } = await loadFixture(deployFixture); await expect( deployedContract.write.withdraw([BigInt(0)], { account: other.account, }) ).to.be.revertedWithCustomError(ethersContract, "Unauthorized"); });
核心原因说明
revertWithCustomError是Hardhat Ethers插件扩展的Chai断言,它依赖Ethers合约的interface属性解码自定义错误。而Viem的合约实例采用了不同设计,用abi属性存储合约ABI,没有interface字段,因此直接传入Viem合约会触发类型错误。
内容的提问来源于stack exchange,提问作者Francisco Canela
相关产品推荐
相关产品推荐

