Core testing infrastructure for Ethereum Waffle including MockProvider for local blockchain simulation, pre-funded test accounts, fixtures for efficient test setup, and comprehensive call history tracking.
Enhanced Web3Provider designed specifically for testing, providing isolated blockchain environment with pre-funded accounts, call history tracking, and ENS support.
/**
* Enhanced Web3Provider for testing with isolated blockchain environment
* @param options - Configuration options for the provider
*/
class MockProvider extends providers.Web3Provider {
constructor(options?: MockProviderOptions);
/** Get array of pre-funded test wallets */
getWallets(): Wallet[];
/** Create new empty wallet without ETH balance */
createEmptyWallet(): Wallet;
/** Clear all recorded contract calls */
clearCallHistory(): void;
/** Setup ENS domain resolution for testing */
setupENS(wallet?: Wallet): Promise<void>;
/** Read-only access to all recorded contract calls */
readonly callHistory: readonly RecordedCall[];
/** ENS instance if setupENS was called */
readonly ens: ENS | undefined;
}
interface MockProviderOptions {
ganacheOptions: EthereumProviderOptions;
}
interface RecordedCall {
readonly address: string | undefined;
readonly data: string;
}Usage Examples:
import { MockProvider } from "ethereum-waffle";
// Create provider with default settings
const provider = new MockProvider();
const [wallet, otherWallet] = provider.getWallets();
// Create provider with custom ganache options
const customProvider = new MockProvider({
ganacheOptions: {
gasLimit: 8000000,
gasPrice: 20000000000
}
});
// Track contract calls
const contract = await deployContract(wallet, contractJson);
await contract.someFunction();
console.log(provider.callHistory); // Array of RecordedCall objects
// Setup ENS for testing
await provider.setupENS(wallet);
const address = await provider.resolveName('test.eth');Efficient test setup system with automatic blockchain snapshotting and restoration, enabling fast test execution by reusing common setup scenarios.
/**
* Function type for test fixtures that setup testing environment
* @param wallets - Array of funded wallets for testing
* @param provider - MockProvider instance
* @returns Promise resolving to fixture state
*/
type Fixture<T> = (wallets: Wallet[], provider: MockProvider) => Promise<T>;
/**
* Load a fixture with automatic snapshotting for test isolation
* @param fixture - Fixture function to execute and cache
* @returns Promise resolving to fixture result
*/
function loadFixture<T>(fixture: Fixture<T>): Promise<T>;
/**
* Create custom fixture loader with specific wallets and provider
* @param overrideWallets - Custom wallets to use instead of defaults
* @param overrideProvider - Custom provider to use instead of default
* @returns Fixture loader function
*/
function createFixtureLoader(
overrideWallets?: Wallet[],
overrideProvider?: MockProvider
): <T>(fixture: Fixture<T>) => Promise<T>;Usage Examples:
import { loadFixture, MockProvider } from "ethereum-waffle";
// Define a fixture
const myFixture: Fixture<{token: Contract, wallet: Wallet}> = async (wallets, provider) => {
const [wallet] = wallets;
const token = await deployContract(wallet, ERC20Json, ["Test Token", "TEST"]);
await token.mint(wallet.address, 1000);
return { token, wallet };
};
// Use fixture in tests - automatically cached and snapshot restored
it("should transfer tokens", async () => {
const { token, wallet } = await loadFixture(myFixture);
// Test logic here - fresh state each time
});
// Create custom fixture loader
const customLoader = createFixtureLoader(customWallets, customProvider);
const result = await customLoader(myFixture);Pre-configured test accounts with deterministic private keys and substantial ETH balances for consistent testing.
/**
* Array of 10 pre-funded test accounts with deterministic private keys
* Each account has balance: '0x1ED09BEAD87C0378D8E6400000000' (10^34 wei)
*/
const defaultAccounts: Array<{
balance: string;
secretKey: string;
}>;Usage Examples:
import { defaultAccounts, MockProvider } from "ethereum-waffle";
// Access account private keys
const privateKey = defaultAccounts[0].secretKey;
const wallet = new Wallet(privateKey);
// Check account balance (same for all 10 accounts)
console.log(defaultAccounts[0].balance); // '0x1ED09BEAD87C0378D8E6400000000'
// Use with custom provider
const provider = new MockProvider();
const wallets = provider.getWallets(); // Uses defaultAccounts automaticallySystem for recording and analyzing contract function calls during testing, useful for verifying interaction patterns and debugging.
/**
* Tracks and manages contract call history
*/
class CallHistory {
/** Clear all recorded calls */
clear(): void;
/** Get array of all recorded calls */
getCalls(): RecordedCall[];
/** Wrap provider to record calls */
record(provider: Provider): Provider;
}Usage Examples:
import { MockProvider } from "ethereum-waffle";
const provider = new MockProvider();
const [wallet] = provider.getWallets();
// Deploy and interact with contract
const contract = await deployContract(wallet, contractJson);
await contract.setValue(42);
await contract.getValue();
// Check call history
console.log(provider.callHistory.length); // 2
console.log(provider.callHistory[0].data); // Encoded setValue call data
// Clear history for next test
provider.clearCallHistory();Utilities for extracting and handling revert reasons from failed transactions, providing better debugging information during testing.
/**
* Extract revert reason string from call revert error
* @param callRevertError - Error object from failed contract call
* @returns Decoded revert reason string
*/
function decodeRevertString(callRevertError: any): string;
/**
* Append revert string to transaction receipt for debugging
* @param etherProvider - Web3Provider instance
* @param receipt - Transaction receipt to enhance
*/
function appendRevertString(etherProvider: providers.Web3Provider, receipt: any): Promise<void>;
/**
* Inject revert string decoding capabilities into provider
* @param provider - Provider to enhance with revert string support
* @returns Enhanced provider with revert string decoding
*/
function injectRevertString(provider: Provider): Provider;Usage Examples:
import { decodeRevertString, MockProvider } from "ethereum-waffle";
const provider = new MockProvider();
const [wallet] = provider.getWallets();
try {
await contract.requireSomething();
} catch (error) {
const revertReason = decodeRevertString(error);
console.log("Revert reason:", revertReason); // "Something is required"
}
// Enhance provider with automatic revert string extraction
const enhancedProvider = injectRevertString(provider);Factory function for creating custom fixture loaders with specific wallets and providers, enabling advanced test setup scenarios.
/**
* Create custom fixture loader with specific wallets and provider
* @param overrideWallets - Custom wallets to use instead of defaults
* @param overrideProvider - Custom provider to use instead of default
* @returns Fixture loader function
*/
function createFixtureLoader(
overrideWallets?: Wallet[],
overrideProvider?: MockProvider
): <T>(fixture: Fixture<T>) => Promise<T>;Usage Examples:
import { createFixtureLoader, MockProvider } from "ethereum-waffle";
// Create custom wallets
const customWallets = [
new Wallet("0x1234..."),
new Wallet("0x5678...")
];
// Create custom provider with specific options
const customProvider = new MockProvider({
ganacheOptions: {
gasLimit: 8000000,
accounts: customWallets.map(w => ({
balance: "0x1000000000000000000",
secretKey: w.privateKey
}))
}
});
// Create custom fixture loader
const loadCustomFixture = createFixtureLoader(customWallets, customProvider);
// Use in tests
const myFixture = async (wallets, provider) => {
const [owner, user] = wallets;
const contract = await deployContract(owner, ContractJson);
return { contract, owner, user };
};
const { contract, owner, user } = await loadCustomFixture(myFixture);Enhanced error handling utilities for extracting and analyzing revert reasons from failed transactions.
/**
* Extract revert reason string from call revert error
* @param callRevertError - Error object from failed contract call
* @returns Decoded revert reason string
*/
function decodeRevertString(callRevertError: any): string;
/**
* Append revert string to transaction receipt for debugging
* @param etherProvider - Web3Provider instance
* @param receipt - Transaction receipt to enhance
* @returns Promise that resolves when revert string is appended
*/
function appendRevertString(etherProvider: providers.Web3Provider, receipt: any): Promise<void>;
/**
* Inject revert string decoding capabilities into provider
* @param provider - Provider to enhance with revert string support
* @returns Enhanced provider with revert string decoding
*/
function injectRevertString(provider: Provider): Provider;Usage Examples:
import { decodeRevertString, injectRevertString, MockProvider } from "ethereum-waffle";
const provider = new MockProvider();
const [wallet] = provider.getWallets();
// Manual revert string extraction
try {
await contract.restrictedFunction();
} catch (error) {
const revertReason = decodeRevertString(error);
console.log("Transaction failed:", revertReason);
}
// Automatic revert string enhancement
const enhancedProvider = injectRevertString(provider);
// Enhanced provider automatically includes revert strings in error messages
try {
const contract = new Contract(address, abi, enhancedProvider);
await contract.failingFunction();
} catch (error) {
console.log(error.message); // Includes decoded revert reason
}Type definition for providers enhanced with wallet access, compatible with both MockProvider and other test providers.
/**
* Provider interface with wallet access for testing
*/
type TestProvider = providers.BaseProvider & {
/** Get array of test wallets */
getWallets(): Wallet[];
/** Get L1 fee for transaction (Optimism/L2 networks) */
getL1Fee?(txHash: string): Promise<BigNumber>;
};Usage Examples:
import { TestProvider, MockProvider } from "ethereum-waffle";
function setupTest(provider: TestProvider) {
const wallets = provider.getWallets();
// Test setup logic
}
const mockProvider = new MockProvider();
setupTest(mockProvider); // TypeScript knows MockProvider implements TestProvider