@rango-dev/wallets-react 0.49.2-next.3 → 0.49.2-next.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/events.d.ts +49 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/hub/autoConnect.d.ts +2 -0
- package/dist/hub/autoConnect.d.ts.map +1 -1
- package/dist/hub/constants.d.ts +1 -0
- package/dist/hub/constants.d.ts.map +1 -1
- package/dist/hub/useHubAdapter.d.ts.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +4 -4
- package/dist/types.d.ts +3 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/walletEvents.test.d.ts +2 -0
- package/dist/walletEvents.test.d.ts.map +1 -0
- package/package.json +2 -1
- package/src/events.ts +99 -0
- package/src/hub/autoConnect.ts +55 -3
- package/src/hub/constants.ts +12 -0
- package/src/hub/useHubAdapter.ts +76 -21
- package/src/index.ts +12 -0
- package/src/types.ts +3 -0
- package/src/walletEvents.test.tsx +533 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
Emitter,
|
|
3
|
+
ProviderProps,
|
|
4
|
+
WalletEventData,
|
|
5
|
+
WalletEvents,
|
|
6
|
+
} from './index.js';
|
|
7
|
+
import type { Provider as HubProvider } from '@hub3js/core';
|
|
8
|
+
import type { EvmBlockchainMeta } from 'rango-types';
|
|
9
|
+
|
|
10
|
+
import { NamespaceBuilder, ProviderBuilder } from '@hub3js/core';
|
|
11
|
+
import { garbageWalletMetaData } from '@hub3js/core/test-utils';
|
|
12
|
+
import { act, renderHook } from '@testing-library/react-hooks/dom';
|
|
13
|
+
import { TransactionType } from 'rango-types';
|
|
14
|
+
import React from 'react';
|
|
15
|
+
import { beforeEach, describe, expect, test, vi } from 'vitest';
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
Provider,
|
|
19
|
+
useWallets,
|
|
20
|
+
WalletEventChannel,
|
|
21
|
+
WalletEventTypes,
|
|
22
|
+
} from './index.js';
|
|
23
|
+
|
|
24
|
+
const LAST_CONNECTED_WALLETS_KEY = 'hub-v1-last-connected-wallets';
|
|
25
|
+
const EVM_ACCOUNT = 'eip155:1:0x000000000000000000000000000000000000dEaD';
|
|
26
|
+
const SOLANA_ACCOUNT =
|
|
27
|
+
'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp:11111111111111111111111111111111';
|
|
28
|
+
|
|
29
|
+
function createEvmBlockchain(name: string, chainId: string): EvmBlockchainMeta {
|
|
30
|
+
return {
|
|
31
|
+
name,
|
|
32
|
+
shortName: name,
|
|
33
|
+
displayName: name,
|
|
34
|
+
defaultDecimals: 18,
|
|
35
|
+
addressPatterns: [],
|
|
36
|
+
logo: '',
|
|
37
|
+
color: '#000000',
|
|
38
|
+
sort: 1,
|
|
39
|
+
enabled: true,
|
|
40
|
+
feeAssets: [],
|
|
41
|
+
type: TransactionType.EVM,
|
|
42
|
+
chainId,
|
|
43
|
+
info: {
|
|
44
|
+
infoType: 'EvmMetaInfo',
|
|
45
|
+
chainName: name,
|
|
46
|
+
nativeCurrency: { name, symbol: name, decimals: 18 },
|
|
47
|
+
rpcUrls: [],
|
|
48
|
+
blockExplorerUrls: [],
|
|
49
|
+
addressUrl: '',
|
|
50
|
+
transactionUrl: '',
|
|
51
|
+
enableGasV2: false,
|
|
52
|
+
tokenUrl: '',
|
|
53
|
+
},
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const allBlockChains = [
|
|
58
|
+
createEvmBlockchain('ETH', '0x1'),
|
|
59
|
+
createEvmBlockchain('POLYGON', '0x89'),
|
|
60
|
+
];
|
|
61
|
+
|
|
62
|
+
type NamespaceBehaviour = {
|
|
63
|
+
connect?: () => Promise<void>;
|
|
64
|
+
disconnect?: () => Promise<void>;
|
|
65
|
+
canEagerConnect?: () => Promise<boolean>;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
interface TestActions {
|
|
69
|
+
connect: (...args: unknown[]) => Promise<unknown>;
|
|
70
|
+
disconnect: () => Promise<void>;
|
|
71
|
+
canEagerConnect: () => Promise<boolean>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function buildNamespace(
|
|
75
|
+
namespaceId: 'EVM' | 'Solana',
|
|
76
|
+
walletId: string,
|
|
77
|
+
behaviour: NamespaceBehaviour
|
|
78
|
+
) {
|
|
79
|
+
return new NamespaceBuilder<TestActions>(namespaceId, walletId)
|
|
80
|
+
.action('connect', async (context) => {
|
|
81
|
+
await behaviour.connect?.();
|
|
82
|
+
const [, setState] = context.state();
|
|
83
|
+
setState('connected', true);
|
|
84
|
+
if (namespaceId === 'EVM') {
|
|
85
|
+
setState('accounts', [EVM_ACCOUNT]);
|
|
86
|
+
setState('network', '0x1');
|
|
87
|
+
return { accounts: [EVM_ACCOUNT], network: '0x1' };
|
|
88
|
+
}
|
|
89
|
+
setState('accounts', [SOLANA_ACCOUNT]);
|
|
90
|
+
return [SOLANA_ACCOUNT];
|
|
91
|
+
})
|
|
92
|
+
.action('disconnect', async (context) => {
|
|
93
|
+
await behaviour.disconnect?.();
|
|
94
|
+
const [, setState] = context.state();
|
|
95
|
+
setState('connected', false);
|
|
96
|
+
setState('accounts', null);
|
|
97
|
+
})
|
|
98
|
+
.action(
|
|
99
|
+
'canEagerConnect',
|
|
100
|
+
async () => (await behaviour.canEagerConnect?.()) ?? true
|
|
101
|
+
)
|
|
102
|
+
.build();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function buildWallet(
|
|
106
|
+
walletId: string,
|
|
107
|
+
namespaces: {
|
|
108
|
+
evm?: NamespaceBehaviour;
|
|
109
|
+
solana?: NamespaceBehaviour;
|
|
110
|
+
} = {},
|
|
111
|
+
options: { installed?: boolean } = {}
|
|
112
|
+
): HubProvider {
|
|
113
|
+
return new ProviderBuilder(walletId)
|
|
114
|
+
.config('metadata', garbageWalletMetaData)
|
|
115
|
+
.init((context) => {
|
|
116
|
+
const [, setState] = context.state();
|
|
117
|
+
setState('installed', options.installed ?? true);
|
|
118
|
+
})
|
|
119
|
+
.add('evm', buildNamespace('EVM', walletId, namespaces.evm ?? {}))
|
|
120
|
+
.add('solana', buildNamespace('Solana', walletId, namespaces.solana ?? {}))
|
|
121
|
+
.build() as unknown as HubProvider;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
function createRecordingEmitter() {
|
|
125
|
+
const events: WalletEventData[] = [];
|
|
126
|
+
const emitter: Emitter<WalletEvents> = {
|
|
127
|
+
emit(type, event) {
|
|
128
|
+
expect(type).toBe(WalletEventChannel);
|
|
129
|
+
events.push(event);
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
return { events, emitter };
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// The hub detects the test wallets on render; connect and disconnect tests only look at the rest.
|
|
136
|
+
function withoutDetection(events: WalletEventData[]) {
|
|
137
|
+
return events.filter(
|
|
138
|
+
(event) => event.type !== WalletEventTypes.WALLET_DETECTED
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function renderWallets(props: Omit<ProviderProps, 'children'>) {
|
|
143
|
+
const wrapper = ({ children }: { children?: React.ReactNode }) => (
|
|
144
|
+
<Provider {...props}>{children}</Provider>
|
|
145
|
+
);
|
|
146
|
+
return renderHook(() => useWallets(), { wrapper });
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function rejectWith(error: unknown) {
|
|
150
|
+
return async () => {
|
|
151
|
+
throw error;
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
beforeEach(() => {
|
|
156
|
+
localStorage.clear();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe('manual connect', () => {
|
|
160
|
+
test('emits initiated then connected or failed for each namespace', async () => {
|
|
161
|
+
const { events, emitter } = createRecordingEmitter();
|
|
162
|
+
const wallet = buildWallet('manual-mixed', {
|
|
163
|
+
evm: {},
|
|
164
|
+
solana: { connect: rejectWith(new Error('boom')) },
|
|
165
|
+
});
|
|
166
|
+
const { result } = renderWallets({
|
|
167
|
+
providers: [wallet],
|
|
168
|
+
allBlockChains,
|
|
169
|
+
emitter,
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
await act(async () => {
|
|
173
|
+
await expect(
|
|
174
|
+
result.current.connect('manual-mixed', [
|
|
175
|
+
{ namespace: 'EVM', network: 'ETH' },
|
|
176
|
+
{ namespace: 'Solana', network: undefined },
|
|
177
|
+
])
|
|
178
|
+
).rejects.toThrow('boom');
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
expect(withoutDetection(events)).toEqual([
|
|
182
|
+
{
|
|
183
|
+
type: WalletEventTypes.WALLET_CONNECT_INITIATED,
|
|
184
|
+
payload: {
|
|
185
|
+
walletName: 'manual-mixed',
|
|
186
|
+
namespace: 'EVM',
|
|
187
|
+
chain: 'ETH',
|
|
188
|
+
origin: 'manual',
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
type: WalletEventTypes.WALLET_CONNECTED,
|
|
193
|
+
payload: {
|
|
194
|
+
walletName: 'manual-mixed',
|
|
195
|
+
namespace: 'EVM',
|
|
196
|
+
chain: 'ETH',
|
|
197
|
+
origin: 'manual',
|
|
198
|
+
},
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
type: WalletEventTypes.WALLET_CONNECT_INITIATED,
|
|
202
|
+
payload: {
|
|
203
|
+
walletName: 'manual-mixed',
|
|
204
|
+
namespace: 'Solana',
|
|
205
|
+
chain: null,
|
|
206
|
+
origin: 'manual',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
type: WalletEventTypes.WALLET_CONNECT_FAILED,
|
|
211
|
+
payload: {
|
|
212
|
+
walletName: 'manual-mixed',
|
|
213
|
+
namespace: 'Solana',
|
|
214
|
+
chain: null,
|
|
215
|
+
origin: 'manual',
|
|
216
|
+
},
|
|
217
|
+
},
|
|
218
|
+
]);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
test('reports the connected network, not the requested one, on success', async () => {
|
|
222
|
+
const { events, emitter } = createRecordingEmitter();
|
|
223
|
+
const { result } = renderWallets({
|
|
224
|
+
providers: [buildWallet('manual-no-network')],
|
|
225
|
+
allBlockChains,
|
|
226
|
+
emitter,
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
await act(async () => {
|
|
230
|
+
await result.current.connect('manual-no-network', [
|
|
231
|
+
{ namespace: 'EVM', network: undefined },
|
|
232
|
+
]);
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
expect(
|
|
236
|
+
withoutDetection(events).map((event) => [event.type, event.payload])
|
|
237
|
+
).toEqual([
|
|
238
|
+
[
|
|
239
|
+
WalletEventTypes.WALLET_CONNECT_INITIATED,
|
|
240
|
+
{
|
|
241
|
+
walletName: 'manual-no-network',
|
|
242
|
+
namespace: 'EVM',
|
|
243
|
+
chain: null,
|
|
244
|
+
origin: 'manual',
|
|
245
|
+
},
|
|
246
|
+
],
|
|
247
|
+
[
|
|
248
|
+
WalletEventTypes.WALLET_CONNECTED,
|
|
249
|
+
{
|
|
250
|
+
walletName: 'manual-no-network',
|
|
251
|
+
namespace: 'EVM',
|
|
252
|
+
chain: 'ETH',
|
|
253
|
+
origin: 'manual',
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
]);
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
test('emits nothing for a namespace that is already connected', async () => {
|
|
260
|
+
const { events, emitter } = createRecordingEmitter();
|
|
261
|
+
const { result } = renderWallets({
|
|
262
|
+
providers: [buildWallet('manual-reconnect')],
|
|
263
|
+
allBlockChains,
|
|
264
|
+
emitter,
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
await act(async () => {
|
|
268
|
+
await result.current.connect('manual-reconnect', [
|
|
269
|
+
{ namespace: 'EVM', network: 'ETH' },
|
|
270
|
+
]);
|
|
271
|
+
});
|
|
272
|
+
events.length = 0;
|
|
273
|
+
|
|
274
|
+
await act(async () => {
|
|
275
|
+
await result.current.connect('manual-reconnect', [
|
|
276
|
+
{ namespace: 'EVM', network: 'POLYGON' },
|
|
277
|
+
]);
|
|
278
|
+
});
|
|
279
|
+
|
|
280
|
+
expect(events).toEqual([]);
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
test('emits nothing for namespaces cancelled after a rejection', async () => {
|
|
284
|
+
const { events, emitter } = createRecordingEmitter();
|
|
285
|
+
const rejection = Object.assign(new Error('User rejected'), { code: 4001 });
|
|
286
|
+
const wallet = buildWallet('manual-cancelled', {
|
|
287
|
+
evm: { connect: rejectWith(rejection) },
|
|
288
|
+
solana: {},
|
|
289
|
+
});
|
|
290
|
+
const { result } = renderWallets({
|
|
291
|
+
providers: [wallet],
|
|
292
|
+
allBlockChains,
|
|
293
|
+
emitter,
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
await act(async () => {
|
|
297
|
+
await expect(
|
|
298
|
+
result.current.connect('manual-cancelled', [
|
|
299
|
+
{ namespace: 'EVM', network: undefined },
|
|
300
|
+
{ namespace: 'Solana', network: undefined },
|
|
301
|
+
])
|
|
302
|
+
).rejects.toBe(rejection);
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const payload = {
|
|
306
|
+
walletName: 'manual-cancelled',
|
|
307
|
+
namespace: 'EVM',
|
|
308
|
+
chain: null,
|
|
309
|
+
origin: 'manual',
|
|
310
|
+
};
|
|
311
|
+
expect(withoutDetection(events)).toEqual([
|
|
312
|
+
{ type: WalletEventTypes.WALLET_CONNECT_INITIATED, payload },
|
|
313
|
+
{ type: WalletEventTypes.WALLET_CONNECT_FAILED, payload },
|
|
314
|
+
]);
|
|
315
|
+
});
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
describe('disconnect', () => {
|
|
319
|
+
test('emits one event per namespace when its disconnect is initiated', async () => {
|
|
320
|
+
const { events, emitter } = createRecordingEmitter();
|
|
321
|
+
let finishEvmDisconnect: () => void = () => undefined;
|
|
322
|
+
const wallet = buildWallet('disconnect-wallet', {
|
|
323
|
+
evm: {
|
|
324
|
+
disconnect: async () =>
|
|
325
|
+
new Promise<void>((resolve) => {
|
|
326
|
+
finishEvmDisconnect = resolve;
|
|
327
|
+
}),
|
|
328
|
+
},
|
|
329
|
+
solana: {},
|
|
330
|
+
});
|
|
331
|
+
const { result } = renderWallets({
|
|
332
|
+
providers: [wallet],
|
|
333
|
+
allBlockChains,
|
|
334
|
+
emitter,
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
await act(async () => {
|
|
338
|
+
await result.current.connect('disconnect-wallet', [
|
|
339
|
+
{ namespace: 'EVM', network: undefined },
|
|
340
|
+
{ namespace: 'Solana', network: undefined },
|
|
341
|
+
]);
|
|
342
|
+
});
|
|
343
|
+
events.length = 0;
|
|
344
|
+
|
|
345
|
+
await act(async () => {
|
|
346
|
+
await result.current.disconnect('disconnect-wallet');
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
// Both events fire before the pending EVM disconnect settles.
|
|
350
|
+
expect(events).toEqual([
|
|
351
|
+
{
|
|
352
|
+
type: WalletEventTypes.WALLET_DISCONNECTED,
|
|
353
|
+
payload: { walletName: 'disconnect-wallet', namespace: 'EVM' },
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
type: WalletEventTypes.WALLET_DISCONNECTED,
|
|
357
|
+
payload: { walletName: 'disconnect-wallet', namespace: 'Solana' },
|
|
358
|
+
},
|
|
359
|
+
]);
|
|
360
|
+
|
|
361
|
+
await act(async () => {
|
|
362
|
+
finishEvmDisconnect();
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
expect(events).toHaveLength(2);
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
describe('auto-connect', () => {
|
|
370
|
+
function saveLastConnectedWallet(walletId: string) {
|
|
371
|
+
localStorage.setItem(
|
|
372
|
+
LAST_CONNECTED_WALLETS_KEY,
|
|
373
|
+
JSON.stringify({
|
|
374
|
+
[walletId]: savedNamespaces,
|
|
375
|
+
})
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
const savedNamespaces = [
|
|
380
|
+
{ namespace: 'EVM', network: 'ETH' },
|
|
381
|
+
{ namespace: 'Solana' },
|
|
382
|
+
];
|
|
383
|
+
|
|
384
|
+
// Resolves once every saved namespace has an outcome (connected or failed).
|
|
385
|
+
async function runAutoConnect(
|
|
386
|
+
walletId: string,
|
|
387
|
+
namespaces: { evm: NamespaceBehaviour; solana: NamespaceBehaviour }
|
|
388
|
+
) {
|
|
389
|
+
const { events, emitter } = createRecordingEmitter();
|
|
390
|
+
saveLastConnectedWallet(walletId);
|
|
391
|
+
renderWallets({
|
|
392
|
+
providers: [buildWallet(walletId, namespaces)],
|
|
393
|
+
allBlockChains,
|
|
394
|
+
autoConnect: true,
|
|
395
|
+
emitter,
|
|
396
|
+
});
|
|
397
|
+
|
|
398
|
+
await vi.waitFor(() =>
|
|
399
|
+
expect(
|
|
400
|
+
withoutDetection(events).filter(
|
|
401
|
+
(event) => event.type !== WalletEventTypes.WALLET_CONNECT_INITIATED
|
|
402
|
+
)
|
|
403
|
+
).toHaveLength(savedNamespaces.length)
|
|
404
|
+
);
|
|
405
|
+
const connectEvents = withoutDetection(events);
|
|
406
|
+
|
|
407
|
+
expect(connectEvents[0].type).toBe(
|
|
408
|
+
WalletEventTypes.WALLET_CONNECT_INITIATED
|
|
409
|
+
);
|
|
410
|
+
connectEvents.forEach((event) => {
|
|
411
|
+
expect(event.payload).toMatchObject({
|
|
412
|
+
walletName: walletId,
|
|
413
|
+
origin: 'auto',
|
|
414
|
+
});
|
|
415
|
+
});
|
|
416
|
+
return connectEvents.map((event) => [
|
|
417
|
+
event.type,
|
|
418
|
+
'namespace' in event.payload && event.payload.namespace,
|
|
419
|
+
'chain' in event.payload && event.payload.chain,
|
|
420
|
+
]);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
test('reports a namespace whose eager-connect check returns false as failed', async () => {
|
|
424
|
+
const events = await runAutoConnect('auto-check-false', {
|
|
425
|
+
evm: {},
|
|
426
|
+
solana: { canEagerConnect: async () => false },
|
|
427
|
+
});
|
|
428
|
+
|
|
429
|
+
expect(events).toEqual([
|
|
430
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'EVM', 'ETH'],
|
|
431
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'Solana', null],
|
|
432
|
+
[WalletEventTypes.WALLET_CONNECT_FAILED, 'Solana', null],
|
|
433
|
+
[WalletEventTypes.WALLET_CONNECTED, 'EVM', 'ETH'],
|
|
434
|
+
]);
|
|
435
|
+
});
|
|
436
|
+
|
|
437
|
+
test('reports a namespace whose eager-connect check throws as failed', async () => {
|
|
438
|
+
const events = await runAutoConnect('auto-check-throws', {
|
|
439
|
+
evm: { canEagerConnect: rejectWith(new Error('check failed')) },
|
|
440
|
+
solana: {},
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
expect(events).toEqual([
|
|
444
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'EVM', 'ETH'],
|
|
445
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'Solana', null],
|
|
446
|
+
[WalletEventTypes.WALLET_CONNECT_FAILED, 'EVM', 'ETH'],
|
|
447
|
+
[WalletEventTypes.WALLET_CONNECTED, 'Solana', null],
|
|
448
|
+
]);
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
test('reports a connect that fails after the check passed', async () => {
|
|
452
|
+
const consoleWarn = vi
|
|
453
|
+
.spyOn(console, 'warn')
|
|
454
|
+
.mockImplementation(() => undefined);
|
|
455
|
+
const events = await runAutoConnect('auto-connect-fails', {
|
|
456
|
+
evm: { connect: rejectWith(new Error('connect failed')) },
|
|
457
|
+
solana: { connect: rejectWith(new Error('connect failed')) },
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
expect(events).toEqual([
|
|
461
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'EVM', 'ETH'],
|
|
462
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'Solana', null],
|
|
463
|
+
[WalletEventTypes.WALLET_CONNECT_FAILED, 'EVM', 'ETH'],
|
|
464
|
+
[WalletEventTypes.WALLET_CONNECT_FAILED, 'Solana', null],
|
|
465
|
+
]);
|
|
466
|
+
consoleWarn.mockRestore();
|
|
467
|
+
});
|
|
468
|
+
|
|
469
|
+
test('reports connected namespaces', async () => {
|
|
470
|
+
const events = await runAutoConnect('auto-success', {
|
|
471
|
+
evm: {},
|
|
472
|
+
solana: {},
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
expect(events).toEqual([
|
|
476
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'EVM', 'ETH'],
|
|
477
|
+
[WalletEventTypes.WALLET_CONNECT_INITIATED, 'Solana', null],
|
|
478
|
+
[WalletEventTypes.WALLET_CONNECTED, 'EVM', 'ETH'],
|
|
479
|
+
[WalletEventTypes.WALLET_CONNECTED, 'Solana', null],
|
|
480
|
+
]);
|
|
481
|
+
});
|
|
482
|
+
});
|
|
483
|
+
|
|
484
|
+
describe('detection', () => {
|
|
485
|
+
function detectedWalletNames(events: WalletEventData[]) {
|
|
486
|
+
return events
|
|
487
|
+
.filter((event) => event.type === WalletEventTypes.WALLET_DETECTED)
|
|
488
|
+
.map((event) => event.payload.walletName);
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
test('emits a detected wallet once per page session', () => {
|
|
492
|
+
const first = createRecordingEmitter();
|
|
493
|
+
renderWallets({
|
|
494
|
+
providers: [buildWallet('detected-once')],
|
|
495
|
+
allBlockChains,
|
|
496
|
+
emitter: first.emitter,
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
const second = createRecordingEmitter();
|
|
500
|
+
renderWallets({
|
|
501
|
+
providers: [buildWallet('detected-once')],
|
|
502
|
+
allBlockChains,
|
|
503
|
+
emitter: second.emitter,
|
|
504
|
+
});
|
|
505
|
+
|
|
506
|
+
expect(detectedWalletNames(first.events)).toEqual(['detected-once']);
|
|
507
|
+
expect(detectedWalletNames(second.events)).toEqual([]);
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
test('skips wallets that always report themselves installed', () => {
|
|
511
|
+
const { events, emitter } = createRecordingEmitter();
|
|
512
|
+
renderWallets({
|
|
513
|
+
providers: [buildWallet('ledger'), buildWallet('detected-regular')],
|
|
514
|
+
allBlockChains,
|
|
515
|
+
emitter,
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
expect(detectedWalletNames(events)).toEqual(['detected-regular']);
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
test('emits nothing for a wallet that is not installed', () => {
|
|
522
|
+
const { events, emitter } = createRecordingEmitter();
|
|
523
|
+
renderWallets({
|
|
524
|
+
providers: [
|
|
525
|
+
buildWallet('detected-not-installed', {}, { installed: false }),
|
|
526
|
+
],
|
|
527
|
+
allBlockChains,
|
|
528
|
+
emitter,
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
expect(detectedWalletNames(events)).toEqual([]);
|
|
532
|
+
});
|
|
533
|
+
});
|