@tomo-inc/inject-providers 0.0.15 → 0.0.17
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/index.cjs +19 -11
- package/dist/index.js +19 -11
- package/package.json +3 -2
- package/project.json +1 -1
- package/src/__tests__/btc-provider.test.ts +523 -0
- package/src/__tests__/dapp-info.test.ts +603 -0
- package/src/__tests__/dogecoin-provider.test.ts +288 -0
- package/src/__tests__/dom.test.ts +146 -0
- package/src/__tests__/evm-provider.test.ts +1362 -0
- package/src/__tests__/evm-shim.test.ts +114 -0
- package/src/__tests__/evm-utils.test.ts +258 -0
- package/src/__tests__/index.test.ts +26 -0
- package/src/__tests__/messages.test.ts +139 -0
- package/src/__tests__/ready-promise.test.ts +114 -0
- package/src/__tests__/solana-provider.test.ts +375 -0
- package/src/__tests__/solana-utils.test.ts +60 -0
- package/src/__tests__/tron-provider.test.ts +288 -0
- package/src/__tests__/utils.test.ts +78 -0
- package/src/evm/metamask.ts +1 -1
- package/src/solana/phantom.ts +9 -7
- package/src/utils/dapp-info.ts +13 -8
- package/src/utils/dom.ts +2 -1
- package/vitest.config.ts +27 -0
|
@@ -0,0 +1,523 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import { BitcoinProvider } from "../btc";
|
|
3
|
+
import { IProductInfo, IConnectors } from "../types";
|
|
4
|
+
import * as utils from "../utils/index";
|
|
5
|
+
|
|
6
|
+
describe("BitcoinProvider", () => {
|
|
7
|
+
let provider: BitcoinProvider;
|
|
8
|
+
let mockSendRequest: ReturnType<typeof vi.fn>;
|
|
9
|
+
let mockOnResponse: ReturnType<typeof vi.fn>;
|
|
10
|
+
let productInfo: IProductInfo;
|
|
11
|
+
let connectors: IConnectors;
|
|
12
|
+
|
|
13
|
+
beforeEach(() => {
|
|
14
|
+
mockSendRequest = vi.fn();
|
|
15
|
+
mockOnResponse = vi.fn().mockResolvedValue({ data: null });
|
|
16
|
+
|
|
17
|
+
productInfo = {
|
|
18
|
+
name: "Test Wallet",
|
|
19
|
+
rdns: "com.test.wallet",
|
|
20
|
+
icon: "test-icon.png",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
connectors = {
|
|
24
|
+
sendRequest: mockSendRequest,
|
|
25
|
+
onResponse: mockOnResponse,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Mock utils
|
|
29
|
+
vi.spyOn(utils, "getDappInfo").mockResolvedValue({
|
|
30
|
+
origin: "https://test.com",
|
|
31
|
+
title: "Test",
|
|
32
|
+
desc: "Test desc",
|
|
33
|
+
favicon: "",
|
|
34
|
+
});
|
|
35
|
+
vi.spyOn(utils, "domReadyCall").mockImplementation((callback) => {
|
|
36
|
+
callback();
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
// Mock document methods
|
|
40
|
+
vi.spyOn(document, "addEventListener").mockImplementation(() => {});
|
|
41
|
+
vi.spyOn(window, "addEventListener").mockImplementation(() => {});
|
|
42
|
+
|
|
43
|
+
// Mock setTimeout to prevent keepAlive from running
|
|
44
|
+
vi.useFakeTimers();
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
afterEach(() => {
|
|
48
|
+
vi.restoreAllMocks();
|
|
49
|
+
vi.useRealTimers();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
describe("constructor", () => {
|
|
53
|
+
it("should create BitcoinProvider instance", () => {
|
|
54
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
55
|
+
expect(provider).toBeInstanceOf(BitcoinProvider);
|
|
56
|
+
expect(provider.name).toBe("Test Wallet");
|
|
57
|
+
expect(provider.rdns).toBe("com.test.wallet");
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("should initialize with default values", () => {
|
|
61
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
62
|
+
expect(provider._selectedAddress).toBeNull();
|
|
63
|
+
expect(provider._isConnected).toBe(false);
|
|
64
|
+
expect(provider._initialized).toBe(false);
|
|
65
|
+
expect(provider.chainId).toBe("BITCOIN_MAINNET");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("should call _request on visibilitychange when visible", async () => {
|
|
69
|
+
let visibilityHandler: (() => void) | null = null;
|
|
70
|
+
vi.mocked(document.addEventListener).mockImplementation((event: string, handler: any) => {
|
|
71
|
+
if (event === "visibilitychange") visibilityHandler = handler;
|
|
72
|
+
});
|
|
73
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
74
|
+
mockOnResponse.mockResolvedValue({});
|
|
75
|
+
Object.defineProperty(document, "visibilityState", {
|
|
76
|
+
value: "visible",
|
|
77
|
+
writable: true,
|
|
78
|
+
configurable: true,
|
|
79
|
+
});
|
|
80
|
+
if (visibilityHandler) await visibilityHandler();
|
|
81
|
+
expect(mockSendRequest).toHaveBeenCalledWith(
|
|
82
|
+
"bitcoin",
|
|
83
|
+
expect.objectContaining({ method: "wallet_sendDomainMetadata" }),
|
|
84
|
+
);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it("should handle window message subscribeWalletEvents", () => {
|
|
88
|
+
let messageHandler: ((e: MessageEvent) => void) | null = null;
|
|
89
|
+
vi.mocked(window.addEventListener).mockImplementation((event: string, handler: any) => {
|
|
90
|
+
if (event === "message") messageHandler = handler;
|
|
91
|
+
});
|
|
92
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
93
|
+
(provider as any)._state.initialized = true;
|
|
94
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
95
|
+
if (messageHandler) {
|
|
96
|
+
messageHandler({
|
|
97
|
+
data: {
|
|
98
|
+
type: "subscribeWalletEvents",
|
|
99
|
+
method: "accountsChanged",
|
|
100
|
+
data: { bitcoin: [{ address: "bc1xxx" }] },
|
|
101
|
+
},
|
|
102
|
+
} as MessageEvent);
|
|
103
|
+
}
|
|
104
|
+
expect(emitSpy).toHaveBeenCalledWith("accountsChanged", ["bc1xxx"]);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe("request", () => {
|
|
109
|
+
beforeEach(() => {
|
|
110
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("should throw error if method is not provided", async () => {
|
|
114
|
+
await expect(provider.request({ method: "", params: {} })).rejects.toThrow();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should call sendRequest with correct parameters", async () => {
|
|
118
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
119
|
+
return Promise.resolve({ data: ["0x123"] });
|
|
120
|
+
});
|
|
121
|
+
await provider.request({ method: "getAccounts", params: {} });
|
|
122
|
+
|
|
123
|
+
expect(mockSendRequest).toHaveBeenCalled();
|
|
124
|
+
expect(mockOnResponse).toHaveBeenCalledWith({ method: "getAccounts" });
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it("should return response data", async () => {
|
|
128
|
+
const expectedData = ["0x123"];
|
|
129
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
130
|
+
return Promise.resolve({ data: expectedData });
|
|
131
|
+
});
|
|
132
|
+
const result = await provider.request({ method: "getAccounts", params: {} });
|
|
133
|
+
|
|
134
|
+
expect(result).toEqual(expectedData);
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
describe("connect", () => {
|
|
139
|
+
beforeEach(() => {
|
|
140
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it("should call request with connect method", async () => {
|
|
144
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
145
|
+
return Promise.resolve({ data: { address: "0x123" } });
|
|
146
|
+
});
|
|
147
|
+
await provider.connect();
|
|
148
|
+
|
|
149
|
+
expect(mockSendRequest).toHaveBeenCalled();
|
|
150
|
+
expect(mockOnResponse).toHaveBeenCalledWith({ method: "connect" });
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("disconnect", () => {
|
|
155
|
+
beforeEach(() => {
|
|
156
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("should call request with disconnect method", async () => {
|
|
160
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
161
|
+
return Promise.resolve({ data: { disconnected: true } });
|
|
162
|
+
});
|
|
163
|
+
await provider.disconnect();
|
|
164
|
+
|
|
165
|
+
expect(mockSendRequest).toHaveBeenCalled();
|
|
166
|
+
expect(mockOnResponse).toHaveBeenCalledWith({ method: "disconnect" });
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
describe("requestAccounts", () => {
|
|
171
|
+
beforeEach(() => {
|
|
172
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("should return accounts array", async () => {
|
|
176
|
+
const accounts = ["0x123", "0x456"];
|
|
177
|
+
mockOnResponse.mockImplementation(() => Promise.resolve({ data: accounts }));
|
|
178
|
+
const result = await provider.requestAccounts();
|
|
179
|
+
|
|
180
|
+
expect(result).toEqual(accounts);
|
|
181
|
+
});
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
describe("getAccounts", () => {
|
|
185
|
+
beforeEach(() => {
|
|
186
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it("should return accounts array", async () => {
|
|
190
|
+
const accounts = ["0x123"];
|
|
191
|
+
mockOnResponse.mockImplementation(() => Promise.resolve({ data: accounts }));
|
|
192
|
+
const result = await provider.getAccounts();
|
|
193
|
+
|
|
194
|
+
expect(result).toEqual(accounts);
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
describe("signMessage", () => {
|
|
199
|
+
beforeEach(() => {
|
|
200
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it("should sign message with default type", async () => {
|
|
204
|
+
const signature = "0xsignature";
|
|
205
|
+
mockOnResponse.mockImplementation(() => Promise.resolve({ data: signature }));
|
|
206
|
+
const result = await provider.signMessage("test message");
|
|
207
|
+
|
|
208
|
+
expect(result).toBe(signature);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should sign message with specified type", async () => {
|
|
212
|
+
const signature = "0xsignature";
|
|
213
|
+
mockOnResponse.mockImplementation(() => Promise.resolve({ data: signature }));
|
|
214
|
+
const result = await provider.signMessage("test message", "ecdsa");
|
|
215
|
+
|
|
216
|
+
expect(result).toBe(signature);
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
describe("getBalance", () => {
|
|
221
|
+
beforeEach(() => {
|
|
222
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
it("should return balance", async () => {
|
|
226
|
+
const balance = { confirmed: 1000, unconfirmed: 100, total: 1100 };
|
|
227
|
+
mockOnResponse.mockImplementation(() => Promise.resolve({ data: balance }));
|
|
228
|
+
const result = await provider.getBalance();
|
|
229
|
+
|
|
230
|
+
expect(result).toEqual(balance);
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("_request with adapter", () => {
|
|
235
|
+
beforeEach(() => {
|
|
236
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it("should use adapter when provided", async () => {
|
|
240
|
+
mockOnResponse.mockResolvedValue({ data: { confirmed: 100 } });
|
|
241
|
+
const adapter = vi.fn((d: any) => ({ wrapped: d }));
|
|
242
|
+
const result = await (provider as any)._request({ method: "getBalance" }, adapter);
|
|
243
|
+
expect(adapter).toHaveBeenCalledWith({ confirmed: 100 });
|
|
244
|
+
expect(result).toEqual({ wrapped: { confirmed: 100 } });
|
|
245
|
+
});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
describe("_request connect and wallet_switchEthereumChain branches", () => {
|
|
249
|
+
beforeEach(() => {
|
|
250
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
it("should call _handleAccountsChanged when method is connect and data has address", async () => {
|
|
254
|
+
mockOnResponse.mockResolvedValue({ data: { address: "bc1xxx" } });
|
|
255
|
+
await (provider as any)._request({ method: "connect" });
|
|
256
|
+
expect(provider._selectedAddress).toBe("bc1xxx");
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
it("should call _handleChainChanged when method is wallet_switchEthereumChain", async () => {
|
|
260
|
+
mockOnResponse.mockResolvedValue({ data: "0x2" });
|
|
261
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
262
|
+
await (provider as any)._request({ method: "wallet_switchEthereumChain" });
|
|
263
|
+
expect(emitSpy).toHaveBeenCalledWith("chainChanged", "0x2");
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it("should handle connect with no address in response", async () => {
|
|
267
|
+
mockOnResponse.mockResolvedValue({ data: {} });
|
|
268
|
+
const result = await (provider as any)._request({ method: "connect" });
|
|
269
|
+
expect(result).toEqual({});
|
|
270
|
+
expect(mockSendRequest).toHaveBeenCalled();
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it("should return data when response is null (res || {} branch)", async () => {
|
|
274
|
+
mockOnResponse.mockResolvedValue(null);
|
|
275
|
+
const result = await (provider as any)._request({ method: "getBalance" });
|
|
276
|
+
expect(result).toBeUndefined();
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
it("should call _handleAccountsChanged when method is getAccounts", async () => {
|
|
280
|
+
mockOnResponse.mockResolvedValue({ data: ["addr1", "addr2"] });
|
|
281
|
+
await (provider as any)._request({ method: "getAccounts" });
|
|
282
|
+
expect((provider as any)._state.accounts).toEqual(["addr1", "addr2"]);
|
|
283
|
+
});
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
describe("subscribeWalletEventsCallback", () => {
|
|
287
|
+
beforeEach(() => {
|
|
288
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
289
|
+
provider._state.initialized = true;
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it("should handle accountsChanged event", () => {
|
|
293
|
+
const accountsChangedSpy = vi.spyOn(provider, "emit");
|
|
294
|
+
// ChainTypes.BITCOIN is "bitcoin" from wallet-utils
|
|
295
|
+
const data = {
|
|
296
|
+
bitcoin: [{ address: "0x123" }],
|
|
297
|
+
};
|
|
298
|
+
|
|
299
|
+
provider.subscribeWalletEventsCallback({
|
|
300
|
+
method: "accountsChanged",
|
|
301
|
+
data,
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
expect(accountsChangedSpy).toHaveBeenCalledWith("accountsChanged", ["0x123"]);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it("should handle chainChanged event", () => {
|
|
308
|
+
const chainChangedSpy = vi.spyOn(provider, "emit");
|
|
309
|
+
const data = {
|
|
310
|
+
chainId: "0x1",
|
|
311
|
+
type: "bitcoin:mainnet",
|
|
312
|
+
};
|
|
313
|
+
|
|
314
|
+
provider.subscribeWalletEventsCallback({
|
|
315
|
+
method: "chainChanged",
|
|
316
|
+
data,
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
expect(chainChangedSpy).toHaveBeenCalledWith("chainChanged", "0x1");
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it("should not emit chainChanged when type does not match chain prefix", () => {
|
|
323
|
+
const chainChangedSpy = vi.spyOn(provider, "emit");
|
|
324
|
+
provider.subscribeWalletEventsCallback({
|
|
325
|
+
method: "chainChanged",
|
|
326
|
+
data: { chainId: "0x2", type: "eth:mainnet" },
|
|
327
|
+
});
|
|
328
|
+
expect(chainChangedSpy).not.toHaveBeenCalledWith("chainChanged", expect.anything());
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it("should not emit chainChanged when chainId is same as current", () => {
|
|
332
|
+
const chainChangedSpy = vi.spyOn(provider, "emit");
|
|
333
|
+
provider.chainId = "0x1";
|
|
334
|
+
provider.subscribeWalletEventsCallback({
|
|
335
|
+
method: "chainChanged",
|
|
336
|
+
data: { chainId: "0x1", type: "bitcoin:mainnet" },
|
|
337
|
+
});
|
|
338
|
+
expect(chainChangedSpy).not.toHaveBeenCalled();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
it("should not emit chainChanged when not initialized", () => {
|
|
342
|
+
(provider as any)._state.initialized = false;
|
|
343
|
+
const chainChangedSpy = vi.spyOn(provider, "emit");
|
|
344
|
+
provider.subscribeWalletEventsCallback({
|
|
345
|
+
method: "chainChanged",
|
|
346
|
+
data: { chainId: "0x2", type: "bitcoin:mainnet" },
|
|
347
|
+
});
|
|
348
|
+
expect(chainChangedSpy).not.toHaveBeenCalled();
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
it("should not emit chainChanged when chainId is missing or invalid", () => {
|
|
352
|
+
const chainChangedSpy = vi.spyOn(provider, "emit");
|
|
353
|
+
provider.subscribeWalletEventsCallback({
|
|
354
|
+
method: "chainChanged",
|
|
355
|
+
data: { type: "bitcoin:mainnet" },
|
|
356
|
+
});
|
|
357
|
+
expect(chainChangedSpy).not.toHaveBeenCalled();
|
|
358
|
+
provider.subscribeWalletEventsCallback({
|
|
359
|
+
method: "chainChanged",
|
|
360
|
+
data: { chainId: 123, type: "bitcoin:mainnet" },
|
|
361
|
+
});
|
|
362
|
+
expect(chainChangedSpy).not.toHaveBeenCalled();
|
|
363
|
+
provider.subscribeWalletEventsCallback({
|
|
364
|
+
method: "chainChanged",
|
|
365
|
+
data: { chainId: "abc", type: "bitcoin:mainnet" },
|
|
366
|
+
});
|
|
367
|
+
expect(chainChangedSpy).not.toHaveBeenCalled();
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
it("should handle accountsChanged with invalid (non-array) accounts from getAccounts response", async () => {
|
|
371
|
+
const consoleSpy = vi.spyOn(console, "error").mockImplementation(() => {});
|
|
372
|
+
mockOnResponse.mockResolvedValue({ data: "not-an-array" });
|
|
373
|
+
await provider.getAccounts();
|
|
374
|
+
expect(provider._state.accounts).toEqual([]);
|
|
375
|
+
expect(consoleSpy).toHaveBeenCalledWith("BTC: Received invalid accounts parameter.", "not-an-array");
|
|
376
|
+
consoleSpy.mockRestore();
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
it("should handle chainChanged when type does not start with bitcoin:", () => {
|
|
380
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
381
|
+
provider.subscribeWalletEventsCallback({
|
|
382
|
+
method: "chainChanged",
|
|
383
|
+
data: { chainId: "0x1", type: "evm:1" },
|
|
384
|
+
});
|
|
385
|
+
expect(provider.chainId).toBe("BITCOIN_MAINNET");
|
|
386
|
+
expect(emitSpy).not.toHaveBeenCalledWith("chainChanged", expect.anything());
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
it("should not emit chainChanged when chainId is invalid (no 0x prefix)", () => {
|
|
390
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
391
|
+
provider.subscribeWalletEventsCallback({
|
|
392
|
+
method: "chainChanged",
|
|
393
|
+
data: { chainId: "1", type: "bitcoin:mainnet" },
|
|
394
|
+
});
|
|
395
|
+
expect(provider.chainId).toBe("BITCOIN_MAINNET");
|
|
396
|
+
expect(emitSpy).not.toHaveBeenCalledWith("chainChanged", expect.anything());
|
|
397
|
+
});
|
|
398
|
+
|
|
399
|
+
it("should not emit chainChanged when chainId equals current chainId", () => {
|
|
400
|
+
provider.chainId = "0x1";
|
|
401
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
402
|
+
provider.subscribeWalletEventsCallback({
|
|
403
|
+
method: "chainChanged",
|
|
404
|
+
data: { chainId: "0x1", type: "bitcoin:mainnet" },
|
|
405
|
+
});
|
|
406
|
+
expect(emitSpy).not.toHaveBeenCalledWith("chainChanged", expect.anything());
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
it("should not emit chainChanged when not initialized", () => {
|
|
410
|
+
provider._state.initialized = false;
|
|
411
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
412
|
+
provider.subscribeWalletEventsCallback({
|
|
413
|
+
method: "chainChanged",
|
|
414
|
+
data: { chainId: "0x2", type: "bitcoin:mainnet" },
|
|
415
|
+
});
|
|
416
|
+
expect(provider.chainId).toBe("BITCOIN_MAINNET");
|
|
417
|
+
expect(emitSpy).not.toHaveBeenCalledWith("chainChanged", expect.anything());
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
describe("_request branches", () => {
|
|
422
|
+
beforeEach(() => {
|
|
423
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
424
|
+
});
|
|
425
|
+
|
|
426
|
+
it("should call _handleChainChanged when method is wallet_switchEthereumChain", async () => {
|
|
427
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
428
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
429
|
+
if (method === "wallet_switchEthereumChain") {
|
|
430
|
+
return Promise.resolve({ data: "0x2" });
|
|
431
|
+
}
|
|
432
|
+
return Promise.resolve({ data: null });
|
|
433
|
+
});
|
|
434
|
+
await provider.request({ method: "wallet_switchEthereumChain", params: { chainId: "0x2" } });
|
|
435
|
+
expect(provider.chainId).toBe("0x2");
|
|
436
|
+
expect(emitSpy).toHaveBeenCalledWith("chainChanged", "0x2");
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it("should call _handleAccountsChanged when connect returns data.address", async () => {
|
|
440
|
+
mockOnResponse.mockImplementation(({ method }) => {
|
|
441
|
+
if (method === "connect") {
|
|
442
|
+
return Promise.resolve({ data: { address: "bc1new" } });
|
|
443
|
+
}
|
|
444
|
+
return Promise.resolve({ data: null });
|
|
445
|
+
});
|
|
446
|
+
const emitSpy = vi.spyOn(provider, "emit");
|
|
447
|
+
provider._state.initialized = true;
|
|
448
|
+
await provider.connect();
|
|
449
|
+
expect(provider._selectedAddress).toBe("bc1new");
|
|
450
|
+
expect(emitSpy).toHaveBeenCalledWith("accountsChanged", ["bc1new"]);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it("should use adapter when provided", async () => {
|
|
454
|
+
const adapted = { adapted: true };
|
|
455
|
+
mockOnResponse.mockResolvedValue({ data: { raw: 1 } });
|
|
456
|
+
const result = await (provider as any)._request(
|
|
457
|
+
{ method: "getBalance", params: {} },
|
|
458
|
+
(data: any) => ({ ...data, adapted: true }),
|
|
459
|
+
);
|
|
460
|
+
expect(result).toEqual({ raw: 1, adapted: true });
|
|
461
|
+
});
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
describe("public API methods", () => {
|
|
465
|
+
beforeEach(() => {
|
|
466
|
+
provider = new BitcoinProvider(productInfo, connectors);
|
|
467
|
+
mockOnResponse.mockImplementation(({ method }) => Promise.resolve({ data: `res-${method}` }));
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
it("getPublicKey", async () => {
|
|
471
|
+
const r = await provider.getPublicKey();
|
|
472
|
+
expect(r).toBe("res-getPublicKey");
|
|
473
|
+
});
|
|
474
|
+
it("getTransactionStatus", async () => {
|
|
475
|
+
const r = await provider.getTransactionStatus({ txId: "abc" });
|
|
476
|
+
expect(r).toBe("res-getTransactionStatus");
|
|
477
|
+
});
|
|
478
|
+
it("getNetwork", async () => {
|
|
479
|
+
const r = await provider.getNetwork();
|
|
480
|
+
expect(r).toBe("res-getNetwork");
|
|
481
|
+
});
|
|
482
|
+
it("switchNetwork", async () => {
|
|
483
|
+
const r = await provider.switchNetwork("mainnet");
|
|
484
|
+
expect(mockSendRequest).toHaveBeenCalledWith("bitcoin", expect.objectContaining({ method: "switchNetwork", params: { network: "mainnet" } }));
|
|
485
|
+
});
|
|
486
|
+
it("getChain", async () => {
|
|
487
|
+
const r = await provider.getChain();
|
|
488
|
+
expect(r).toBe("res-getChain");
|
|
489
|
+
});
|
|
490
|
+
it("switchChain", async () => {
|
|
491
|
+
const r = await provider.switchChain("BITCOIN_MAINNET");
|
|
492
|
+
expect(r).toBe("res-switchChain");
|
|
493
|
+
});
|
|
494
|
+
it("signPsbt", async () => {
|
|
495
|
+
const r = await provider.signPsbt("hex");
|
|
496
|
+
expect(r).toBe("res-signPsbt");
|
|
497
|
+
});
|
|
498
|
+
it("signPsbts", async () => {
|
|
499
|
+
const r = await provider.signPsbts(["a", "b"]);
|
|
500
|
+
expect(r).toBe("res-signPsbts");
|
|
501
|
+
});
|
|
502
|
+
it("pushPsbt", async () => {
|
|
503
|
+
const r = await provider.pushPsbt("hex");
|
|
504
|
+
expect(r).toBe("res-pushPsbt");
|
|
505
|
+
});
|
|
506
|
+
it("sendBitcoin", async () => {
|
|
507
|
+
const r = await provider.sendBitcoin("addr", 1000, { feeRate: 5 });
|
|
508
|
+
expect(r).toBe("res-sendBitcoin");
|
|
509
|
+
});
|
|
510
|
+
it("signTx", async () => {
|
|
511
|
+
const r = await provider.signTx("raw");
|
|
512
|
+
expect(r).toBe("res-signTx");
|
|
513
|
+
});
|
|
514
|
+
it("pushTx", async () => {
|
|
515
|
+
const r = await provider.pushTx("raw");
|
|
516
|
+
expect(r).toBe("res-pushTx");
|
|
517
|
+
});
|
|
518
|
+
it("sendTransaction", async () => {
|
|
519
|
+
const r = await provider.sendTransaction({ from: "a", to: "b" });
|
|
520
|
+
expect(r).toBe("res-sendTransaction");
|
|
521
|
+
});
|
|
522
|
+
});
|
|
523
|
+
});
|