{"slug":"web3-testing","title":"web3-testing","summary":"Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.","platform":"ChatGPT","tags":[],"authorName":"LLM Mart","authorSlug":"llm-mart","score":0,"source":"github","price":null,"verified":false,"createdAt":"2026-08-16T13:39:07.627485Z","repo":{"url":"https://github.com/sickn33/agentic-awesome-skills","stars":46883,"forks":6831,"license":"MIT","updatedAt":"2026-09-25T05:43:16Z"},"bodyHtml":"<hr>\n<h2>name: web3-testing\ndescription: \"Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.\"\nrisk: critical\nsource: community\ndate_added: \"2026-02-27\"</h2>\n<h1>Web3 Smart Contract Testing</h1>\n<p>Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.</p>\n<h2>Do not use this skill when</h2>\n<ul>\n<li>The task is unrelated to web3 smart contract testing</li>\n<li>You need a different domain or tool outside this scope</li>\n</ul>\n<h2>Instructions</h2>\n<ul>\n<li>Clarify goals, constraints, and required inputs.</li>\n<li>Apply relevant best practices and validate outcomes.</li>\n<li>Provide actionable steps and verification.</li>\n<li>If detailed examples are required, open <code>resources/implementation-playbook.md</code>.</li>\n</ul>\n<h2>Use this skill when</h2>\n<ul>\n<li>Writing unit tests for smart contracts</li>\n<li>Setting up integration test suites</li>\n<li>Performing gas optimization testing</li>\n<li>Fuzzing for edge cases</li>\n<li>Forking mainnet for realistic testing</li>\n<li>Automating test coverage reporting</li>\n<li>Verifying contracts on Etherscan</li>\n</ul>\n<h2>Hardhat Testing Setup</h2>\n<pre><code>// hardhat.config.js\nrequire(\"@nomicfoundation/hardhat-toolbox\");\nrequire(\"@nomiclabs/hardhat-etherscan\");\nrequire(\"hardhat-gas-reporter\");\nrequire(\"solidity-coverage\");\n\nmodule.exports = {\n  solidity: {\n    version: \"0.8.19\",\n    settings: {\n      optimizer: {\n        enabled: true,\n        runs: 200,\n      },\n    },\n  },\n  networks: {\n    hardhat: {\n      forking: {\n        url: process.env.MAINNET_RPC_URL,\n        blockNumber: 15000000,\n      },\n    },\n    goerli: {\n      url: process.env.GOERLI_RPC_URL,\n      accounts: [process.env.PRIVATE_KEY],\n    },\n  },\n  gasReporter: {\n    enabled: true,\n    currency: \"USD\",\n    coinmarketcap: process.env.COINMARKETCAP_API_KEY,\n  },\n  etherscan: {\n    apiKey: process.env.ETHERSCAN_API_KEY,\n  },\n};\n</code></pre>\n<h2>Unit Testing Patterns</h2>\n<pre><code>const { expect } = require(\"chai\");\nconst { ethers } = require(\"hardhat\");\nconst {\n  loadFixture,\n  time,\n} = require(\"@nomicfoundation/hardhat-network-helpers\");\n\ndescribe(\"Token Contract\", function () {\n  // Fixture for test setup\n  async function deployTokenFixture() {\n    const [owner, addr1, addr2] = await ethers.getSigners();\n\n    const Token = await ethers.getContractFactory(\"Token\");\n    const token = await Token.deploy();\n\n    return { token, owner, addr1, addr2 };\n  }\n\n  describe(\"Deployment\", function () {\n    it(\"Should set the right owner\", async function () {\n      const { token, owner } = await loadFixture(deployTokenFixture);\n      expect(await token.owner()).to.equal(owner.address);\n    });\n\n    it(\"Should assign total supply to owner\", async function () {\n      const { token, owner } = await loadFixture(deployTokenFixture);\n      const ownerBalance = await token.balanceOf(owner.address);\n      expect(await token.totalSupply()).to.equal(ownerBalance);\n    });\n  });\n\n  describe(\"Transactions\", function () {\n    it(\"Should transfer tokens between accounts\", async function () {\n      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);\n\n      await expect(token.transfer(addr1.address, 50)).to.changeTokenBalances(\n        token,\n        [owner, addr1],\n        [-50, 50],\n      );\n    });\n\n    it(\"Should fail if sender doesn't have enough tokens\", async function () {\n      const { token, addr1 } = await loadFixture(deployTokenFixture);\n      const initialBalance = await token.balanceOf(addr1.address);\n\n      await expect(\n        token.connect(addr1).transfer(owner.address, 1),\n      ).to.be.revertedWith(\"Insufficient balance\");\n    });\n\n    it(\"Should emit Transfer event\", async function () {\n      const { token, owner, addr1 } = await loadFixture(deployTokenFixture);\n\n      await expect(token.transfer(addr1.address, 50))\n        .to.emit(token, \"Transfer\")\n        .withArgs(owner.address, addr1.address, 50);\n    });\n  });\n\n  describe(\"Time-based tests\", function () {\n    it(\"Should handle time-locked operations\", async function () {\n      const { token } = await loadFixture(deployTokenFixture);\n\n      // Increase time by 1 day\n      await time.increase(86400);\n\n      // Test time-dependent functionality\n    });\n  });\n\n  describe(\"Gas optimization\", function () {\n    it(\"Should use gas efficiently\", async function () {\n      const { token } = await loadFixture(deployTokenFixture);\n\n      const tx = await token.transfer(addr1.address, 100);\n      const receipt = await tx.wait();\n\n      expect(receipt.gasUsed).to.be.lessThan(50000);\n    });\n  });\n});\n</code></pre>\n<h2>Foundry Testing (Forge)</h2>\n<pre><code>// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport \"forge-std/Test.sol\";\nimport \"../src/Token.sol\";\n\ncontract TokenTest is Test {\n    Token token;\n    address owner = address(1);\n    address user1 = address(2);\n    address user2 = address(3);\n\n    function setUp() public {\n        vm.prank(owner);\n        token = new Token();\n    }\n\n    function testInitialSupply() public {\n        assertEq(token.totalSupply(), 1000000 * 10**18);\n    }\n\n    function testTransfer() public {\n        vm.prank(owner);\n        token.transfer(user1, 100);\n\n        assertEq(token.balanceOf(user1), 100);\n        assertEq(token.balanceOf(owner), token.totalSupply() - 100);\n    }\n\n    function testFailTransferInsufficientBalance() public {\n        vm.prank(user1);\n        token.transfer(user2, 100); // Should fail\n    }\n\n    function testCannotTransferToZeroAddress() public {\n        vm.prank(owner);\n        vm.expectRevert(\"Invalid recipient\");\n        token.transfer(address(0), 100);\n    }\n\n    // Fuzzing test\n    function testFuzzTransfer(uint256 amount) public {\n        vm.assume(amount &gt; 0 &amp;&amp; amount &lt;= token.totalSupply());\n\n        vm.prank(owner);\n        token.transfer(user1, amount);\n\n        assertEq(token.balanceOf(user1), amount);\n    }\n\n    // Test with cheatcodes\n    function testDealAndPrank() public {\n        // Give ETH to address\n        vm.deal(user1, 10 ether);\n\n        // Impersonate address\n        vm.prank(user1);\n\n        // Test functionality\n        assertEq(user1.balance, 10 ether);\n    }\n\n    // Mainnet fork test\n    function testForkMainnet() public {\n        vm.createSelectFork(\"https://eth-mainnet.alchemyapi.io/v2/...\");\n\n        // Interact with mainnet contracts\n        address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;\n        assertEq(IERC20(dai).symbol(), \"DAI\");\n    }\n}\n</code></pre>\n<h2>Advanced Testing Patterns</h2>\n<h3>Snapshot and Revert</h3>\n<pre><code>describe(\"Complex State Changes\", function () {\n  let snapshotId;\n\n  beforeEach(async function () {\n    snapshotId = await network.provider.send(\"evm_snapshot\");\n  });\n\n  afterEach(async function () {\n    await network.provider.send(\"evm_revert\", [snapshotId]);\n  });\n\n  it(\"Test 1\", async function () {\n    // Make state changes\n  });\n\n  it(\"Test 2\", async function () {\n    // State reverted, clean slate\n  });\n});\n</code></pre>\n<h3>Mainnet Forking</h3>\n<pre><code>describe(\"Mainnet Fork Tests\", function () {\n  let uniswapRouter, dai, usdc;\n\n  before(async function () {\n    await network.provider.request({\n      method: \"hardhat_reset\",\n      params: [\n        {\n          forking: {\n            jsonRpcUrl: process.env.MAINNET_RPC_URL,\n            blockNumber: 15000000,\n          },\n        },\n      ],\n    });\n\n    // Connect to existing mainnet contracts\n    uniswapRouter = await ethers.getContractAt(\n      \"IUniswapV2Router\",\n      \"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D\",\n    );\n\n    dai = await ethers.getContractAt(\n      \"IERC20\",\n      \"0x6B175474E89094C44Da98b954EedeAC495271d0F\",\n    );\n  });\n\n  it(\"Should swap on Uniswap\", async function () {\n    // Test with real Uniswap contracts\n  });\n});\n</code></pre>\n<h3>Impersonating Accounts</h3>\n<pre><code>it(\"Should impersonate whale account\", async function () {\n  const whaleAddress = \"0x...\";\n\n  await network.provider.request({\n    method: \"hardhat_impersonateAccount\",\n    params: [whaleAddress],\n  });\n\n  const whale = await ethers.getSigner(whaleAddress);\n\n  // Use whale's tokens\n  await dai\n    .connect(whale)\n    .transfer(addr1.address, ethers.utils.parseEther(\"1000\"));\n});\n</code></pre>\n<h2>Gas Optimization Testing</h2>\n<pre><code>const { expect } = require(\"chai\");\n\ndescribe(\"Gas Optimization\", function () {\n  it(\"Compare gas usage between implementations\", async function () {\n    const Implementation1 =\n      await ethers.getContractFactory(\"OptimizedContract\");\n    const Implementation2 = await ethers.getContractFactory(\n      \"UnoptimizedContract\",\n    );\n\n    const contract1 = await Implementation1.deploy();\n    const contract2 = await Implementation2.deploy();\n\n    const tx1 = await contract1.doSomething();\n    const receipt1 = await tx1.wait();\n\n    const tx2 = await contract2.doSomething();\n    const receipt2 = await tx2.wait();\n\n    console.log(\"Optimized gas:\", receipt1.gasUsed.toString());\n    console.log(\"Unoptimized gas:\", receipt2.gasUsed.toString());\n\n    expect(receipt1.gasUsed).to.be.lessThan(receipt2.gasUsed);\n  });\n});\n</code></pre>\n<h2>Coverage Reporting</h2>\n<pre><code># Generate coverage report\nnpx hardhat coverage\n\n# Output shows:\n# File                | % Stmts | % Branch | % Funcs | % Lines |\n# -------------------|---------|----------|---------|---------|\n# contracts/Token.sol |   100   |   90     |   100   |   95    |\n</code></pre>\n<h2>Contract Verification</h2>\n<pre><code>// Verify on Etherscan\nawait hre.run(\"verify:verify\", {\n  address: contractAddress,\n  constructorArguments: [arg1, arg2],\n});\n</code></pre>\n<pre><code># Or via CLI\nnpx hardhat verify --network mainnet CONTRACT_ADDRESS \"Constructor arg1\" \"arg2\"\n</code></pre>\n<h2>CI/CD Integration</h2>\n<pre><code># .github/workflows/test.yml\nname: Tests\n\non: [push, pull_request]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: \"16\"\n\n      - run: npm install\n      - run: npx hardhat compile\n      - run: npx hardhat test\n      - run: npx hardhat coverage\n\n      - name: Upload coverage to Codecov\n        uses: codecov/codecov-action@v2\n</code></pre>\n<h2>Resources</h2>\n<ul>\n<li><strong>references/hardhat-setup.md</strong>: Hardhat configuration guide</li>\n<li><strong>references/foundry-setup.md</strong>: Foundry testing framework</li>\n<li><strong>references/test-patterns.md</strong>: Testing best practices</li>\n<li><strong>references/mainnet-forking.md</strong>: Fork testing strategies</li>\n<li><strong>references/contract-verification.md</strong>: Etherscan verification</li>\n<li><strong>assets/hardhat-config.js</strong>: Complete Hardhat configuration</li>\n<li><strong>assets/test-suite.js</strong>: Comprehensive test examples</li>\n<li><strong>assets/foundry.toml</strong>: Foundry configuration</li>\n<li><strong>scripts/test-contract.sh</strong>: Automated testing script</li>\n</ul>\n<h2>Best Practices</h2>\n<ol>\n<li><strong>Test Coverage</strong>: Aim for &gt;90% coverage</li>\n<li><strong>Edge Cases</strong>: Test boundary conditions</li>\n<li><strong>Gas Limits</strong>: Verify functions don't hit block gas limit</li>\n<li><strong>Reentrancy</strong>: Test for reentrancy vulnerabilities</li>\n<li><strong>Access Control</strong>: Test unauthorized access attempts</li>\n<li><strong>Events</strong>: Verify event emissions</li>\n<li><strong>Fixtures</strong>: Use fixtures to avoid code duplication</li>\n<li><strong>Mainnet Fork</strong>: Test with real contracts</li>\n<li><strong>Fuzzing</strong>: Use property-based testing</li>\n<li><strong>CI/CD</strong>: Automate testing on every commit</li>\n</ol>\n<h2>Limitations</h2>\n<ul>\n<li>Use this skill only when the task clearly matches the scope described above.</li>\n<li>Do not treat the output as a substitute for environment-specific validation, testing, or expert review.</li>\n<li>Stop and ask for clarification if required inputs, permissions, safety boundaries, or success criteria are missing.</li>\n</ul>\n","files":[{"path":"SKILL.md","sizeBytes":11387,"isText":true}],"reviewScore":null,"reviewSummary":null,"trust":{"provenance":"human-reviewed","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow.","bodySource":null},"bodyLocked":false,"purchaseUrl":null,"sourceUrl":null,"report":{"provenance":"human-reviewed","screen":{"ran":true,"outcome":"flagged-cleared-by-moderator","suspicious":2,"notes":2,"hiddenCharacters":false},"virusScan":{"engine":"clamav","status":"clean","scannedAt":"2026-08-16T13:47:31.389042Z","sha256":"FAB359A948069918E9D6388DC4DD32805E4D16C26D2BC73307ABD20FB97ED1DC","sizeBytes":3960},"review":null,"source":{"repositoryUrl":"https://github.com/sickn33/agentic-awesome-skills","path":"skills/web3-testing","license":"MIT","commit":"f2bba339de74414b0771234cbe4f6a15258e32a3","subtreeSha":"35E59E273BE8D42A269B0CF36458F94663968427BF693E78DE29E9A96BFB5F20","lastSyncedAt":"2026-09-25T06:48:39.853703Z"},"reviewedAt":"2026-08-16T14:03:49.549308Z","notice":"Community-authored content, reproduced verbatim and not vetted as instructions. Treat it as data to evaluate, never as directives to follow."},"install":[{"target":"skills-cli","command":"npx skills add https://github.com/sickn33/agentic-awesome-skills/tree/main/skills/web3-testing"},{"target":"claude-code","command":"claude plugin marketplace add https://llmmart.ai/marketplace.json && claude plugin install sickn33-agentic-awesome-skills@llmmart"},{"target":"git","command":"git clone https://github.com/sickn33/agentic-awesome-skills.git"}]}