diff --git a/packages/use-wallet/src/__tests__/wallets/pera.test.ts b/packages/use-wallet/src/__tests__/wallets/pera.test.ts index cb865555..e6e1d6cf 100644 --- a/packages/use-wallet/src/__tests__/wallets/pera.test.ts +++ b/packages/use-wallet/src/__tests__/wallets/pera.test.ts @@ -451,6 +451,79 @@ describe('PeraWallet', () => { expect(store.state.wallets[WalletId.PERA]).toBeUndefined() expect(wallet.isConnected).toBe(false) }) + + describe('auto-connect in Pera browser', () => { + let mockUserAgent: string + + beforeEach(() => { + mockUserAgent = '' + vi.clearAllMocks() + + vi.stubGlobal('window', { + navigator: { + get userAgent() { + return mockUserAgent + } + } + }) + }) + + afterEach(() => { + vi.unstubAllGlobals() + }) + + it('should attempt auto-connect in Pera browser when no session exists and no active wallet', async () => { + mockUserAgent = 'pera/1.0.0' + mockPeraWallet.connect.mockResolvedValueOnce([account1.address]) + + await wallet.resumeSession() + + expect(mockPeraWallet.connect).toHaveBeenCalled() + expect(store.state.wallets[WalletId.PERA]).toBeDefined() + expect(mockLogger.info).toHaveBeenCalledWith('Auto-connect successful') + }) + + it('should not attempt auto-connect if another wallet is active', async () => { + mockUserAgent = 'pera/1.0.0' + + // Set up another active wallet + store.setState((state) => ({ + ...state, + activeWallet: WalletId.DEFLY, + wallets: { + [WalletId.DEFLY]: { + accounts: [account2], + activeAccount: account2 + } + } + })) + + await wallet.resumeSession() + + expect(mockPeraWallet.connect).not.toHaveBeenCalled() + expect(mockLogger.info).toHaveBeenCalledWith('No session to resume') + }) + + it('should not attempt auto-connect in other browsers', async () => { + mockUserAgent = 'chrome/1.0.0' + + await wallet.resumeSession() + + expect(mockPeraWallet.connect).not.toHaveBeenCalled() + expect(mockLogger.info).toHaveBeenCalledWith('No session to resume') + }) + + it('should handle auto-connect failure gracefully', async () => { + mockUserAgent = 'pera/1.0.0' + mockPeraWallet.connect.mockRejectedValueOnce(new Error('Connect failed')) + + await wallet.resumeSession() + + expect(mockPeraWallet.connect).toHaveBeenCalled() + expect(mockLogger.warn).toHaveBeenCalledWith('Auto-connect failed:', 'Connect failed') + expect(store.state.wallets[WalletId.PERA]).toBeUndefined() + }) + }) }) describe('setActive', () => { @@ -541,53 +614,6 @@ describe('PeraWallet', () => { }) }) - describe('autoConnect', () => { - let mockUserAgent: string - - beforeEach(() => { - mockUserAgent = '' - vi.clearAllMocks() - - vi.stubGlobal('window', { - navigator: { - get userAgent() { - return mockUserAgent - } - } - }) - }) - - afterEach(() => { - vi.unstubAllGlobals() - }) - - it('should attempt auto-connect in Pera browser', () => { - mockUserAgent = 'pera/1.0.0' - - // Mock the private method before creating the wallet - vi.spyOn(PeraWallet.prototype as any, 'autoConnect') - .mockReset() - .mockImplementation(() => Promise.resolve()) - - createWalletWithStore(store) - - expect(PeraWallet.prototype['autoConnect']).toHaveBeenCalled() - }) - - it('should not attempt auto-connect in other browsers', () => { - mockUserAgent = 'chrome/1.0.0' - - // Mock the private method before creating the wallet - vi.spyOn(PeraWallet.prototype as any, 'autoConnect') - .mockReset() - .mockImplementation(() => Promise.resolve()) - - createWalletWithStore(store) - - expect(PeraWallet.prototype['autoConnect']).not.toHaveBeenCalled() - }) - }) - describe('signing transactions', () => { // Connected accounts const connectedAcct1 = '7ZUECA7HFLZTXENRV24SHLU4AVPUTMTTDUFUBNBD64C73F3UHRTHAIOF6Q' diff --git a/packages/use-wallet/src/__tests__/wallets/pera2.test.ts b/packages/use-wallet/src/__tests__/wallets/pera2.test.ts index 4d20b6a3..67a2a526 100644 --- a/packages/use-wallet/src/__tests__/wallets/pera2.test.ts +++ b/packages/use-wallet/src/__tests__/wallets/pera2.test.ts @@ -332,52 +332,78 @@ describe('PeraWallet', () => { expect(store.state.wallets[WalletId.PERA2]).toBeUndefined() expect(wallet.isConnected).toBe(false) }) - }) - describe('autoConnect', () => { - let mockUserAgent: string + describe('auto-connect in Pera browser', () => { + let mockUserAgent: string - beforeEach(() => { - mockUserAgent = '' - vi.clearAllMocks() + beforeEach(() => { + mockUserAgent = '' + vi.clearAllMocks() - vi.stubGlobal('window', { - navigator: { - get userAgent() { - return mockUserAgent + vi.stubGlobal('window', { + navigator: { + get userAgent() { + return mockUserAgent + } } - } + }) }) - }) - afterEach(() => { - vi.unstubAllGlobals() - }) + afterEach(() => { + vi.unstubAllGlobals() + }) - it('should attempt auto-connect in Pera browser', () => { - mockUserAgent = 'pera/1.0.0' + it('should attempt auto-connect in Pera browser when no session exists and no active wallet', async () => { + mockUserAgent = 'pera/1.0.0' + mockPeraWallet.connect.mockResolvedValueOnce([account1.address]) - // Mock the private method before creating the wallet - vi.spyOn(PeraWallet.prototype as any, 'autoConnect') - .mockReset() - .mockImplementation(() => Promise.resolve()) + await wallet.resumeSession() - createWalletWithStore(store) + expect(mockPeraWallet.connect).toHaveBeenCalled() + expect(store.state.wallets[WalletId.PERA2]).toBeDefined() + expect(mockLogger.info).toHaveBeenCalledWith('Auto-connect successful') + }) - expect(PeraWallet.prototype['autoConnect']).toHaveBeenCalled() - }) + it('should not attempt auto-connect if another wallet is active', async () => { + mockUserAgent = 'pera/1.0.0' + + // Set up another active wallet + store.setState((state) => ({ + ...state, + activeWallet: WalletId.DEFLY, + wallets: { + [WalletId.DEFLY]: { + accounts: [account2], + activeAccount: account2 + } + } + })) - it('should not attempt auto-connect in other browsers', () => { - mockUserAgent = 'chrome/1.0.0' + await wallet.resumeSession() - // Mock the private method before creating the wallet - vi.spyOn(PeraWallet.prototype as any, 'autoConnect') - .mockReset() - .mockImplementation(() => Promise.resolve()) + expect(mockPeraWallet.connect).not.toHaveBeenCalled() + expect(mockLogger.info).toHaveBeenCalledWith('No session to resume') + }) + + it('should not attempt auto-connect in other browsers', async () => { + mockUserAgent = 'chrome/1.0.0' - createWalletWithStore(store) + await wallet.resumeSession() + + expect(mockPeraWallet.connect).not.toHaveBeenCalled() + expect(mockLogger.info).toHaveBeenCalledWith('No session to resume') + }) - expect(PeraWallet.prototype['autoConnect']).not.toHaveBeenCalled() + it('should handle auto-connect failure gracefully', async () => { + mockUserAgent = 'pera/1.0.0' + mockPeraWallet.connect.mockRejectedValueOnce(new Error('Connect failed')) + + await wallet.resumeSession() + + expect(mockPeraWallet.connect).toHaveBeenCalled() + expect(mockLogger.warn).toHaveBeenCalledWith('Auto-connect failed:', 'Connect failed') + expect(store.state.wallets[WalletId.PERA2]).toBeUndefined() + }) }) }) diff --git a/packages/use-wallet/src/wallets/pera.ts b/packages/use-wallet/src/wallets/pera.ts index f650f530..dea4d13f 100644 --- a/packages/use-wallet/src/wallets/pera.ts +++ b/packages/use-wallet/src/wallets/pera.ts @@ -44,13 +44,6 @@ export class PeraWallet extends BaseWallet { super({ id, metadata, getAlgodClient, store, subscribe, networks }) this.options = options this.store = store - - if (typeof window !== 'undefined' && window.navigator) { - const isPeraDiscover = window.navigator.userAgent.includes('pera') - if (isPeraDiscover) { - void this.autoConnect() - } - } } static defaultMetadata = { @@ -154,6 +147,21 @@ export class PeraWallet extends BaseWallet { const state = this.store.state const walletState = state.wallets[this.id] + // Check for Pera Discover browser and auto-connect if no other wallet is active + if (typeof window !== 'undefined' && window.navigator) { + const isPeraDiscover = window.navigator.userAgent.includes('pera') + if (isPeraDiscover && !walletState && !state.activeWallet) { + this.logger.info('Pera Discover browser detected, attempting auto-connect...') + try { + await this.connect() + this.logger.info('Auto-connect successful') + return + } catch (error: any) { + this.logger.warn('Auto-connect failed:', error.message) + } + } + } + // No session to resume if (!walletState) { this.logger.info('No session to resume') diff --git a/packages/use-wallet/src/wallets/pera2.ts b/packages/use-wallet/src/wallets/pera2.ts index 05a35928..9e7a94d3 100644 --- a/packages/use-wallet/src/wallets/pera2.ts +++ b/packages/use-wallet/src/wallets/pera2.ts @@ -53,13 +53,6 @@ export class PeraWallet extends BaseWallet { } this.options = options this.store = store - - if (typeof window !== 'undefined' && window.navigator) { - const isPeraDiscover = window.navigator.userAgent.includes('pera') - if (isPeraDiscover) { - void this.autoConnect() - } - } } static defaultMetadata = { @@ -67,16 +60,6 @@ export class PeraWallet extends BaseWallet { icon: ICON } - private async autoConnect(): Promise { - this.logger.info('Pera Discover browser detected, auto connecting...') - try { - await this.connect() - this.logger.info('Auto-connect successful') - } catch (error: any) { - this.logger.warn('Auto-connect failed:', error.message) - } - } - private async initializeClient(): Promise { this.logger.info('Initializing client...') const module = await import('@perawallet/connect-beta') @@ -136,6 +119,21 @@ export class PeraWallet extends BaseWallet { const state = this.store.state const walletState = state.wallets[this.id] + // Check for Pera Discover browser and auto-connect if no other wallet is active + if (typeof window !== 'undefined' && window.navigator) { + const isPeraDiscover = window.navigator.userAgent.includes('pera') + if (isPeraDiscover && !walletState && !state.activeWallet) { + this.logger.info('Pera Discover browser detected, attempting auto-connect...') + try { + await this.connect() + this.logger.info('Auto-connect successful') + return + } catch (error: any) { + this.logger.warn('Auto-connect failed:', error.message) + } + } + } + // No session to resume if (!walletState) { this.logger.info('No session to resume')