with one click
web3-testing
Test smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or validating DeFi protocols.
Test smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or validating DeFi protocols.
| name | web3-testing |
| description | Test smart contracts comprehensively using Hardhat and Foundry with unit tests, integration tests, and mainnet forking. Use when testing Solidity contracts, setting up blockchain test suites, or validating DeFi protocols. |
Master comprehensive testing strategies for smart contracts using Hardhat, Foundry, and advanced testing patterns.
// 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,
},
};
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);
});
});
});
// 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) public {
vm.assume(amount > 0 && amount <= token.totalSupply());
vm.prank(owner);
token.transfer(user1, amount);
assertEq(token.balanceOf(user1), amount);
}
// Test with cheatcodes
function testDealAndPrank() public {
// Give ETH to address
vm.deal(user1, 10 ether);
// Impersonate address
vm.prank(user1);
// Test functionality
assertEq(user1.balance, 10 ether);
}
// Mainnet fork test
function testForkMainnet() public {
vm.createSelectFork("https://eth-mainnet.alchemyapi.io/v2/...");
// Interact with mainnet contracts
address dai = 0x6B175474E89094C44Da98b954EedeAC495271d0F;
assertEq(IERC20(dai).symbol(), "DAI");
}
}
describe("Complex State Changes", function () {
let snapshotId;
beforeEach(async function () {
snapshotId = await network.provider.send("evm_snapshot");
});
afterEach(async function () {
await network.provider.send("evm_revert", [snapshotId]);
});
it("Test 1", async function () {
// Make state changes
});
it("Test 2", async function () {
// State reverted, clean slate
});
});
describe("Mainnet Fork Tests", function () {
let uniswapRouter, dai, usdc;
before(async function () {
await network.provider.request({
method: "hardhat_reset",
params: [
{
forking: {
jsonRpcUrl: process.env.MAINNET_RPC_URL,
blockNumber: 15000000,
},
},
],
});
// Connect to existing mainnet contracts
uniswapRouter = await ethers.getContractAt(
"IUniswapV2Router",
"0x7a250d5630B4cF539739dF2C5dAcb4c659F2488D",
);
dai = await ethers.getContractAt(
"IERC20",
"0x6B175474E89094C44Da98b954EedeAC495271d0F",
);
});
it("Should swap on Uniswap", async function () {
// Test with real Uniswap contracts
});
});
it("Should impersonate whale account", async function () {
const whaleAddress = "0x...";
await network.provider.request({
method: "hardhat_impersonateAccount",
params: [whaleAddress],
});
const whale = await ethers.getSigner(whaleAddress);
// Use whale's tokens
await dai
.connect(whale)
.transfer(addr1.address, ethers.utils.parseEther("1000"));
});
More detailed templates and worked examples live in references/details.md. Read that file for the full pattern library.
Schedule and publish social media posts across 13 platforms (X, LinkedIn, Instagram, Facebook Pages, TikTok, Discord, Telegram, YouTube, Reddit, WordPress, Pinterest) via the SocialClaw API. Use when the user wants to publish, schedule, or manage social media content programmatically. Requires SOCIALCLAW_API_KEY.
Conduct WCAG 2.2 accessibility audits with automated testing, manual verification, and remediation guidance. Use when auditing websites for accessibility, fixing WCAG violations, or implementing accessible design patterns.
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Master REST and GraphQL API design principles to build intuitive, scalable, and maintainable APIs that delight developers. Use when designing new APIs, reviewing API specifications, or establishing API design standards.
Implement proven backend architecture patterns including Clean Architecture, Hexagonal Architecture, and Domain-Driven Design. Use this skill when designing clean architecture for a new microservice, when refactoring a monolith to use bounded contexts, when implementing hexagonal or onion architecture patterns, or when debugging dependency cycles between application layers.
Implement Command Query Responsibility Segregation for scalable architectures. Use when separating read and write models, optimizing query performance, or building event-sourced systems.