From 5911c201d9ea14771e1cfd2a1b923b345af14ca1 Mon Sep 17 00:00:00 2001 From: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> Date: Wed, 26 Aug 2026 19:22:47 +0530 Subject: [PATCH] fix(frontend): remove unsafe non-null assertion on WalletConnect publicKey with proper null handling Replace publicKey! with a null guard, fallback label, and dev-mode console.warn so a connected state without a key cannot crash render. Fixes #274 Signed-off-by: Vedant Madane <6527493+VedantMadane@users.noreply.github.com> --- frontend/package-lock.json | 4 +- frontend/package.json | 2 +- .../src/components/WalletConnect.test.tsx | 75 +++++++++++++++++++ frontend/src/components/WalletConnect.tsx | 66 +++++++++------- 4 files changed, 116 insertions(+), 31 deletions(-) create mode 100644 frontend/src/components/WalletConnect.test.tsx diff --git a/frontend/package-lock.json b/frontend/package-lock.json index c5d53d3..4bfbf01 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -1,12 +1,12 @@ { "name": "frontend", - "version": "0.1.0", + "version": "0.1.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "frontend", - "version": "0.1.0", + "version": "0.1.1", "dependencies": { "@stellar/freighter-api": "^6.0.1", "@stellar/stellar-sdk": "^16.0.1", diff --git a/frontend/package.json b/frontend/package.json index a9ee43b..a4440c4 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "frontend", "private": true, - "version": "0.1.0", + "version": "0.1.1", "type": "module", "scripts": { "dev": "vite", diff --git a/frontend/src/components/WalletConnect.test.tsx b/frontend/src/components/WalletConnect.test.tsx new file mode 100644 index 0000000..0f0d24a --- /dev/null +++ b/frontend/src/components/WalletConnect.test.tsx @@ -0,0 +1,75 @@ +import { render, screen } from '@testing-library/react' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +import WalletConnect from './WalletConnect' +import { useWallet } from '../context/WalletContext' + +vi.mock('../context/WalletContext', () => ({ + useWallet: vi.fn(), +})) + +const mockUseWallet = vi.mocked(useWallet) + +const baseWallet = { + wrongNetwork: false, + connecting: false, + error: null as string | null, + connect: vi.fn(), + disconnect: vi.fn(), + recheckInstall: vi.fn(), + clearError: vi.fn(), + connected: false, +} + +describe('', () => { + beforeEach(() => { + vi.clearAllMocks() + }) + + it('renders truncated publicKey when connected', () => { + mockUseWallet.mockReturnValue({ + ...baseWallet, + status: 'connected', + publicKey: 'GABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890ABCDEFGHIJKLMNOP', + connected: true, + }) + + render() + + expect(screen.getByText('GABC...MNOP')).toBeInTheDocument() + expect( + screen.getByRole('button', { name: /Disconnect wallet GABC\.\.\.MNOP/i }), + ).toBeInTheDocument() + }) + + it('does not crash when connected with null publicKey and shows fallback', () => { + const warn = vi.spyOn(console, 'warn').mockImplementation(() => {}) + + mockUseWallet.mockReturnValue({ + ...baseWallet, + status: 'connected', + publicKey: null, + connected: true, + }) + + render() + + expect(screen.getByText('Address unavailable')).toBeInTheDocument() + expect(screen.getByRole('button', { name: 'Disconnect wallet' })).toBeInTheDocument() + expect(screen.queryByText(/\.\.\./)).not.toBeInTheDocument() + + warn.mockRestore() + }) + + it('renders connect button when disconnected', () => { + mockUseWallet.mockReturnValue({ + ...baseWallet, + status: 'disconnected', + publicKey: null, + }) + + render() + + expect(screen.getByRole('button', { name: 'Connect Wallet' })).toBeInTheDocument() + }) +}) diff --git a/frontend/src/components/WalletConnect.tsx b/frontend/src/components/WalletConnect.tsx index 81c5caa..e4509ec 100644 --- a/frontend/src/components/WalletConnect.tsx +++ b/frontend/src/components/WalletConnect.tsx @@ -62,39 +62,49 @@ export default function WalletConnect() { ); } + // Connected: guard against unexpected missing publicKey (avoids runtime crash from !) + if (!publicKey) { + if (import.meta.env.DEV) { + console.warn( + '[WalletConnect] status is connected but publicKey is null/undefined', + ); + } + return ( +
+ {wrongNetwork && ( + Switch to Testnet + )} + + Address unavailable + + +
+ ); + } + return (
{wrongNetwork && ( Switch to Testnet )} - {publicKey ? ( - <> - - {truncateAddress(publicKey)} - - - - ) : ( - <> - {import.meta.env.DEV && console.warn('[WalletConnect] Connected status but publicKey is null/undefined — unexpected state')} - Wallet key unavailable - - - )} + + {truncateAddress(publicKey)} + +
); }