Skip to Content
Welcome to RitoSwap's documentation!
dAppPlaywrightCustom Wallet Harness

Custom Wallet Harness

The dapp never talks to a real browser wallet during tests. Instead, dapp/e2e/playwright/wallet injects a purpose-built provider that can:

  • Mimic EIP-1193 behaviour (connect, switch chains, send transactions, emit events).
  • Persist the connection across reloads or reset it between specs.
  • Bridge to Node-side viem clients for true Sepolia transactions when a private key is present.

Key files

FilePurpose
wallet/test-setup.tsMain helper that specs call. Clears storage, configures persistence, exposes signing RPC bridges, and injects the provider bundle before the app boots.
wallet/provider.tsWraps Playwright’s page.addInitScript to seed window.__TEST_WALLET_CONFIG and load the bundled provider.
wallet/injected/provider.tsBrowser-side provider implementation: request handler, connection state, pending tx tracking, event emitters, synthetic receipts (mock mode), and EIP-6963 announcements.
wallet/build-helper.tsRuns an esbuild bundle when needed (injected/provider.ts → injected-provider.js). Automatically invoked by setupTest.
utils/wallet.utils.tsHigh-level utilities that flows/tests use to click connect buttons, assert connection state, preview WalletConnect QR codes, etc.

setupTest() lifecycle

1. Storage strategy

Clears wagmi/localStorage keys unless persistConnection is enabled. When persistence is on, the script only wipes non-test wallet keys the first time to simulate how users stay connected after reloads.

2. Bridge wiring

If walletConfig.privateKey exists, setupTest creates publicClient and walletClient via viem, then exposes __testwallet_rpc, __testwallet_sendTransaction, __testwallet_signMessage, and __testwallet_signTypedData to the page. Otherwise, mock mode is used.

3. Provider injection

ensureInjectedBuilt() compiles wallet/injected/provider.ts (when stale) and injectWallet() seeds the runtime config + bundle before any app script evaluates. This guarantees that wagmi detects the provider on first render.

4. Diagnostics helpers

The helper subscribes to page.on('console') and page.on('pageerror'), printing anything that contains [Test Wallet], [REAL], [BRIDGE], wagmi, or error. The returned object exposes waitForProvider(), waitForAccounts(), debugWalletState(), and disconnectWallet() so specs can orchestrate complex flows.

Provider behaviour

  • Transactions are stored in _pendingTxs and mined after txDelay.
  • Mint/Burn detection relies on method selectors (0x1249c58b, 0x42966c68) and toggles an in-memory NFT state so the UI can react instantly.
  • Receipts/logs are generated with deterministic hashes, block numbers, and Transfer topics that match ERC-721 expectations.
  • personal_sign / eth_signTypedData return zeroed signatures unless you opt into deterministic signing via utils/signing.utils.ts.
  • Persisted connections rely on localStorage[‘testwallet.connected’]. When persistConnection is true, eth_accounts automatically returns the cached address after reloads.

Working with WalletTestUtils

utils/wallet.utils.ts abstracts the repetitive UI work:

  • connectWallet(walletName?) finds the connect button (header, hero CTA, or modal) and completes the flow.
  • openConnectModal() accounts for already-open dialogs and retries after reload.
  • waitForQrVisible() + previewWalletConnectQr() exercise the WalletConnect branch.
  • isMobileWidth() helps specs skip QR assertions on small viewports.
  • disconnectWallet() ensures the UI returns to the “Connect Wallet” state when needed.

Pair these helpers with setupTest() for deterministic sequences. Example:

const setup = await setupTest(page, { clearStorage: true, injectWallet: true, persistConnection: true, walletConfig: walletConfigFromEnv, }); await page.goto('/swap', { waitUntil: 'networkidle' }); await setup.waitForWagmi(); const wallet = new WalletTestUtils(page); await wallet.connectWallet('Test Wallet');
⚠️

Never re-use a private key from mainnet. Real-mode specs mint and burn NFTs on Sepolia, and failures will leave the mock wallet in an inconsistent state if the account lacks gas.

With the wallet harness understood, continue to the mocks page to learn how AI and portfolio data are intercepted during tests.

RitoSwap Docs does not store, collect or access any of your conversations. All saved prompts are stored locally in your browser only.