Files
c486bd38a5 tests(mobile): E2E pairing and session approval for WalletConnect dApps (#8200)
* tests(mobile): add shared createE2eStore factory for e2e singletons

Collapse the duplicated get/set/reset/subscribe + listeners machinery into one
tested factory and adopt it in the Signer-side walletConnectE2eState. The
Wallet-side store reuses it too (added in a later commit).

* fix(mobile): expose WalletConnect proposal sheet to accessibility

@gorhom/bottom-sheet defaults its container to accessible={true}, which
collapses the proposal/request sheet into a single iOS accessibility element
and hides its children from VoiceOver (and Maestro). Set accessible={false} to
expose them, matching the other sheets in the app.

* tests(mobile): add WalletConnect dApp pairing e2e harness

App-side scaffolding to drive WalletConnect dApp pairing/approval
deterministically under Maestro (no live relay):

- walletKitE2eState singleton + fake WalletKit (walletKit.e2e.ts) that replaces
  relay calls (pair/approveSession/rejectSession) and reflects approved sessions
  via getActiveSessions so the controller can't clobber the slice.
- useHasFeature.e2e.ts force-enables NATIVE_WALLETCONNECT when armed, via a
  subscription so consumers re-render on the flag flip.
- E2eScanInjector feeds a wc: URI into the real scanner onScan handler
  (Maestro can't drive the camera); prod variant is a no-op.
- walletConnectDappsSetup synth fns + fixtures, exposed via hidden TestCtrls
  buttons and a reject side-channel marker.
- Extract a shared onboardAndNavigate + TEST_WALLET_ICON into the setup helpers
  and adopt them in connectSignerSetup (de-duplication).

* tests(mobile): add WalletConnect dApp pairing Maestro flows

Seven flows under e2e/tests/walletconnect-dapps/ covering scan happy / invalid /
timeout, deep-link pairing, proposal reject, and the unverified + scam verify
variants, plus JSON fixtures and a README documenting the test-id side-channels
and the iOS accessibility gotchas that shaped the flows.

* tests(mobile): drop unused WC dApp fixture JSON

The JSON files were never imported — the typed factory in walletConnectDappsSetup
(buildProposal) is the canonical fixture source, so the JSON would only drift.

* tests(mobile): harden fake WalletKit and relocate the session fixture

- Default unimplemented fake WalletKit methods to a resolved no-op via a Proxy,
  guarding `then`/symbols so the fake isn't mistaken for a thenable.
- Type APPROVED_SESSION and buildProposal as literals (drop `as` casts) so
  upstream WC type changes fail at compile instead of at runtime.
- Move APPROVED_SESSION next to the fake (walletKit.e2e.ts) and share the
  session topic via walletKitE2eState, removing the feature->test import.
- Reset proposalSeq per flow in setupWcDappsBase.

* docs(mobile): clarify e2e store immutability and proposal-sheet a11y comments

Note that createE2eStore state must be updated via set() (shallow-cloned initial),
and that RequestSheetHost's accessible={false} matches the app's other sheets.

* tests(mobile): dedup pairing-topic literal and copy getActiveSessions result

- Export E2E_PAIRING_TOPIC from walletKitE2eState and use it on both sides
  (APPROVED_SESSION + buildProposal) so the shared topic can't drift.
- getActiveSessions() returns a spread copy, matching the real SDK and so a
  caller mutating the result can't corrupt the singleton.
- Assert the Proxy symbol guard (Symbol.iterator/asyncIterator read as undefined).

* tests(mobile): deep-clone createE2eStore initial state to enforce reset

reset() (and init) now restore a deep clone of the initial state, so a scenario
that mutated even a nested value can't leak into the next flow — turning the
documented contract into behaviour a regression test enforces.

* tests(mobile): freeze APPROVED_SESSION and use the session-topic constant in tests

- Deeply freeze APPROVED_SESSION so a caller mutating a nested field (it shares
  the ref getActiveSessions hands out) can't corrupt the singleton; inline the
  fake self.metadata so freezing doesn't touch the shared SAFE_WALLET_METADATA.
- Use E2E_SESSION_TOPIC in the synthSessionDelete test instead of a raw literal.
- Note the Proxy SDK-drift trade-off for future @reown/walletkit bumps.

* docs(e2e): remove README for WalletConnect dApps

---------

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-13 19:01:10 +02:00

34 lines
1004 B
YAML

appId: ${APP_ID}
tags:
- walletconnect-dapps
---
# Deep link: a wc:// link is opened while the app runs → WalletKitController pairs
# it (fake resolves) → synthesise the proposal → proposal sheet opens WITHOUT the
# scanner ever being mounted.
- runFlow:
file: ../../utils/setup/app-start.yml
- tapOn:
id: 'e2eWcDappsBase'
- assertVisible:
id: 'home-tab'
# Open a wc: deep link — handled by WalletKitController's Linking listener, not the scanner.
- openLink:
link: 'wc:e2e-deeplink@2?relay-protocol=irn'
# Synthesise the proposal the relay would deliver after pairing.
- tapOn:
id: 'e2eWcSynthProposalValid'
# Proposal sheet opens (anchor on the Connect button id — sheet text nodes are
# merged into one grouped accessibility label).
- extendedWaitUntil:
visible:
id: 'wc-proposal-connect'
timeout: 10000
# The scanner was never mounted — its footer copy is absent.
- assertNotVisible: 'Scan an Ethereum wallet address or connect to a desktop app'