mirror of
https://github.com/luxfi/safe-wallet.git
synced 2026-10-30 15:19:21 +00:00
* refactor(mobile): extract findCollidingSigner pure helper Move the matching predicate out of useSignerCollisionGuard and into apps/mobile/src/features/ImportSigner/utils/findCollidingSigner.ts so the e2e WalletConnect mock and the production hook can share one implementation. The hook becomes a thin wrapper over the helper plus Alert.alert dispatch. Address comparison uses `sameAddress` from @safe-global/utils — case- insensitive equality consistent with the rest of the mobile WC code. The Map-based normalisation in the previous hook is dropped (signer lists are <10 entries; the hook is called at most once per import). Existing useSignerCollisionGuard.test.ts continues to pass without modification. * refactor(mobile): share WalletConnectContextValue across real + e2e providers Move the context interface to apps/mobile/src/features/WalletConnect/ context/types.ts so both WalletConnectContext.tsx and WalletConnectContext.e2e.tsx import the same contract. Drift between the two providers is now a TypeScript error rather than a runtime crash. The migration surfaced two latent type mismatches that the contract now prevents: - walletConnectE2eState.chainId was typed `number | undefined` but `useAccount.chainId` is `string | undefined`. Nothing read the field, so the bug was latent. Corrected. - The e2e mock's `sign` was typed `(unknown) => Promise<unknown>` instead of `(SignParams) => Promise<SigningResponse>`. Retyped via `useCallback<WalletConnectContextValue['sign']>(…)` so the contract drives the signature. * refactor(mobile): add resetE2EState reset boundary for e2e tests Introduce a top-level `resetE2EState` action that every e2e-relevant slice handles via `extraReducers` by returning its initialState: signersSlice, activeSignerSlice, safesSlice, activeSafeSlice, executionMethodSlice, estimatedFeeSlice, notificationsSlice. Setup helpers now call a single `resetReduxForE2E(dispatch)` helper that dispatches the action AND resets `walletConnectE2eState`. The existing four connectSignerSetup helpers migrate from the bare `walletConnectE2eState.reset()` to the unified entrypoint. settingsSlice intentionally NOT reset — `onboardingVersionSeen` must persist for setup paths that skip `setupBaseConfig`. * feat(mobile): extend WC e2e mock with reconnect-mismatch + collision branches walletConnectE2eState gains a single-shot `reconnectMismatch` flag and field-grouping comments separating scenario directives from session state. WalletConnectContext.e2e.tsx mock now mirrors two production behaviours: - `reconnect(addr)` — when reconnectMismatch is true, routes to /import-signers/reconnect-error AND clears the flag so a follow-up retry succeeds. Mirrors useReconnectFlow on address mismatch. - `initiateConnection()` — after the isOwner check, calls findCollidingSigner (the shared helper landed in Phase 1A). On a type-mismatched collision: Alert.alert + clear session state + return without navigation. Mirrors useImportSignerFlow's guardAgainstCollision branch. Both branches use the shared findCollidingSigner helper so logic drift between mock and prod is caught at compile time. * tests(mobile): add TestCtrls helpers for reconnect-mismatch + collision Two new setup helpers + e2e<PascalCase> TestCtrls triggers: - setupWcGateReconnectWrongWallet / e2eWcGateReconnectWrongWallet: delegates to setupWcGateBase with `reconnectMismatch: true` so the next reconnect routes to ReconnectError before the single-shot flag clears. - setupConnectSignerCollision / e2eConnectSignerCollision: pre-seeds a private-key signer at OWNER_ADDRESS and configures the WC mock to return the same address. The mock's collision branch fires Alert.alert + clears the WC session, mirroring useImportSignerFlow's guardAgainstCollision via the shared findCollidingSigner helper. The signer-selection setup (Notion #19/#20) is deferred — it needs a real testnet Safe with 2 owners + pending tx with empty confirmations that doesn't exist yet. To be addressed in a follow-up round. * tests(mobile): harden Try-again retry assertion in connect-signer-not-owner The retry tap calls router.dismiss() before initiateConnection re-runs. Without an animation wait, the next assertion can race the dismiss and flake intermittently. Add waitForAnimationToEnd + extendedWaitUntil notVisible on connect-signer-error so the test waits for the screen transition before asserting the Name screen. Notion #6 (Try-again recovery) was already covered by PR #7676 — this is robustness only. * tests(mobile): add reconnect-wrong-wallet e2e flow Exercises useReconnectFlow's address-mismatch path → ReconnectError screen → retry. Drives the new single-shot reconnectMismatch flag end to end: setup (flag=true) → tap reconnect → mock routes to /import-signers/reconnect-error, clears flag → tap "Connect a different wallet" → router.dismiss() + reconnect retries → flag cleared so retry succeeds → gate dismisses First test to reach ReconnectError + reconnect-error-done testIDs. Outside Notion's documented cases — extra coverage for production code that previously had only the happy reconnect path tested. * tests(mobile): add connect-signer-collision e2e flow First test in the repo to assert against and dismiss a native iOS Alert.alert. Setup pre-seeds a private-key signer at OWNER_ADDRESS, then triggers a WC connect flow that returns the same address — the type mismatch fires findCollidingSigner via the e2e mock's collision branch, which mirrors useImportSignerFlow's guardAgainstCollision. The test asserts: 1. The native alert "Signer already imported" appears 2. Tapping "OK" dismisses it 3. The flow does NOT advance to Name your signer (collision bailed) Same-type re-imports are intentionally NOT covered — findCollidingSigner returns null for them (silent overwrite per production behavior). Closes Notion #7. iOS-only — Android native dialog handling differs and is out of scope for this round. * tests(mobile): wire collision + reconnect-wrong-wallet into suite, drop ordering Three updates: - __suite__.yml — add connect-signer-collision and reconnect-wrong-wallet to the suite. Tags trimmed to `connect-signer` + `suite` (narrow tags live on per-test files, so --include-tags filtering works as intended). Order is presentation-only: every setup helper now calls resetReduxForE2E so tests are independent. - plan — record post-implementation reality: Phase 5A was already shipped by PR #7676 (this round added robustness only); Phase 5D / signer-selection deferred (extractAppSigners reads from CGW's on-chain owner list, not Redux SafeOverview, so a synthetic Safe fixture won't surface a tx); R1 (native iOS Alert.alert) closed by simulator verification. - brainstorm — same updates for future readers. * refactor(mobile): apply WC e2e code-review findings (todos 027-038) Resolves 8 todos surfaced by the code review on tests/wa-1858-wc-coverage-extensions: P1: - 027 — Extract showCollisionAlert to a shared util (apps/mobile/src/features/ImportSigner/utils/showCollisionAlert.ts). The e2e mock and useSignerCollisionGuard now share one source of truth for the alert title + body — drift impossible. - 028 — resetReduxForE2E now also dispatches resetApiState() on cgwClient, hypernativeApi, and web3API. Closes the cache-leak vector via safesSlice.addMatcher. - 029 — Add `wc-gate` tag to reconnect-wrong-wallet.yml so --include-tags wc-gate filtering picks it up. P2: - 031 — settingsSlice now selectively resets on resetE2EState — preserves onboardingVersionSeen, resets everything else. Per-test theme/currency/ RPC overrides no longer leak across the suite. - 032 — Each WC hook now exports a named return type (ImportSignerFlowResult, ReconnectFlowResult, SwitchNetworkResult, WalletConnectSigningResult). types.ts imports those instead of using `Pick<ReturnType<typeof useX>>`. Same compile-time guarantee, narrower dependency footprint. - 034 — Extracted clearSession helper in WalletConnectContext.e2e.tsx so the collision branch + disconnect callback share one implementation. reconnect mismatch branch now also calls clearSession before routing to ReconnectError, mirroring useReconnectFlow's production semantics. - 035 — extraReducers in notificationsSlice / signersSlice / safesSlice / activeSignerSlice now return fresh objects on reset rather than the module-level initialState reference. Defensive against future in-place mutation. P3: - 038 — Trimmed verbose comment preambles in connect-signer-collision.yml and reconnect-wrong-wallet.yml. Doc retention decision deferred. Verification: - yarn workspace @safe-global/mobile type-check ✓ - yarn workspace @safe-global/mobile lint ✓ - yarn workspace @safe-global/mobile prettier ✓ - jest (9 suites / 103 tests) ✓ - maestro suite (6/6 child tests) ✓ * refactor(mobile): hoist resetE2EState handling to root reducer Wrap the combined reducer with `withE2EReset` so every slice resets to its `initialState` automatically. Slices that need custom reset behavior (only settingsSlice, which preserves `onboardingVersionSeen`) keep their own `extraReducers` — the wrapper detects which slices changed in response to the action and preserves those values. Drops the boilerplate `extraReducers` from signers, activeSigner, safes, activeSafe, estimatedFee, executionMethod, and notifications slices. New slices are now covered by the e2e reset automatically; opt-in is only needed for selective-reset cases. * fix(mobile): ensure chains are re-fetched after redux reset in e2e tests Updated the `resetReduxForE2E` function to dispatch a re-fetch for chains configuration immediately after resetting the Redux state. This change prevents `selectActiveChain` from returning `undefined`, ensuring that the `WalletConnectGate` correctly identifies the active signer during the pending transaction flow. This addresses potential issues with the execution method fallback and improves the reliability of the e2e tests. * fix(mobile): prevent opening explorer link if block explorer URI is not defined Added a check in the `viewOnExplorer` function to ensure that the `activeChain` has a valid `blockExplorerUriTemplate` before attempting to generate and open the explorer link. This prevents potential errors when the URI is undefined. --------- Co-authored-by: Daniel Dimitrov <[email protected]>