### LocalNodeManager Initialization and Start Source: https://github.com/coinbase/onchaintestkit/blob/master/README.md Example of creating and starting a LocalNodeManager with automatic port allocation. Ensure the E2E_TEST_SEED_PHRASE environment variable is set. ```typescript // Create node with automatic port allocation const nodeManager = new LocalNodeManager({ chainId: 84532, mnemonic: process.env.E2E_TEST_SEED_PHRASE, // Optional: specify a custom port range // portRange: [10000, 20000] }); // Start the node (port is automatically allocated) await nodeManager.start(); // Get the allocated port const port = nodeManager.getPort(); console.log(`Node running on port ${port}`); // Run your test... // Stop the node await nodeManager.stop(); ``` -------------------------------- ### MetaMask Complete Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx A comprehensive configuration for MetaMask, including local node setup, seed phrase, and network details. Exports the configuration for use in e2e tests. ```typescript // e2e/config/metamask.config.ts import { baseSepolia } from "viem/chains" import { configure } from "@coinbase/onchaintestkit" export const DEFAULT_PASSWORD = "PASSWORD" export const DEFAULT_SEED_PHRASE = process.env.E2E_TEST_SEED_PHRASE const config = configure() .withLocalNode({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"), hardfork: "cancun", }) .withMetaMask() .withSeedPhrase({ seedPhrase: DEFAULT_SEED_PHRASE ?? "", password: DEFAULT_PASSWORD, }) .withNetwork({ name: "Base Sepolia", chainId: baseSepolia.id, symbol: "ETH", rpcUrl: "http://localhost:8545", }) .build() export const metamaskWalletConfig = config ``` -------------------------------- ### Comprehensive Coinbase Wallet Test Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/coinbase.mdx A full test example integrating various Coinbase Wallet features: connection, passkey setup, network management, and transaction approval. ```typescript import { createOnchainTest, CoinbaseSpecificActionType, BaseActionType } from '@coinbase/onchaintestkit'; import { configure } from '@coinbase/onchaintestkit'; const config = configure() .withLocalNode({ chainId: 84532, forkUrl: process.env.E2E_TEST_FORK_URL, }) .withCoinbase() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'COMPLEXPASSWORD1', }) .build(); const test = createOnchainTest(config); test('comprehensive Coinbase test', async ({ page, coinbase, node }) => { if (!coinbase) throw new Error('Coinbase fixture is required'); // Navigate to dApp await page.goto('https://app.example.com'); // Connect wallet await page.getByTestId('connect-wallet').click(); await page.getByRole('button', { name: 'Coinbase' }).click(); await coinbase.handleAction(BaseActionType.CONNECT_TO_DAPP); // Setup passkey const [passkeyPopup] = await Promise.all([ page.context().waitForEvent('page'), page.getByTestId('enable-passkey').click(), ]); await coinbase.handleAction(CoinbaseSpecificActionType.HANDLE_PASSKEY_POPUP, { mainPage: page, popup: passkeyPopup, passkeyAction: 'register', passkeyConfig: { name: 'Test Passkey', rpId: 'localhost', rpName: 'Example dApp', userId: 'test-user', isUserVerified: true, }, }); // Add custom network await coinbase.handleAction(CoinbaseSpecificActionType.ADD_NETWORK, { network: { name: 'Local Test Network', rpcUrl: `http://localhost:${node?.port}`, chainId: 84532, symbol: 'ETH', }, }); // Switch to the network await coinbase.handleAction(BaseActionType.SWITCH_NETWORK, { networkName: 'Local Test Network', }); // Perform transaction with passkey approval await page.getByRole('button', { name: 'Send Transaction' }).click(); const [txPopup] = await Promise.all([ page.context().waitForEvent('page'), page.getByRole('button', { name: 'Confirm' }).click(), ]); await coinbase.handleAction(CoinbaseSpecificActionType.HANDLE_PASSKEY_POPUP, { mainPage: page, popup: txPopup, passkeyAction: 'approve', }); // Verify success await expect(page.getByText('Transaction complete')).toBeVisible(); }); ``` -------------------------------- ### Configure MetaMask with Custom Setup Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/metamask.mdx Demonstrates configuring MetaMask with a seed phrase and performing custom actions like importing accounts, adding tokens, and adding networks during the setup phase. ```typescript const metamaskConfig = configure() .withMetaMask() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'PASSWORD', }) .withCustomSetup(async (wallet, context) => { // Import additional accounts await wallet.handleAction(BaseActionType.IMPORT_WALLET_FROM_PRIVATE_KEY, { privateKey: process.env.SECONDARY_PRIVATE_KEY!, }); // Add custom tokens await wallet.handleAction(MetaMaskSpecificActionType.ADD_TOKEN, { tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', tokenSymbol: 'USDC', tokenDecimals: 6, }); // Add custom networks await wallet.handleAction(MetaMaskSpecificActionType.ADD_NETWORK, { network: { name: 'Base Mainnet', rpcUrl: 'https://mainnet.base.org', chainId: 8453, symbol: 'ETH', }, }); }) .build(); ``` -------------------------------- ### Coinbase Wallet Complete Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx A complete configuration for Coinbase Wallet, including local node setup, seed phrase, and network details. Exports the configuration for e2e tests. ```typescript // e2e/config/coinbase.config.ts import { baseSepolia } from "viem/chains" import { configure } from "@coinbase/onchaintestkit" export const DEFAULT_PASSWORD = "COMPLEXPASSWORD1" export const DEFAULT_SEED_PHRASE = process.env.E2E_TEST_SEED_PHRASE const config = configure() .withLocalNode({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"), hardfork: "cancun", }) .withCoinbase() .withSeedPhrase({ seedPhrase: DEFAULT_SEED_PHRASE ?? "", password: DEFAULT_PASSWORD, }) .withNetwork({ name: "Base Sepolia", chainId: baseSepolia.id, symbol: "ETH", rpcUrl: "http://localhost:8545", }) .build() export const coinbaseWalletConfig = config ``` -------------------------------- ### Install Dependencies and Build Contracts with Forge Source: https://github.com/coinbase/onchaintestkit/blob/master/README-SmartContractManager.md Navigates to the smart contracts directory, installs forge-std and openzeppelin-contracts, and builds the contracts. This generates artifacts in the 'out/' directory. ```bash cd example/smart-contracts forge install foundry-rs/forge-std forge install OpenZeppelin/openzeppelin-contracts forge build ``` -------------------------------- ### Run Development Server Source: https://github.com/coinbase/onchaintestkit/blob/master/example/frontend/README.md Start the Next.js development server to view the project locally. ```bash npm run dev # or yarn dev # or pnpm dev # or bun dev ``` -------------------------------- ### Environment Configuration Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Example `.env` file for configuring test wallet seed phrase, optional fork URL and block number, and smart contract project root. ```dotenv E2E_TEST_SEED_PHRASE="test test test test test test test test test test test junk" E2E_TEST_FORK_URL="https://mainnet.base.org" E2E_TEST_FORK_BLOCK_NUMBER="12345678" E2E_CONTRACT_PROJECT_ROOT="../smart-contracts" ``` -------------------------------- ### Complete Wallet Interaction Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/common-actions.mdx A comprehensive example demonstrating a full wallet interaction flow, including connecting to a dApp, switching networks, performing a swap, and handling transaction approvals. Ensure the wallet fixture is available before use. ```typescript import { createOnchainTest, BaseActionType, ActionApprovalType } from '@coinbase/onchaintestkit'; import { metamaskWalletConfig } from './config/metamaskWalletConfig'; const test = createOnchainTest(metamaskWalletConfig); test('complete wallet flow', async ({ page, metamask }) => { if (!metamask) throw new Error('MetaMask fixture is required'); // Connect to dApp await page.getByTestId('ockConnectButton').click(); await page.getByRole('button', { name: 'MetaMask' }).click(); await metamask.handleAction(BaseActionType.CONNECT_TO_DAPP); // Switch network await page.getByTestId('switch-network').click(); await metamask.handleAction(BaseActionType.SWITCH_NETWORK, { networkName: 'Base Sepolia', isTestnet: true }); // Perform swap transaction await page.locator('input[placeholder="0.0"]').fill('0.1'); await page.getByRole('button', { name: 'Swap' }).click(); // Handle spending cap if needed let notificationType = await metamask.identifyNotificationType(); if (notificationType === 'SpendingCap') { await metamask.handleAction(BaseActionType.CHANGE_SPENDING_CAP, { approvalType: ActionApprovalType.APPROVE }); } // Handle transaction notificationType = await metamask.identifyNotificationType(); if (notificationType === 'Transaction') { await metamask.handleAction(BaseActionType.HANDLE_TRANSACTION, { approvalType: ActionApprovalType.APPROVE }); } // Verify success await expect(page.getByRole('link', { name: 'View on Explorer' })).toBeVisible(); }); ``` -------------------------------- ### Install Foundry Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Install Foundry, a blockchain development toolkit, by running the provided curl command and foundryup. ```bash curl -L https://foundry.paradigm.xyz | bash foundryup ``` -------------------------------- ### Install Dependencies Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Install OnchainTestKit and Playwright for testing. Ensure you have Node.js and yarn installed. ```bash yarn add -D @coinbase/onchaintestkit @playwright/test yarn playwright install --with-deps ``` -------------------------------- ### start() Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/api-reference.mdx Starts the Anvil node. This method allocates a port, spawns the Anvil process, and waits for the node to become ready to accept connections. ```APIDOC ## start() ### Description Starts the Anvil node with the configured options. Allocates a port, spawns the process, and waits for readiness. ### Signature ```typescript async start(): Promise ``` ### Usage Example ```typescript const node = new LocalNodeManager() await node.start() console.log(`Node running at ${node.rpcUrl}`) ``` ``` -------------------------------- ### Install OnchainTestKit with Bun Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Use this snippet to install OnchainTestKit and Playwright using Bun. It also includes commands to install Playwright browsers and download wallet extensions. ```bash bun add -D @coinbase/onchaintestkit @playwright/test bunx playwright install --with-deps bun prepare-metamask bun prepare-coinbase ``` -------------------------------- ### Verify Installation Commands Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Run these commands in your terminal to confirm that Node.js, Playwright, and Anvil are installed correctly and to list the installed Playwright browsers. ```bash # Check Node.js node --version # Check Playwright npx playwright --version # Check Anvil anvil --version # List installed browsers npx playwright show-browsers ``` -------------------------------- ### Basic Test Setup with OnchainTestKit Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Demonstrates how to initialize OnchainTestKit with a wallet configuration and use it within a test function. This is the standard entry point for setting up your test environment. ```typescript import { createOnchainTest, } from '@coinbase/onchaintestkit'; import { metamaskWalletConfig } from './config/metamask.config'; const test = createOnchainTest(metamaskWalletConfig); test('my test', async ({ page, metamask, node }) => { // Your test code here console.log(`Local node running on port: ${node?.port}`); }); ``` -------------------------------- ### Install OnchainTestKit with npm Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Use this snippet to install OnchainTestKit and Playwright using npm. It also includes commands to install Playwright browsers and download wallet extensions. ```bash npm install -D @coinbase/onchaintestkit @playwright/test npx playwright install --with-deps npm run prepare-metamask npm run prepare-coinbase ``` -------------------------------- ### MetaMask Basic Setup Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Configures MetaMask wallet with a seed phrase. Ensure the E2E_TEST_SEED_PHRASE environment variable is set. ```typescript import { configure } from '@coinbase/onchaintestkit'; const metamaskConfig = configure() .withMetaMask() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'PASSWORD', }) .build(); ``` -------------------------------- ### Install Dependencies Source: https://github.com/coinbase/onchaintestkit/blob/master/example/frontend/README.md Install project dependencies using your preferred package manager. ```bash npm install # or yarn install # or pnpm install # or bun install ``` -------------------------------- ### Start LocalNodeManager Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/api-reference.mdx Starts the Anvil node, allocating a port, spawning the process, and waiting for readiness. Logs the RPC URL upon successful start. ```typescript const node = new LocalNodeManager() await node.start() console.log(`Node running at ${node.rpcUrl}`) ``` -------------------------------- ### Install Foundry Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Installs Foundry, which is required for running local Anvil nodes. Remember to update your PATH and verify the installation. ```bash curl -L https://foundry.paradigm.xyz | bash source ~/.bashrc anvil --version ``` -------------------------------- ### Configure Wallet with Fluent Builder Pattern Source: https://github.com/coinbase/onchaintestkit/blob/master/README.md Demonstrates the fluent builder pattern for configuring wallets with the Onchain Test Kit. This example shows how to initialize with MetaMask, a seed phrase, and network settings. ```typescript const config = configure() .withMetaMask() .withSeedPhrase({ seedPhrase: 'your seed phrase', password: 'your password', }) .withNetwork({ name: 'Network Name', rpcUrl: 'RPC URL', chainId: 1, symbol: 'ETH', }) .build(); ``` -------------------------------- ### Connect to DApp Action Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/api-reference.mdx Example of handling the basic action to connect a wallet to a DApp. ```typescript await wallet.handleAction(BaseActionType.CONNECT_TO_DAPP); ``` -------------------------------- ### Install OnchainTestKit with Yarn Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx Use this snippet to install OnchainTestKit and Playwright using Yarn. It also includes commands to install Playwright browsers and download wallet extensions. ```bash yarn add -D @coinbase/onchaintestkit @playwright/test yarn playwright install --with-deps yarn prepare-metamask yarn prepare-coinbase ``` -------------------------------- ### Comprehensive MetaMask Test Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/metamask.mdx A full example showcasing various MetaMask functionalities within a test, including adding accounts, networks, tokens, connecting to a dApp, and handling transactions. ```typescript import { createOnchainTest, MetaMaskSpecificActionType, BaseActionType } from '@coinbase/onchaintestkit'; import { configure } from '@coinbase/onchaintestkit'; import { baseSepolia } from "viem/chains" const config = configure() .withLocalNode({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, }) .withMetaMask() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'PASSWORD', }) .withNetwork({ name: "Base Sepolia", chainId: baseSepolia.id, symbol: "ETH", // placeholder for the actual rpcUrl, which is auto injected by the node fixture rpcUrl: "http://localhost:8545", }) .build(); const test = createOnchainTest(config); test('comprehensive MetaMask test', async ({ page, metamask }) => { if (!metamask) throw new Error('MetaMask fixture is required'); // Add accounts await metamask.handleAction(MetaMaskSpecificActionType.ADD_ACCOUNT, { accountName: 'DeFi Account', }); // Add custom network await metamask.handleAction(MetaMaskSpecificActionType.ADD_NETWORK, { network: { name: 'Base Mainnet', rpcUrl: 'https://mainnet.base.org', chainId: 8453, symbol: 'ETH', }, }); // Switch network await metamask.handleAction(BaseActionType.SWITCH_NETWORK, { networkName: 'Base Mainnet', }); // Add tokens await metamask.handleAction(MetaMaskSpecificActionType.ADD_TOKEN, { tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', tokenSymbol: 'USDC', tokenDecimals: 6, }); // Connect to dApp await page.goto('https://app.example.com'); await page.getByTestId('connect-wallet').click(); await page.getByRole('button', { name: 'MetaMask' }).click(); await metamask.handleAction(BaseActionType.CONNECT_TO_DAPP); // Perform transaction await page.getByRole('button', { name: 'Send Transaction' }).click(); await metamask.handleAction(BaseActionType.HANDLE_TRANSACTION, { approvalType: ActionApprovalType.APPROVE, }); }); ``` -------------------------------- ### Build Smart Contracts Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx Install necessary dependencies and build the smart contracts project using Forge. ```bash cd smart-contracts # Install dependencies forge install foundry-rs/forge-std OpenZeppelin/openzeppelin-contracts # Build contracts forge build ``` -------------------------------- ### Complete MetaMask Account Management Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/metamask.mdx A comprehensive test case demonstrating the addition, switching, and removal of accounts in MetaMask using OnchainTestKit. ```typescript test('MetaMask account management', async ({ page, metamask }) => { if (!metamask) throw new Error('MetaMask fixture is required'); // Add a new account await metamask.handleAction(MetaMaskSpecificActionType.ADD_ACCOUNT, { accountName: 'DeFi Account', }); // Add another account await metamask.handleAction(MetaMaskSpecificActionType.ADD_ACCOUNT, { accountName: 'Trading Account', }); // Switch between accounts await metamask.handleAction(MetaMaskSpecificActionType.SWITCH_ACCOUNT, { accountName: 'DeFi Account', }); // Remove an account await metamask.handleAction(MetaMaskSpecificActionType.REMOVE_ACCOUNT, { accountName: 'Trading Account', }); }); ``` -------------------------------- ### WalletSetupContext Interface Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/api-reference.mdx Represents the context provided during the wallet setup process, potentially including details like the local node port. ```typescript interface WalletSetupContext { localNodePort?: number; } ``` -------------------------------- ### Coinbase Wallet Basic Setup Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Configures Coinbase Wallet with a specific seed phrase and password. Ensure E2E_TEST_SEED_PHRASE environment variable is set. ```typescript import { configure } from '@coinbase/onchaintestkit'; const coinbaseConfig = configure() .withCoinbase() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'COMPLEXPASSWORD1', }) .build(); ``` -------------------------------- ### Start and Manage Local Node Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/overview.mdx Initialize a LocalNodeManager, start the Anvil node, and perform basic operations like taking snapshots and reverting states. Ensure to stop the node when done. ```typescript import { LocalNodeManager } from '@coinbase/onchaintestkit' import { baseSepolia } from 'viem/chains' // Create a node manager with automatic port allocation const node = new LocalNodeManager({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"), hardfork: "cancun", }) // Start the node await node.start() console.log(`Node running on port ${node.getPort()}`) // Manipulate chain state const snapshotId = await node.snapshot() // ...run tests... await node.revert(snapshotId) // Clean up await node.stop() ``` -------------------------------- ### Example Test Flow: Passkey Registration and Transaction Approval Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/webauthn-playwright-passkey.md An end-to-end test case demonstrating passkey registration and subsequent transaction approval using the CoinbaseSmartWallet and Playwright. ```typescript test("should register a passkey and complete a transaction", async ({ page, coinbase }) => { const smartWallet = new CoinbaseSmartWallet(coinbase.walletContext, coinbase.walletPage); // Registration const [registrationPopup] = await Promise.all([ page.context().waitForEvent("page"), page.click("#wallet-type-smart"), ]); await smartWallet.registerPasskey(passkeyConfig, registrationPopup); // Transaction approval const [transactionPopup] = await Promise.all([ page.context().waitForEvent("page"), page.locator('[data-testid="ockTransactionButton_Button"]').click(), ]); await smartWallet.approveTransactionWithPasskey(transactionPopup); // Assert success await expect(page.getByTestId("ockToast").getByText("Successful")).toBeVisible({ timeout: 30000 }); }); ``` -------------------------------- ### Complete Passkey Flow with Coinbase Wallet Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/coinbase.mdx A comprehensive example demonstrating the full passkey flow in Coinbase Wallet, including connecting the wallet, registering a passkey, and approving a transaction using the passkey. ```typescript test('complete passkey flow', async ({ page, coinbase }) => { if (!coinbase) throw new Error('Coinbase fixture is required'); // Connect wallet await page.getByTestId('connect-wallet').click(); await page.getByRole('button', { name: 'Coinbase' }).click(); await coinbase.handleAction(BaseActionType.CONNECT_TO_DAPP); // Register passkey const [registerPopup] = await Promise.all([ page.context().waitForEvent('page'), page.getByTestId('setup-passkey').click(), ]); await coinbase.handleAction(CoinbaseSpecificActionType.HANDLE_PASSKEY_POPUP, { mainPage: page, popup: registerPopup, passkeyAction: 'register', passkeyConfig: { name: 'Test Passkey', rpId: 'localhost', rpName: 'Test dApp', userId: 'user-' + Date.now(), isUserVerified: true, }, }); // Use passkey for transaction await page.getByRole('button', { name: 'Send ETH' }).click(); const [txPopup] = await Promise.all([ page.context().waitForEvent('page'), page.getByRole('button', { name: 'Confirm' }).click(), ]); await coinbase.handleAction(CoinbaseSpecificActionType.HANDLE_PASSKEY_POPUP, { mainPage: page, popup: txPopup, passkeyAction: 'approve', }); // Verify transaction success await expect(page.getByText('Transaction successful')).toBeVisible(); }); ``` -------------------------------- ### Switch Network Action Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/api-reference.mdx Example of handling the action to switch the wallet to a different network, specifying the network name and if it's a testnet. ```typescript await wallet.handleAction(BaseActionType.SWITCH_NETWORK, { networkName: 'Base Sepolia', isTestnet: true }); ``` -------------------------------- ### Add Token Action for MetaMask Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/api-reference.mdx Example of using MetaMask-specific actions to add a token to the wallet. Requires token address, symbol, and decimals. ```typescript await metamask.handleAction(MetaMaskSpecificActionType.ADD_TOKEN, { tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', tokenSymbol: 'USDC', tokenDecimals: 6 }); ``` -------------------------------- ### Handle Passkey Popup for Coinbase Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/api-reference.mdx Example of handling a passkey-related popup in Coinbase Wallet, specifying the action, page elements, and passkey configuration. ```typescript await coinbase.handleAction(CoinbaseSpecificActionType.HANDLE_PASSKEY_POPUP, { mainPage: page, popup: popup, passkeyAction: 'register', passkeyConfig: { name: 'Test Passkey', rpId: 'localhost', rpName: 'My dApp', userId: 'user123', isUserVerified: true } }); ``` -------------------------------- ### Configure MetaMask Wallet with Seed Phrase and Network Source: https://github.com/coinbase/onchaintestkit/blob/master/README.md Configure a MetaMask wallet using the onchaintestkit's configure builder. This example sets up a wallet with a seed phrase and connects it to the Base Sepolia network. ```typescript // walletConfig/metamaskWalletConfig.ts import { configure } from 'e2e/onchainTestKit'; import { baseSepolia } from 'viem/chains'; export const DEFAULT_PASSWORD = 'PASSWORD'; export const DEFAULT_SEED_PHRASE = process.env.E2E_TEST_SEED_PHRASE; export const metamaskWalletConfig = configure() .withMetaMask() .withSeedPhrase({ seedPhrase: DEFAULT_SEED_PHRASE ?? '', password: DEFAULT_PASSWORD, }) .withNetwork({ name: baseSepolia.name, rpcUrl: baseSepolia.rpcUrls.default.http[0], chainId: baseSepolia.id, symbol: baseSepolia.nativeCurrency.symbol, }) .build(); ``` -------------------------------- ### Typed Configuration with OnchainTestKit Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Shows how to export typed configurations for wallet setups, enhancing IDE support and preventing type-related errors. This involves importing `OnchainTestConfig` and using a builder pattern. ```typescript import type { OnchainTestConfig } from '@coinbase/onchaintestkit'; export const metamaskConfig: OnchainTestConfig = configure() .withMetaMask() // ... rest of config .build(); ``` -------------------------------- ### Add Multiple Tokens to MetaMask Example Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/metamask.mdx Demonstrates how to add multiple ERC-20 tokens, such as USDC and DAI, to MetaMask within a single test case. ```typescript test('add multiple tokens', async ({ page, metamask }) => { // Add USDC await metamask.handleAction(MetaMaskSpecificActionType.ADD_TOKEN, { tokenAddress: '0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48', tokenSymbol: 'USDC', tokenDecimals: 6, }); // Add DAI await metamask.handleAction(MetaMaskSpecificActionType.ADD_TOKEN, { tokenAddress: '0x6B175474E89094C44Da98b954EedeAC495271d0F', tokenSymbol: 'DAI', tokenDecimals: 18, }); }); ``` -------------------------------- ### Deploy and Test Contract with Fixture Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx Example of using the `smartContractManager` fixture within a test to interact with deployed contracts. ```typescript test("deploy and test contract", async ({ page, metamask, smartContractManager, node }) => { // Contract deployment and testing }) ``` -------------------------------- ### setContractState() Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/contracts/smart-contract-manager.mdx Deploys contracts and executes calls as specified in a setup config. This is useful for setting up complex test scenarios. ```APIDOC ## setContractState(config: SetupConfig, node: LocalNodeManager) ### Description Deploys contracts and executes calls as specified in a setup config. This is useful for setting up complex test scenarios. ### Parameters #### Path Parameters - **config** (SetupConfig) - Required - Setup configuration with deployments and calls - **node** (LocalNodeManager) - Required - The local node manager instance ### Returns - **Promise** ``` -------------------------------- ### Create Foundry Project Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx Set up a new smart contracts project using Foundry. ```bash mkdir smart-contracts && cd smart-contracts forge init ``` -------------------------------- ### GitHub Actions Workflow for E2E Tests Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/ci-cd.mdx This YAML file defines a GitHub Actions workflow to run End-to-End (E2E) tests. It checks out code, sets up Node.js and Yarn, installs dependencies including Foundry, builds contracts, prepares wallet extensions, builds the application, and finally runs the E2E tests using xvfb-run. ```yaml name: E2E Tests on: push: branches: [main, develop] pull_request: branches: [main] jobs: e2e: runs-on: ubuntu-latest timeout-minutes: 30 steps: - name: Checkout code uses: actions/checkout@v4 - name: Setup Node.js uses: actions/setup-node@v4 with: node-version: '18' cache: 'npm' - name: Set up Corepack + yarn run: | npm install -g corepack yarn set version 4.9.2 - name: Install root dependencies run: yarn - name: Install Foundry uses: foundry-rs/foundry-toolchain@v1 - name: Build contracts run: | cd smart-contracts forge install foundry-rs/forge-std forge install OpenZeppelin/openzeppelin-contracts forge build - name: Install Playwright browsers run: yarn playwright install --with-deps - name: Prepare wallet extensions run: | yarn prepare-metamask yarn prepare-coinbase - name: Build application run: | echo "E2E_TEST_SEED_PHRASE=${{ secrets.E2E_TEST_SEED_PHRASE }}" > .env echo "E2E_CONTRACT_PROJECT_ROOT=../smart-contracts" >> .env yarn build - name: Install xvfb run: sudo apt-get update && sudo apt-get install -y xvfb - name: Run E2E tests env: NODE_OPTIONS: '--dns-result-order=ipv4first' run: xvfb-run --auto-servernum --server-args="-screen 0 1920x1080x24" yarn test:e2e ``` -------------------------------- ### SmartContractManager setContractState() Method Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/contracts/smart-contract-manager.mdx Deploys contracts and executes calls based on a setup configuration. Useful for complex test scenarios. Requires SetupConfig and LocalNodeManager. ```typescript async setContractState( config: SetupConfig, node: LocalNodeManager ): Promise ``` -------------------------------- ### Get Allocated Port Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/api-reference.mdx Retrieves the allocated port number for the running node instance. Returns null if the node has not been started. ```typescript const port = node.getPort() // Use port for configuration ``` -------------------------------- ### MetaMask With Local Node Configuration Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Configures MetaMask with a local node, including fork options and a specific network setup. Requires E2E_TEST_SEED_PHRASE and E2E_TEST_FORK_URL environment variables. ```typescript import { baseSepolia } from 'viem/chains'; const metamaskConfig = configure() .withLocalNode({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"), hardfork: 'cancun', }) .withMetaMask() .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'PASSWORD', }) .withNetwork({ name: 'Base Sepolia', chainId: baseSepolia.id, symbol: 'ETH', rpcUrl: 'http://localhost:8545', }) .build(); ``` -------------------------------- ### Test Both Successful and Failing Contract Interactions Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx This example illustrates the best practice of testing both successful and failing contract interactions. It sets up a describe block for token minting and includes placeholders for testing both a successful mint by the owner and a failed mint attempt by a non-owner. ```typescript test.describe("Token minting", () => { test("owner can mint", async ({ /* ... */ }) => { // Test successful mint }) test("non-owner cannot mint", async ({ /* ... */ }) => { // Test revert }) }) ``` -------------------------------- ### Download Wallet Extensions Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Prepare the necessary wallet extensions for testing by running the prepare commands for MetaMask and Coinbase Wallet. ```bash # Download MetaMask yarn prepare-metamask # Download Coinbase Wallet yarn prepare-coinbase ``` -------------------------------- ### Basic Configuration Builder Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Sets up a local node, MetaMask wallet, a custom network, and a seed phrase for testing. ```typescript import { configure } from '@coinbase/onchaintestkit'; const config = configure() .withLocalNode({ chainId: 1337 }) .withMetaMask() .withNetwork({ name: 'Base Sepolia', rpcUrl: 'http://localhost:8545', chainId: 84532, symbol: 'ETH', }) .withSeedPhrase({ seedPhrase: process.env.E2E_TEST_SEED_PHRASE!, password: 'PASSWORD', }) .build(); ``` -------------------------------- ### SmartContractManager initialize() Method Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/contracts/smart-contract-manager.mdx Initializes viem clients and deploys the proxy. Must be called before other methods. Requires a LocalNodeManager instance. ```typescript async initialize(node: LocalNodeManager): Promise ``` -------------------------------- ### initialize() Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/contracts/smart-contract-manager.mdx Initializes viem clients and ensures the proxy is deployed. This method must be called before using other methods of the SmartContractManager. ```APIDOC ## initialize(node: LocalNodeManager) ### Description Initializes viem clients and ensures the proxy is deployed. Must be called before using other methods. ### Parameters #### Path Parameters - **node** (LocalNodeManager) - Required - The local node manager instance ### Returns - **Promise** ``` -------------------------------- ### Create Environment Variables Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Set up your project's environment variables by creating a .env file. Use a test seed phrase for security. ```dotenv # Test wallet seed phrase (NEVER use production wallets!) E2E_TEST_SEED_PHRASE="test test test test test test test test test test test junk ``` -------------------------------- ### Playwright Configuration File Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/installation.mdx This TypeScript file configures Playwright for end-to-end testing. It includes environment variable loading, base URL setup, test project configurations for different browsers, and web server setup. ```typescript import { defineConfig, devices } from "@playwright/test" require("dotenv").config({ path: "./.env" }) /** * Read environment variables from file. * https://github.com/motdotla/dotenv */ // Use process.env.PORT by default and fallback to port 4000 const PORT = process.env.PORT || 4000 // Set webServer.url and use.baseURL with the location of the WebServer respecting the correct set port const baseURL = `http://localhost:${PORT}` /** * See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ timeout: 120000, testDir: "./e2e", /* Run tests in files in parallel */ fullyParallel: false, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 3 : 0, /* Opt into parallel tests on CI. */ workers: 10, maxFailures: 3, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: "line", /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: "on-first-retry", }, /* Configure projects for major browsers */ projects: [ { name: "chromium", use: { ...devices["Desktop Chrome"] }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, // { // name: 'webkit', // use: { ...devices['Desktop Safari'] }, // }, /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', // use: { ...devices['Pixel 5'] }, // }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, // }, /* Test against branded browsers. */ // { // name: 'Microsoft Edge', // use: { ...devices['Desktop Edge'], channel: 'msedge' }, // }, // { // name: 'Google Chrome', // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, // }, ], // Run your local dev server before starting the tests: // https://playwright.dev/docs/test-advanced#launching-a-development-web-server-during-the-tests webServer: { command: "yarn start -p 4000", url: baseURL, timeout: 30 * 1000, reuseExistingServer: !process.env.CI, }, }) ``` -------------------------------- ### Get Available Accounts Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/api-reference.mdx Retrieves a list of all account addresses managed by the node. ```typescript const accounts = await node.getAccounts() console.log(`Available accounts: ${accounts.length}`) ``` -------------------------------- ### Organizing Wallet Configurations Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/configuration.mdx Illustrates a recommended directory structure for separating wallet configuration files. This promotes modularity and maintainability in your test suite. ```bash e2e/config/ ├── metamask.config.ts ├── coinbase.config.ts └── shared.config.ts ``` -------------------------------- ### getPort() Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/node/api-reference.mdx Retrieves the allocated port number for the running node instance. Returns null if the node has not been started. ```APIDOC ## getPort() ### Description Returns the allocated port number for this node instance, or `null` if not started. ### Signature ```typescript getPort(): number | null ``` ### Usage Example ```typescript const port = node.getPort() // Use port for configuration ``` ``` -------------------------------- ### Lock Coinbase Wallet Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/wallets/coinbase.mdx Example of locking the Coinbase Wallet, typically used to secure the wallet after operations. ```typescript await coinbase.handleAction(CoinbaseSpecificActionType.LOCK); ``` -------------------------------- ### Create First Test File Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Create a new test file (e.g., e2e/connectWallet.spec.ts) and import necessary OnchainTestKit modules and chains. ```typescript import { createOnchainTest } from "@coinbase/onchaintestkit" import { configure } from "@coinbase/onchaintestkit" import { baseSepolia } from "viem/chains" // Configure MetaMask const config = configure() .withLocalNode({ chainId: baseSepolia.id, forkUrl: process.env.E2E_TEST_FORK_URL, // This can be mainnet or testnet sepolia url forkBlockNumber: BigInt(process.env.E2E_TEST_FORK_BLOCK_NUMBER ?? "0"), hardfork: "cancun", }) .withMetaMask() .withSeedPhrase({ seedPhrase: DEFAULT_SEED_PHRASE ?? "", password: DEFAULT_PASSWORD, }) // Add the network with the actual port in a custom setup .withNetwork({ name: "Base Sepolia", chainId: baseSepolia.id, symbol: "ETH", // placeholder for the actual rpcUrl, which is auto injected by the node fixture rpcUrl: "http://localhost:8545", }) .build() // Create test with configuration const test = createOnchainTest(config) test.describe("Wallet Connection", () => { test("should connect to MetaMask", async ({ page, metamask }) => { if (!metamask) throw new Error("MetaMask not initialized") await page.getByTestId('ockConnectButton').first().click(); console.log('[connectWallet] Wallet connect modal opened'); // Select MetaMask from wallet options await page .getByTestId('ockModalOverlay') .first() .getByRole('button', { name: 'MetaMask' }) .click(); console.log('[connectWallet] MetaMask option clicked'); // Handle MetaMask connection request await metamask.handleAction(BaseActionType.CONNECT_TO_DAPP); console.log('[connectWallet] MetaMask handleAction finished, URL after connect:', page.url()); }) }) ``` -------------------------------- ### Configure Environment Variable Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx Add the path to your smart contracts project to your .env file. ```bash # Path to your smart contracts E2E_CONTRACT_PROJECT_ROOT=../smart-contracts ``` -------------------------------- ### Get Proxy Address Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/contracts/proxy-deployer.mdx Returns the address of the deterministic deployment proxy. The address is fixed across all EVM-compatible chains. ```typescript const proxyAddress = proxyDeployer.getProxyAddress(); console.log(`Proxy deployed at: ${proxyAddress}`); ``` -------------------------------- ### PasskeyAuthenticator API Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/webauthn-playwright-passkey.md Provides low-level control over the virtual authenticator, including setup, credential management, and simulation of WebAuthn operations. ```APIDOC ## Class: PasskeyAuthenticator ### Description Manages the low-level virtual authenticator setup, credential management, and simulation of WebAuthn operations within a Playwright page context. ### Methods - **`constructor(page: Page)`** Initializes the authenticator with a given Playwright page. - **`setPage(page: Page): Promise`** Switches the authenticator to operate on a new Playwright page, typically a popup. - **Parameters**: - `page` (Page) - The new Playwright page to associate with the authenticator. - **`initialize(options?: VirtualAuthenticatorOptions): Promise`** Sets up a new virtual authenticator in the current page context. - **Parameters**: - `options` (VirtualAuthenticatorOptions) - Optional configuration for the virtual authenticator. - **`simulateSuccessfulPasskeyInput(operationTrigger: () => Promise): Promise`** Simulates a successful passkey operation (registration or authentication). It listens for WebAuthn events and triggers the user action. - **Parameters**: - `operationTrigger` (() => Promise) - A function that initiates the WebAuthn operation. - **`exportCredentials(): Promise`** Exports all credentials currently stored in the virtual authenticator. - **Returns**: - `Promise` - An array of exported WebAuthn credentials. - **`importCredential(cred: WebAuthnCredential): Promise`** Imports a given credential into the current virtual authenticator. - **Parameters**: - `cred` (WebAuthnCredential) - The WebAuthn credential to import. - **`getCredentials(): Promise`** Retrieves all credentials currently managed by the authenticator. - **Returns**: - `Promise` - An array of WebAuthn credentials. ``` -------------------------------- ### Connect Wallet and Deploy Contract via UI Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/smart-contracts.mdx This snippet demonstrates connecting a wallet (MetaMask) to an application and interacting with a deployed smart contract through the UI. It includes deploying a 'SimpleToken' contract and handling the MetaMask connection flow. ```typescript test("should connect wallet and interact with deployed contract", async ({ page, metamask, smartContractManager, node, }) => { if (!metamask) { throw new Error("MetaMask is not defined") } // Deploy contract first const salt = "0x0000000000000000000000000000000000000000000000000000000000000006" as Hex const deployer = "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266" as Address const tokenAddress = await smartContractManager.deployContract({ name: "SimpleToken", args: [], salt, deployer, }) // Connect wallet to the app await page.getByTestId("ockConnectButton").first().click() await page .getByTestId("ockModalOverlay") .first() .getByRole("button", { name: "MetaMask" }) .click() // Handle MetaMask connection await metamask.handleAction(BaseActionType.CONNECT_TO_DAPP) // Verify wallet is connected await page.waitForSelector("text=/0x[a-fA-F0-9]{4}.*[a-fA-F0-9]{4}/", { timeout: 10000, }) // Now the user could interact with the deployed contract through the UI console.log(`User can now interact with token at: ${tokenAddress}`) }) ``` -------------------------------- ### Increase Test Timeout Source: https://github.com/coinbase/onchaintestkit/blob/master/docs/quickstart.mdx Adjust the test timeout in your Playwright configuration if tests are timing out. This example sets the timeout to 60 seconds. ```typescript test.setTimeout(60000) // 60 seconds ```