Skip to content

Commit e25e797

Browse files
authored
Fix: MWA Select but No Connect Bug (anza-xyz#1049)
* init fix + fix tests * fix mwa disconnect + tests * add changeset
1 parent 3761cd8 commit e25e797

File tree

3 files changed

+20
-51
lines changed

3 files changed

+20
-51
lines changed

.changeset/silly-bananas-repeat.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@solana/wallet-adapter-react': patch
3+
---
4+
5+
Update the default MWA selection behavior

packages/core/react/src/WalletProvider.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,7 @@ export function WalletProvider({
7676
}
7777
return [mobileWalletAdapter, ...adaptersWithStandardAdapters];
7878
}, [adaptersWithStandardAdapters, mobileWalletAdapter]);
79-
const [walletName, setWalletName] = useLocalStorage<WalletName | null>(
80-
localStorageKey,
81-
getIsMobile(adaptersWithStandardAdapters) ? SolanaMobileWalletAdapterWalletName : null
82-
);
79+
const [walletName, setWalletName] = useLocalStorage<WalletName | null>(localStorageKey, null);
8380
const adapter = useMemo(
8481
() => adaptersWithMobileWalletAdapter.find((a) => a.name === walletName) ?? null,
8582
[adaptersWithMobileWalletAdapter, walletName]
@@ -105,8 +102,6 @@ export function WalletProvider({
105102
if (!adapter) return;
106103
function handleDisconnect() {
107104
if (isUnloadingRef.current) return;
108-
// Leave the adapter selected in the event of a disconnection.
109-
if (walletName === SolanaMobileWalletAdapterWalletName && getIsMobile(adaptersWithStandardAdapters)) return;
110105
setWalletName(null);
111106
}
112107
adapter.on('disconnect', handleDisconnect);
@@ -150,7 +145,7 @@ export function WalletProvider({
150145
};
151146
}, [adaptersWithStandardAdapters, walletName]);
152147
const handleConnectError = useCallback(() => {
153-
if (adapter && adapter.name !== SolanaMobileWalletAdapterWalletName) {
148+
if (adapter) {
154149
// If any error happens while connecting, unset the adapter.
155150
changeWallet(null);
156151
}

packages/core/react/src/__tests__/WalletProviderMobile-test.tsx

Lines changed: 13 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import {
1212
} from '@solana-mobile/wallet-adapter-mobile';
1313
import {
1414
type Adapter,
15-
BaseWalletAdapter,
1615
WalletError,
1716
type WalletName,
1817
WalletReadyState,
@@ -25,6 +24,7 @@ import { act } from 'react-dom/test-utils';
2524
import { useConnection } from '../useConnection.js';
2625
import { useWallet, type WalletContextState } from '../useWallet.js';
2726
import { WalletProvider, type WalletProviderProps } from '../WalletProvider.js';
27+
import { MockWalletAdapter } from '../__mocks__/MockWalletAdapter.js';
2828

2929
jest.mock('../getEnvironment.js', () => ({
3030
...jest.requireActual('../getEnvironment.js'),
@@ -90,36 +90,6 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
9090
});
9191
}
9292

93-
abstract class MockWalletAdapter extends BaseWalletAdapter {
94-
connectedValue = false;
95-
get connected() {
96-
return this.connectedValue;
97-
}
98-
readyStateValue: WalletReadyState = WalletReadyState.Installed;
99-
get readyState() {
100-
return this.readyStateValue;
101-
}
102-
connecting = false;
103-
connect = jest.fn(async () => {
104-
this.connecting = true;
105-
this.connecting = false;
106-
this.connectedValue = true;
107-
act(() => {
108-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
109-
this.emit('connect', this.publicKey!);
110-
});
111-
});
112-
disconnect = jest.fn(async () => {
113-
this.connecting = false;
114-
this.connectedValue = false;
115-
act(() => {
116-
this.emit('disconnect');
117-
});
118-
});
119-
sendTransaction = jest.fn();
120-
supportedTransactionVersions = null;
121-
autoConnect = jest.fn();
122-
}
12393
class FooWalletAdapter extends MockWalletAdapter {
12494
name = 'FooWallet' as WalletName<'FooWallet'>;
12595
url = 'https://foowallet.com';
@@ -201,7 +171,6 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
201171
expect(jest.mocked(SolanaMobileWalletAdapter).mock.calls[0][0].cluster).toBe('fake-cluster-for-test');
202172
});
203173
});
204-
205174
describe('when a custom mobile wallet adapter is supplied in the adapters array', () => {
206175
let customAdapter: Adapter;
207176
const CUSTOM_APP_IDENTITY = {
@@ -219,9 +188,9 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
219188
adapters.push(customAdapter);
220189
jest.clearAllMocks();
221190
});
222-
it('loads the custom mobile wallet adapter into state as the default', () => {
191+
it('does not load the custom mobile wallet adapter into state as the default', () => {
223192
renderTest({});
224-
expect(ref.current?.getWalletContextState().wallet?.adapter).toBe(customAdapter);
193+
expect(ref.current?.getWalletContextState().wallet?.adapter).not.toBe(customAdapter);
225194
});
226195
it('does not construct any further mobile wallet adapters', () => {
227196
renderTest({});
@@ -230,11 +199,11 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
230199
});
231200
describe('when there exists no stored wallet name', () => {
232201
beforeEach(() => {
233-
localStorage.removeItem(WALLET_NAME_CACHE_KEY);
202+
(localStorage.getItem as jest.Mock).mockReturnValue(null);
234203
});
235-
it('loads the mobile wallet adapter into state as the default', () => {
204+
it('loads no wallet into state', () => {
236205
renderTest({});
237-
expect(ref.current?.getWalletContextState().wallet?.adapter.name).toBe(SolanaMobileWalletAdapterWalletName);
206+
expect(ref.current?.getWalletContextState().wallet).toBeNull();
238207
});
239208
it('loads no public key into state', () => {
240209
renderTest({});
@@ -243,7 +212,7 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
243212
});
244213
describe('when there exists a stored wallet name', () => {
245214
beforeEach(() => {
246-
localStorage.setItem(WALLET_NAME_CACHE_KEY, JSON.stringify('FooWallet'));
215+
(localStorage.getItem as jest.Mock).mockReturnValue(JSON.stringify('FooWallet'));
247216
});
248217
it('loads the corresponding adapter into state', () => {
249218
renderTest({});
@@ -357,8 +326,8 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
357326
adapter.emit('error', errorThrown);
358327
});
359328
});
360-
it('should fire the `onError` callback', () => {
361-
expect(onError).toHaveBeenCalledWith(errorThrown, adapter);
329+
it('should not fire the `onError` callback', () => {
330+
expect(onError).not.toHaveBeenCalled();
362331
});
363332
});
364333
});
@@ -452,8 +421,8 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
452421
mobileWalletAdapter.disconnect();
453422
});
454423
});
455-
it('should not clear the stored wallet name', () => {
456-
expect(localStorage.removeItem).not.toHaveBeenCalled();
424+
it('should clear the stored wallet name', () => {
425+
expect(localStorage.removeItem).toHaveBeenCalledWith(WALLET_NAME_CACHE_KEY);
457426
});
458427
});
459428
describe('when window beforeunload event fires', () => {
@@ -470,8 +439,8 @@ describe('WalletProvider when the environment is `MOBILE_WEB`', () => {
470439
mobileWalletAdapter.disconnect();
471440
});
472441
});
473-
it('should not clear the stored wallet name', () => {
474-
expect(localStorage.removeItem).not.toHaveBeenCalled();
442+
it('should clear the stored wallet name', () => {
443+
expect(localStorage.removeItem).toHaveBeenCalledWith(WALLET_NAME_CACHE_KEY);
475444
});
476445
it('should clear out the state', () => {
477446
expect(ref.current?.getWalletContextState()).toMatchObject({

0 commit comments

Comments
 (0)