ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

wagmi Solid:mock Connector 详解——用模拟钱包测试连接、签名与错误分支

2026/9/17 21:12:39 拓冰建站 浏览量
wagmi Solid:mock Connector 详解——用模拟钱包测试连接、签名与错误分支 wagmi Solidmock Connector 详解——用模拟钱包测试连接、签名与错误分支【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi本文基于 wagmi 仓库的 solid mock connector 文档 展开系统讲解wagmi/solid中mockConnector 的导入方式、MockParameters参数accounts与各类features功能开关、典型配置示例并结合 核心实现源码 剖析其 RPC 请求拦截、错误注入与多链切换的底层机制帮助你在没有真实钱包的环境单元测试、CI、开发联调中完整验证钱包连接、签名与断连等代码路径。一、mock Connector 的定位wagmi 的 Connector 是连接 Web3 钱包的统一抽象每个 Connector 实现connect、disconnect、getAccounts、getChainId、getProvider、isAuthorized、switchChain等接口接口约定见 createConnector.ts。真实钱包MetaMask、WalletConnect 等在测试环境中无法被驱动它们依赖浏览器扩展弹窗、用户点击授权等交互。mockConnector 正是为此而生——按官方文档的定义它是一个用于模拟mockWagmi 行为的 Connector用你提供的一组固定账户地址响应eth_accounts/eth_requestAccounts模拟用户已授权钱包的状态通过features功能开关可人为触发连接失败、签名失败、切换链失败等错误分支从而测试 UI 对UserRejectedRequestError等异常的处理逻辑签名类请求与交易类请求会被转发到真实 RPC 端点下文源码章节详述因此配合测试网可跑通真实链上流程。mock实现在wagmi/core中经由wagmi/connectors再导出wagmi/solid的./connectors导出入口同样透传了这两个符号见 connectors 导出索引 与 solid 导出索引。二、导入与基础用法2.1 导入import { mock } from wagmi/solid/connectors如需引用参数类型import { type MockParameters } from wagmi/solid/connectors2.2 在 createConfig 中使用文档给出的标准用法——为每条链配置http()transport并将mock加入connectors数组import { createConfig, http } from wagmi/solid import { mainnet, sepolia } from wagmi/solid/chains import { mock } from wagmi/solid/connectors export const config createConfig({ chains: [mainnet, sepolia], connectors: [ mock({ accounts: [ 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0x70997970c51812dc3a010c7d01b50e0d17dc79c8, 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC, ], }), ], transports: { [mainnet.id]: http(), [sepolia.id]: http(), }, })要点accounts是MockParameters中唯一的必填项且类型为readonly [Address, ...Address[]]至少一个地址connectors数组中可以同时放置多个不同accounts的mock实例。仓库内部测试配置正是这样做的——注册了两个使用不同账户集合的 mock用于模拟多钱包并存的场景见 测试配置 与 solid 包测试夹具测试账户可任意指定。仓库测试夹具中的 10 个测试地址由固定助记词派生constants.ts你可以在自己的测试中使用同类做法保证地址可复现。三、MockParameters 参数详解3.1 accountsreadonly [Address, ...Address[]]—— Connector 将返回的账户列表。无论调用connect()还是查询getAccounts()mock 都返回这组地址。完整示例节选文档中的 10 账户版本import { mock } from wagmi/solid/connectors const connector mock({ accounts: [ 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0x70997970c51812dc3a010c7d01b50e0d17dc79c8, 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC, 0x90F79bf6EB2c4f870365E785982E1f101E93b906, 0x15d34aaf54267db7d7c367839aaf71a00a2c6a65, 0x9965507D1a55bcC2695C58ba16FB37d819B0A4dc, 0x976EA74026E726554dB657fA54763abd0C3a0aa9, 0x14dC79964da2C08b23698B3D3cc7Ca32193d9955, 0x23618e81E3f5cdF7f54C3d65f7FBc0aBf5B21E8f, 0xa0Ee7A142d267C1f36714E4a8F75612F20a79720, ], })3.2 featuresfeatures是一组改变 Wagmi 内部行为的功能开关取值类型为{ defaultConnected?: boolean | undefined connectError?: boolean | Error | undefined reconnect?: boolean | undefined signMessageError?: boolean | Error | undefined signTypedDataError?: boolean | undefined switchChainError?: boolean | Error | undefined watchAssetError?: boolean | Error | undefined // 源码额外支持见下文 } | undefined其中错误类开关遵循统一的二态语义填true时抛出默认的UserRejectedRequestError模拟用户拒绝填一个Error实例时原样抛出该实例方便测试任意自定义错误。参数类型作用defaultConnectedbooleanConnector 是否默认处于已连接状态默认为falseconnectErrorboolean \| Error调用connector.connect时是否抛出错误reconnectboolean是否允许重新连接影响isAuthorized()的返回值signMessageErrorboolean \| Error调用personal_sign时是否抛出错误signTypedDataErrorboolean \| Error调用eth_signTypedData_v4时是否抛出错误switchChainErrorboolean \| Error调用connector.switchChain时是否抛出错误watchAssetErrorboolean \| Error调用wallet_watchAsset时是否抛出错误源码类型中存在官方参数页未单列示例文档原例演示connectError传自定义错误 关闭reconnectimport { mock } from wagmi/solid/connectors import { UserRejectedRequestError } from viem const connector mock({ accounts: [ 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266, 0x70997970c51812dc3a010c7d01b50e0d17dc79c8, 0x3C44CdDdB6a900fa2b585dd299e03d12FA4293BC, ], features: { connectError: new UserRejectedRequestError(new Error(Failed to connect.)), reconnect: false, }, })注意文档参数章节的features类型签名中还包含defaultConnected其语义是——设为true后connect()之前 Connector 就视作已连接getAccounts()不会抛ConnectorNotConnectedError。四、源码级实现剖析mock的全部逻辑集中在 packages/core/src/connectors/mock.ts约 340 行通过createConnector工厂创建id: mock、name: Mock Connector、type: mock。4.1 状态初始化与 setup// mock.ts 节选 let connected features.defaultConnected let connectedChainId: number return createConnectorProvider, Properties((config) ({ id: mock, name: Mock Connector, type: mock.type, async setup() { connectedChainId config.chains[0].id // 初始链 配置中的第一条链 }, ... }))从源码结构看mock 的内部状态极简——两个闭包变量connected布尔和connectedChainId当前链 ID初始链固定为config.chains[0]。getChainId()最终就是读取这个值eth_chainId被本地拦截见 4.2。4.2 getProvider一个带拦截逻辑的 EIP-1193 ProvidergetProvider()返回一个基于 viemcustom()transport 的 Provider其request函数mock.ts L164-L334按方法名分层处理请求本地拦截模拟层eth_chainId→ 返回当前connectedChainId的 hex不访问网络eth_accounts/eth_requestAccounts→ 直接返回parameters.accounts模拟用户授权eth_signTypedData_v4→ 若设置了features.signTypedDataError则抛出true时默认错误信息为Failed to sign typed data.否则放行到真实 RPCpersonal_sign→ 若设置了features.signMessageError则抛出否则把方法改写为eth_sign并交换参数顺序personal_sign的[data, address]→eth_sign的[address, data]随后走真实 RPC 端点签名/广播。钱包命名空间方法wallet_switchEthereumChain→ 若设置了features.switchChainError则抛出否则更新内部connectedChainId并触发onChainChanged事件通知 Wagmi 层更新链状态wallet_watchAsset→ 受features.watchAssetError控制成功时返回当前connected状态wallet_getCapabilities→ 返回针对特定链 ID0x2105、0x14A34与特定 paymaster 地址的固定能力描述paymasterService/sessionKeys用于测试能力发现逻辑wallet_sendCalls→ 将批量调用逐条通过eth_sendTransaction发送到链的默认 HTTP RPC收集回执哈希并以keccak256(JSON.stringify(calls))作为 ID 存入内存transactionCache返回{ id }wallet_getCallsStatus→ 用上述 ID 从缓存取出哈希逐条调用eth_getTransactionReceipt组装WalletCallReceipt列表返回status: 200有回执或status: 100无记录/空回执的WalletGetCallsStatusReturnType。兜底转发以上均未命中的方法含改写后的eth_sign统一通过 viem 的rpc.http(url)发往该链rpcUrls.default.http[0]RPC 错误包装为RpcRequestError抛出。Provider 以retryCount: 0创建不做重试。这意味着mock 并非纯内存假钱包——账号、连接状态、事件是模拟的但签名与交易类请求最终会打到真实 RPC。因此要完整跑通签名/转账流程accounts中应使用有测试网资金的账户例如本地 Anvil/Hardhat 的默认账户并保证transports指向可用的节点。4.3 switchChain 与事件switchChain({ chainId })的实现mock.ts L133-L143先在config.chains中查找目标链找不到即抛SwitchChainError(new ChainNotConfiguredError())找到则向 Provider 发wallet_switchEthereumChain由 4.2 的拦截逻辑完成状态更新与事件广播。connect({ chainId })也会先比对当前链不一致时自动走一次switchChain。事件回调方面onAccountsChanged收到空数组时触发onDisconnect()否则发出change事件onChainChanged发出带chainId的change事件onDisconnect发出disconnect事件并复位connected。这些事件经config.emitter广播驱动上层 primitives如useConnection的状态更新。4.4 isAuthorized 与 reconnect// mock.ts L127-L132 async isAuthorized() { if (!features.reconnect) return false if (!connected) return false const accounts await this.getAccounts() return !!accounts.length }reconnect开关是isAuthorized()的总闸不显式开启时页面刷新后不会自动恢复连接。仓库测试对这一行为有直接断言——配置defaultConnected: truereconnect: true后isAuthorized()解析为truemock.test.ts L135-L146。4.5 类型层withCapabilities 与扩展参数从 createConnector 的接口定义 与 mock 的Properties泛型参数可以看到connect({ withCapabilities: true })时返回的accounts会从纯地址数组变为{ address, capabilities }对象数组——mock 为此注入了占位能力capabilities: { foo: { bar: address } }mock.ts L49-L72mock.test.ts中的类型测试expectTypeOf验证了这一契约。源码注释TODO(v3)表明 v3 计划将withCapabilities: true设为默认行为当前版本需显式传参。五、测试用例如何验证这些行为mock.test.ts 是理解各features开关实际效果的最佳参考资料connectErrorfeatures: { connectError: true }时connector.connect()被拒绝内联快照断言错误为[UserRejectedRequestError: User rejected the request. Details: Failed to connect.]签名/切链/添加代币错误分别设置signMessageError、signTypedDataError、switchChainError、watchAssetError为true后对 Provider 发起personal_sign、eth_signTypedData_v4、wallet_switchEthereumChain、wallet_watchAsset请求均断言抛出带对应 Details 的UserRejectedRequestErrormock.test.ts L71-L133。一个源码细节watchAssetError为true时的默认错误信息是Failed to switch chain.见 mock.ts L193-L200测试快照与源码一致。withCapabilitiesconnect({ withCapabilities: true })的返回类型与结构均有断言mock.test.ts L39-L56。此外mock在整个 monorepo 的测试基建中被高频使用core 的connect/disconnect/reconnect/switchChain/signMessage等 action 测试、solid 的useConnectors/useReconnect/useConnectionEffect等 primitives 测试、以及 vue 与 react 包的对应测试都以mock({ accounts })作为统一的假钱包如 core reconnect 测试、solid useReconnect 测试。这说明 mock 不仅是给下游用户用的工具也是 wagmi 自身跨框架行为一致性的验证基石。六、实战建议与适用边界结合文档与源码使用 mock 的典型场景与注意事项单元测试断连/重连 UI配合defaultConnected: truereconnect: true可直接断言刷新后自动恢复连接的交互无需真实钱包错误分支覆盖features的每个*Error开关对应一条 UI 需要处理的失败路径连接拒绝、签名拒绝、切链失败是编写try/catch分支测试用例的错误注入器多账户/多钱包场景在connectors数组中放置多个mock实例不同accounts模拟用户浏览器安装多个钱包、切换活动账户的场景适用边界mock 依赖配置中的链与transports提供的 RPC 端点完成签名/交易类请求离线环境下这类调用会失败其wallet_getCapabilities返回的是针对特定链 ID 的硬编码能力数据只用于验证能力发现逻辑不代表真实钱包能力reconnect默认关闭若测试刷新恢复连接行为务必显式开启文档参数页未单列的watchAssetError由源码类型与实现确认存在mock.ts L37但属于较少文档化的能力升级大版本前建议以当前仓库源码为准核对。七、相关资源导航资源路径Solid mock connector 文档页site/solid/api/connectors/mock.md共享文档源各框架复用site/shared/connectors/mock.mdmock 核心实现packages/core/src/connectors/mock.tsmock 行为测试packages/core/src/connectors/mock.test.tsConnector 接口约定packages/core/src/connectors/createConnector.tsSolid connectors 导出packages/solid/src/exports/index.tsconnectors 包导出透传 mock/MockParameterspackages/connectors/src/exports/index.ts测试配置双 mock 实例示例packages/test/src/config.ts适用版本说明本文基于当前仓库的wagmi/solid0.0.34见 packages/solid/package.json与wagmi/core源码mock的具体行为尤其是withCapabilities的默认值、能力发现格式可能随 v3 演进变化建议以所在版本的 mock 实现 为准。【免费下载链接】wagmiReactive primitives for Ethereum apps项目地址: https://gitcode.com/GitHub_Trending/wa/wagmi创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考