JavaScript is disabled. Some features may not work.
Web3 Testing — ★ 37.1K GitHub Stars — Install Guide | SkillsNav
🇺🇸 English🇨🇳 中文
SkillsNav
Home

Web3 Testing

★ 37K repoframeworkN/AIntermediateClaude
🤖 AI Summary

This skill automates Web3 smart contract testing using Hardhat and Foundry, handling unit tests, integration suites, gas optimization, fuzzing, mainnet forking, and coverage reporting.

How to Install

Claude Code:
git clone --depth 1 https://github.com/wshobson/agents.git && cp agents/plugins/blockchain-web3/skills/web3-testing ~/.claude/skills/SKILL.md -r

Web3 Smart Contract Testing

Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.

When to Use This Skill

  • Writing unit tests for smart contracts
  • Setting up integration test suites
  • Performing gas optimization testing
  • Fuzzing for edge cases
  • Forking mainnet for realistic testing
  • Automating test coverage reporting
  • Verifying contracts on Etherscan

Hardhat Testing Setup

// hardhat.config.js
require("@nomicfoundation/hardhat-toolbox");
require("@nomiclabs/hardhat-etherscan");
require("hardhat-gas-reporter");
require("solidity-coverage");

module.exports = {
  solidity: {
    version: "0.8.19",
    settings: {
      optimizer: {
        enabled: true,
        runs: 200,
      },
    },
  },
  networks: {
    hardhat: {
      forking: {
        url: process.env.MAINNET_RPC_URL,
        blockNumber: 15000000,
      },
    },
    goerli: {
      url: process.env.GOERLI_RPC_URL,
      accounts: [process.env.PRIVATE_KEY],
    },
  },
  gasReporter: {
    enabled: true,
    currency: "USD",
    coinmarketcap: process.env.COINMARKETCAP_API_KEY,
  },
  etherscan: {
    apiKey: process.env.ETHERSCAN_API_KEY,
  },
};

Unit Testing Patterns

const { expect } = require("chai");
const { ethers } = require("hardhat");
const {
  loadFixture,
  time,
} = require("@nomicfoundation/hardhat-network-helpers");

describe("Token Contract", function () {
  // Fixture for test setup
  async function deployTokenFixture() {
    const [owner, addr1, addr2] = await ethers.getSigners();

    const Token = await ethers.getContractFactory("Token");
    const token = await Token.deploy();

    return { token, owner, addr1, addr2 };
  }

  describe("Deployment", function () {
    it("Should set the right owner", async function () {
      const { token, owner } = await loadFixture(deployTokenFixture);
      expect(await token.owner()).to.equal(owner.address);
    });

    it("Should assign total supply to owner", async function () {
      const { token, owner } = await loadFixture(deployTokenFixture);
      const ownerBalance = await token.balanceOf(owner.address);
      expect(await token.totalSupply()).to.equal(ownerBalance);
    });
  });

  describe("Transactions", function () {
    it("Should transfer tokens between accounts", async function () {
      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);

      await expect(token.transfer(addr1.address, 50)).to.changeTokenBalances(
        token,
        [owner, addr1],
        [-50, 50],
      );
    });

    it("Should fail if sender doesn't have enough tokens", async function () {
      const { token, addr1 } = await loadFixture(deployTokenFixture);
      const initialBalance = await token.balanceOf(addr1.address);

      await expect(
        token.connect(addr1).transfer(owner.address, 1),
      ).to.be.revertedWith("Insufficient balance");
    });

    it("Should emit Transfer event", async function () {
      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);

      await expect(token.transfer(addr1.address, 50))
        .to.emit(token, "Transfer")
        .withArgs(owner.address, addr1.address, 50);
    });
  });

  describe("Time-based tests", function () {
    it("Should handle time-locked operations", async function () {
      const { token } = await loadFixture(deployTokenFixture);

      // Increase time by 1 day
      await time.increase(86400);

      // Test time-dependent functionality
    });
  });

  describe("Gas optimization", function () {
    it("Should use gas efficiently", async function () {
      const { token } = await loadFixture(deployTokenFixture);

      const tx = await token.transfer(addr1.address, 100);
      const receipt = await tx.wait();

      expect(receipt.gasUsed).to.be.lessThan(50000);
    });
  });
});

Foundry Testing (Forge)

```solidity // SPDX-License-Identifier: MIT pragma solidity ^0.8.0;

import "forge-std/Test.sol"; import "../src/Token.sol";

contract TokenTest is Test { Token token; address owner = address(1); address user1 = address(2); address user2 = address(3);

function setUp() public {
    vm.prank(owner);
    token = new Token();
}

function testInitialSupply() public {
    assertEq(token.totalSupply(), 1000000 * 10**18);
}

function testTransfer() public {
    vm.prank(owner);
    token.transfer(user1, 100);

    assertEq(token.balanceOf(user1), 100);
    assertEq(token.balanceOf(owner), token.totalSupply() - 100);
}

function testFailTransferInsufficientBalance() public {
    vm.prank(user1);
    token.transfer(user2, 100); // Should fail
}

function testCannotTransferToZeroAddress() public {
    vm.prank(owner);
    vm.expectRevert("Invalid recipient");
    token.transfer(address(0), 100);
}

// Fuzzing test
function testFuzzTransfer(uint256 amount) publ

Details

Category Frontend → framework
Sourcewshobson/agents
SKILL.mdView on GitHub →
Repo Stars★ 37.1K
Est. per Skill371 (shared across 100 skills from this repo)
DifficultyIntermediate
Risk LevelN/A

Related Skills

Works Well With

Skills from the same repository — often designed to work together