@tomo-inc/inject-providers 0.0.16 → 0.0.18
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,114 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";
|
|
2
|
+
import shimWeb3 from "../evm/shimWeb3";
|
|
3
|
+
import { EvmProvider } from "../evm/metamask";
|
|
4
|
+
|
|
5
|
+
describe("shimWeb3", () => {
|
|
6
|
+
let originalWindow: typeof window;
|
|
7
|
+
let mockProvider: EvmProvider;
|
|
8
|
+
let mockLog: any;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
originalWindow = global.window;
|
|
12
|
+
mockLog = {
|
|
13
|
+
debug: vi.fn(),
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
mockProvider = {
|
|
17
|
+
request: vi.fn().mockResolvedValue(undefined),
|
|
18
|
+
} as any;
|
|
19
|
+
|
|
20
|
+
// Clear window.web3
|
|
21
|
+
delete (global.window as any).web3;
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
global.window = originalWindow;
|
|
26
|
+
vi.restoreAllMocks();
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("should create web3 shim when window.web3 does not exist", () => {
|
|
30
|
+
shimWeb3(mockProvider, mockLog);
|
|
31
|
+
|
|
32
|
+
expect((global.window as any).web3).toBeDefined();
|
|
33
|
+
expect((global.window as any).web3.currentProvider).toBe(mockProvider);
|
|
34
|
+
expect((global.window as any).web3.__isShim__).toBe(true);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should not create web3 shim when window.web3 already exists", () => {
|
|
38
|
+
const existingWeb3 = { currentProvider: {} };
|
|
39
|
+
(global.window as any).web3 = existingWeb3;
|
|
40
|
+
|
|
41
|
+
shimWeb3(mockProvider, mockLog);
|
|
42
|
+
|
|
43
|
+
expect((global.window as any).web3).toBe(existingWeb3);
|
|
44
|
+
expect((global.window as any).web3.currentProvider).not.toBe(mockProvider);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it("should log web3 shim usage when accessing non-currentProvider property", async () => {
|
|
48
|
+
shimWeb3(mockProvider, mockLog);
|
|
49
|
+
|
|
50
|
+
// Access a property other than currentProvider
|
|
51
|
+
const _ = (global.window as any).web3.someProperty;
|
|
52
|
+
|
|
53
|
+
// Wait for async logging
|
|
54
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
55
|
+
|
|
56
|
+
expect(mockProvider.request).toHaveBeenCalledWith({
|
|
57
|
+
method: "wallet_logWeb3ShimUsage",
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should not log multiple times for same property access", async () => {
|
|
62
|
+
shimWeb3(mockProvider, mockLog);
|
|
63
|
+
|
|
64
|
+
// Access property multiple times
|
|
65
|
+
const _1 = (global.window as any).web3.someProperty;
|
|
66
|
+
const _2 = (global.window as any).web3.someProperty;
|
|
67
|
+
|
|
68
|
+
// Wait for async logging
|
|
69
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
70
|
+
|
|
71
|
+
// Should only log once
|
|
72
|
+
expect(mockProvider.request).toHaveBeenCalledTimes(1);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("should handle logging errors gracefully", async () => {
|
|
76
|
+
mockProvider.request = vi.fn().mockRejectedValue(new Error("Logging failed"));
|
|
77
|
+
|
|
78
|
+
shimWeb3(mockProvider, mockLog);
|
|
79
|
+
|
|
80
|
+
// Access a property to trigger logging
|
|
81
|
+
const _ = (global.window as any).web3.someProperty;
|
|
82
|
+
|
|
83
|
+
// Wait for async logging
|
|
84
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
85
|
+
|
|
86
|
+
expect(mockLog.debug).toHaveBeenCalledWith(
|
|
87
|
+
expect.stringContaining("Failed to log web3 shim usage"),
|
|
88
|
+
expect.any(Error),
|
|
89
|
+
);
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should allow setting properties on web3 shim", () => {
|
|
93
|
+
shimWeb3(mockProvider, mockLog);
|
|
94
|
+
|
|
95
|
+
(global.window as any).web3.testProperty = "test";
|
|
96
|
+
expect((global.window as any).web3.testProperty).toBe("test");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should not log when accessing currentProvider", () => {
|
|
100
|
+
shimWeb3(mockProvider, mockLog);
|
|
101
|
+
|
|
102
|
+
const _ = (global.window as any).web3.currentProvider;
|
|
103
|
+
|
|
104
|
+
expect(mockProvider.request).not.toHaveBeenCalled();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it("should not log when accessing __isShim__ property", () => {
|
|
108
|
+
shimWeb3(mockProvider, mockLog);
|
|
109
|
+
|
|
110
|
+
const _ = (global.window as any).web3.__isShim__;
|
|
111
|
+
|
|
112
|
+
expect(mockProvider.request).not.toHaveBeenCalled();
|
|
113
|
+
});
|
|
114
|
+
});
|
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
createErrorMiddleware,
|
|
4
|
+
getRpcPromiseCallback,
|
|
5
|
+
logStreamDisconnectWarning,
|
|
6
|
+
NOOP,
|
|
7
|
+
EMITTED_NOTIFICATIONS,
|
|
8
|
+
guid,
|
|
9
|
+
} from "../evm/utils";
|
|
10
|
+
import { EventEmitter } from "events";
|
|
11
|
+
|
|
12
|
+
describe("evm/utils", () => {
|
|
13
|
+
describe("createErrorMiddleware", () => {
|
|
14
|
+
it("should validate method is a non-empty string", () => {
|
|
15
|
+
const log = {
|
|
16
|
+
error: vi.fn(),
|
|
17
|
+
};
|
|
18
|
+
const middleware = createErrorMiddleware(log as any);
|
|
19
|
+
const req = { method: "" } as any;
|
|
20
|
+
const res = {} as any;
|
|
21
|
+
const next = vi.fn((callback) => {
|
|
22
|
+
if (callback) {
|
|
23
|
+
callback(() => {});
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
middleware(req, res, next);
|
|
28
|
+
|
|
29
|
+
expect(res.error).toBeDefined();
|
|
30
|
+
expect(res.error.message).toContain("method");
|
|
31
|
+
expect(next).toHaveBeenCalled();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
it("should validate method is a string", () => {
|
|
35
|
+
const log = {
|
|
36
|
+
error: vi.fn(),
|
|
37
|
+
};
|
|
38
|
+
const middleware = createErrorMiddleware(log as any);
|
|
39
|
+
const req = { method: 123 } as any;
|
|
40
|
+
const res = {} as any;
|
|
41
|
+
const next = vi.fn((callback) => {
|
|
42
|
+
if (callback) {
|
|
43
|
+
callback(() => {});
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
middleware(req, res, next);
|
|
48
|
+
|
|
49
|
+
expect(res.error).toBeDefined();
|
|
50
|
+
expect(next).toHaveBeenCalled();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("should pass through valid requests", () => {
|
|
54
|
+
const log = {
|
|
55
|
+
error: vi.fn(),
|
|
56
|
+
};
|
|
57
|
+
const middleware = createErrorMiddleware(log as any);
|
|
58
|
+
const req = { method: "eth_getBalance" } as any;
|
|
59
|
+
const res = {} as any;
|
|
60
|
+
const next = vi.fn((callback) => {
|
|
61
|
+
if (callback) {
|
|
62
|
+
callback(() => {});
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
middleware(req, res, next);
|
|
67
|
+
|
|
68
|
+
expect(res.error).toBeUndefined();
|
|
69
|
+
expect(next).toHaveBeenCalled();
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
it("should log errors when response has error", () => {
|
|
73
|
+
const log = {
|
|
74
|
+
error: vi.fn(),
|
|
75
|
+
};
|
|
76
|
+
const middleware = createErrorMiddleware(log as any);
|
|
77
|
+
const req = { method: "eth_getBalance" } as any;
|
|
78
|
+
const res = { error: new Error("Test error") } as any;
|
|
79
|
+
const next = vi.fn((callback) => {
|
|
80
|
+
if (callback) {
|
|
81
|
+
callback(() => {});
|
|
82
|
+
}
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
middleware(req, res, next);
|
|
86
|
+
|
|
87
|
+
expect(log.error).toHaveBeenCalledWith("RPC Error: Test error", res.error);
|
|
88
|
+
expect(next).toHaveBeenCalled();
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("getRpcPromiseCallback", () => {
|
|
93
|
+
it("should reject on error", () => {
|
|
94
|
+
const resolve = vi.fn();
|
|
95
|
+
const reject = vi.fn();
|
|
96
|
+
const callback = getRpcPromiseCallback(resolve, reject);
|
|
97
|
+
const error = new Error("Test error");
|
|
98
|
+
|
|
99
|
+
callback(error, {} as any);
|
|
100
|
+
|
|
101
|
+
expect(reject).toHaveBeenCalledWith(error);
|
|
102
|
+
expect(resolve).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it("should reject on response error", () => {
|
|
106
|
+
const resolve = vi.fn();
|
|
107
|
+
const reject = vi.fn();
|
|
108
|
+
const callback = getRpcPromiseCallback(resolve, reject);
|
|
109
|
+
const responseError = new Error("Response error");
|
|
110
|
+
|
|
111
|
+
callback(null, { error: responseError } as any);
|
|
112
|
+
|
|
113
|
+
expect(reject).toHaveBeenCalledWith(responseError);
|
|
114
|
+
expect(resolve).not.toHaveBeenCalled();
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
it("should resolve with result when unwrapResult is true", () => {
|
|
118
|
+
const resolve = vi.fn();
|
|
119
|
+
const reject = vi.fn();
|
|
120
|
+
const callback = getRpcPromiseCallback(resolve, reject, true);
|
|
121
|
+
const result = { data: "test" };
|
|
122
|
+
|
|
123
|
+
callback(null, { result } as any);
|
|
124
|
+
|
|
125
|
+
expect(resolve).toHaveBeenCalledWith(result);
|
|
126
|
+
expect(reject).not.toHaveBeenCalled();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should resolve with response when unwrapResult is false", () => {
|
|
130
|
+
const resolve = vi.fn();
|
|
131
|
+
const reject = vi.fn();
|
|
132
|
+
const callback = getRpcPromiseCallback(resolve, reject, false);
|
|
133
|
+
const response = { result: { data: "test" } };
|
|
134
|
+
|
|
135
|
+
callback(null, response as any);
|
|
136
|
+
|
|
137
|
+
expect(resolve).toHaveBeenCalledWith(response);
|
|
138
|
+
expect(reject).not.toHaveBeenCalled();
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it("should resolve with response when response is array", () => {
|
|
142
|
+
const resolve = vi.fn();
|
|
143
|
+
const reject = vi.fn();
|
|
144
|
+
const callback = getRpcPromiseCallback(resolve, reject, true);
|
|
145
|
+
const response = [{ result: "test1" }, { result: "test2" }];
|
|
146
|
+
|
|
147
|
+
callback(null, response as any);
|
|
148
|
+
|
|
149
|
+
expect(resolve).toHaveBeenCalledWith(response);
|
|
150
|
+
expect(reject).not.toHaveBeenCalled();
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
describe("logStreamDisconnectWarning", () => {
|
|
155
|
+
it("should log warning message", () => {
|
|
156
|
+
const log = {
|
|
157
|
+
warn: vi.fn(),
|
|
158
|
+
};
|
|
159
|
+
const emitter = new EventEmitter();
|
|
160
|
+
const error = new Error("Connection lost");
|
|
161
|
+
|
|
162
|
+
logStreamDisconnectWarning(log as any, "test-stream", error, emitter);
|
|
163
|
+
|
|
164
|
+
expect(log.warn).toHaveBeenCalled();
|
|
165
|
+
const warnCall = log.warn.mock.calls[0][0];
|
|
166
|
+
expect(warnCall).toContain('Lost connection to "test-stream"');
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("should include error stack in warning", () => {
|
|
170
|
+
const log = {
|
|
171
|
+
warn: vi.fn(),
|
|
172
|
+
};
|
|
173
|
+
const emitter = new EventEmitter();
|
|
174
|
+
const error = new Error("Connection lost");
|
|
175
|
+
error.stack = "Error: Connection lost\n at test.js:1:1";
|
|
176
|
+
|
|
177
|
+
logStreamDisconnectWarning(log as any, "test-stream", error, emitter);
|
|
178
|
+
|
|
179
|
+
const warnCall = log.warn.mock.calls[0][0];
|
|
180
|
+
expect(warnCall).toContain(error.stack);
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it("should emit error event if emitter has error listeners", () => {
|
|
184
|
+
const log = {
|
|
185
|
+
warn: vi.fn(),
|
|
186
|
+
};
|
|
187
|
+
const emitter = new EventEmitter();
|
|
188
|
+
const errorListener = vi.fn();
|
|
189
|
+
emitter.on("error", errorListener);
|
|
190
|
+
const error = new Error("Connection lost");
|
|
191
|
+
|
|
192
|
+
logStreamDisconnectWarning(log as any, "test-stream", error, emitter);
|
|
193
|
+
|
|
194
|
+
expect(errorListener).toHaveBeenCalled();
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it("should not emit error event if emitter has no error listeners", () => {
|
|
198
|
+
const log = {
|
|
199
|
+
warn: vi.fn(),
|
|
200
|
+
};
|
|
201
|
+
const emitter = new EventEmitter();
|
|
202
|
+
const error = new Error("Connection lost");
|
|
203
|
+
|
|
204
|
+
logStreamDisconnectWarning(log as any, "test-stream", error, emitter);
|
|
205
|
+
|
|
206
|
+
expect(emitter.listenerCount("error")).toBe(0);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
it("should handle error without stack", () => {
|
|
210
|
+
const log = { warn: vi.fn() };
|
|
211
|
+
const error = new Error("Connection lost");
|
|
212
|
+
delete (error as any).stack;
|
|
213
|
+
logStreamDisconnectWarning(log as any, "stream", error, new EventEmitter());
|
|
214
|
+
expect(log.warn).toHaveBeenCalledWith(expect.stringContaining("Lost connection"));
|
|
215
|
+
expect(log.warn.mock.calls[0][0]).not.toContain("\n at ");
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
it("should not emit when emitter is null", () => {
|
|
219
|
+
const log = { warn: vi.fn() };
|
|
220
|
+
const error = new Error("Connection lost");
|
|
221
|
+
expect(() =>
|
|
222
|
+
logStreamDisconnectWarning(log as any, "stream", error, null as any),
|
|
223
|
+
).not.toThrow();
|
|
224
|
+
expect(log.warn).toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
describe("NOOP", () => {
|
|
229
|
+
it("should return undefined", () => {
|
|
230
|
+
expect(NOOP()).toBeUndefined();
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
describe("EMITTED_NOTIFICATIONS", () => {
|
|
235
|
+
it("should include eth_subscription", () => {
|
|
236
|
+
expect(EMITTED_NOTIFICATIONS).toContain("eth_subscription");
|
|
237
|
+
});
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
describe("guid", () => {
|
|
241
|
+
it("should generate a string starting with w-", () => {
|
|
242
|
+
const result = guid();
|
|
243
|
+
expect(result).toMatch(/^w-/);
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
it("should generate unique values", () => {
|
|
247
|
+
const guid1 = guid();
|
|
248
|
+
const guid2 = guid();
|
|
249
|
+
expect(guid1).not.toBe(guid2);
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
it("should generate valid hex string after w-", () => {
|
|
253
|
+
const result = guid();
|
|
254
|
+
const hexPart = result.replace("w-", "");
|
|
255
|
+
expect(hexPart).toMatch(/^[0-9a-f]+$/);
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
});
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import {
|
|
3
|
+
BitcoinProvider,
|
|
4
|
+
DogecoinProvider,
|
|
5
|
+
EvmProvider,
|
|
6
|
+
SolanaProvider,
|
|
7
|
+
TronProvider,
|
|
8
|
+
} from "../index";
|
|
9
|
+
|
|
10
|
+
describe("inject-providers", () => {
|
|
11
|
+
it("should export all providers", () => {
|
|
12
|
+
expect(BitcoinProvider).toBeDefined();
|
|
13
|
+
expect(DogecoinProvider).toBeDefined();
|
|
14
|
+
expect(EvmProvider).toBeDefined();
|
|
15
|
+
expect(SolanaProvider).toBeDefined();
|
|
16
|
+
expect(TronProvider).toBeDefined();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it("should export providers as classes or functions", () => {
|
|
20
|
+
expect(typeof BitcoinProvider).toBe("function");
|
|
21
|
+
expect(typeof DogecoinProvider).toBe("function");
|
|
22
|
+
expect(typeof EvmProvider).toBe("function");
|
|
23
|
+
expect(typeof SolanaProvider).toBe("function");
|
|
24
|
+
expect(typeof TronProvider).toBe("function");
|
|
25
|
+
});
|
|
26
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import messages from "../evm/messages";
|
|
3
|
+
|
|
4
|
+
describe("messages", () => {
|
|
5
|
+
describe("errors", () => {
|
|
6
|
+
it("should return disconnected error message", () => {
|
|
7
|
+
const message = messages.errors.disconnected();
|
|
8
|
+
expect(message).toContain("ethereum.provider");
|
|
9
|
+
expect(message).toContain("Disconnected from chain");
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("should return permanentlyDisconnected error message", () => {
|
|
13
|
+
const message = messages.errors.permanentlyDisconnected();
|
|
14
|
+
expect(message).toContain("ethereum.provider");
|
|
15
|
+
expect(message).toContain("Page reload required");
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("should return sendSiteMetadata error message", () => {
|
|
19
|
+
const message = messages.errors.sendSiteMetadata();
|
|
20
|
+
expect(message).toContain("ethereum.provider");
|
|
21
|
+
expect(message).toContain("Failed to send site metadata");
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it("should return unsupportedSync error message with method", () => {
|
|
25
|
+
const method = "eth_sendTransaction";
|
|
26
|
+
const message = messages.errors.unsupportedSync(method);
|
|
27
|
+
expect(message).toContain("ethereum.provider");
|
|
28
|
+
expect(message).toContain(method);
|
|
29
|
+
expect(message).toContain("synchronous methods");
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("should return invalidDuplexStream error message", () => {
|
|
33
|
+
const message = messages.errors.invalidDuplexStream();
|
|
34
|
+
expect(message).toContain("Must provide a Node.js-style duplex stream");
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("should return invalidOptions error message with parameters", () => {
|
|
38
|
+
const maxEventListeners = 50;
|
|
39
|
+
const shouldSendMetadata = false;
|
|
40
|
+
const message = messages.errors.invalidOptions(maxEventListeners, shouldSendMetadata);
|
|
41
|
+
expect(message).toContain("Invalid options");
|
|
42
|
+
expect(message).toContain(String(maxEventListeners));
|
|
43
|
+
expect(message).toContain(String(shouldSendMetadata));
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should return invalidRequestArgs error message", () => {
|
|
47
|
+
const message = messages.errors.invalidRequestArgs();
|
|
48
|
+
expect(message).toContain("Expected a single, non-array, object argument");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("should return invalidRequestMethod error message", () => {
|
|
52
|
+
const message = messages.errors.invalidRequestMethod();
|
|
53
|
+
expect(message).toContain("'args.method' must be a non-empty string");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("should return invalidRequestParams error message", () => {
|
|
57
|
+
const message = messages.errors.invalidRequestParams();
|
|
58
|
+
expect(message).toContain("'args.params' must be an object or array if provided");
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it("should return invalidLoggerObject error message", () => {
|
|
62
|
+
const message = messages.errors.invalidLoggerObject();
|
|
63
|
+
expect(message).toContain("'args.logger' must be an object if provided");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("should return invalidLoggerMethod error message with method", () => {
|
|
67
|
+
const method = "log";
|
|
68
|
+
const message = messages.errors.invalidLoggerMethod(method);
|
|
69
|
+
expect(message).toContain("'args.logger' must include required method");
|
|
70
|
+
expect(message).toContain(method);
|
|
71
|
+
});
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
describe("info", () => {
|
|
75
|
+
it("should return connected info message with chainId", () => {
|
|
76
|
+
const chainId = "0x1";
|
|
77
|
+
const message = messages.info.connected(chainId);
|
|
78
|
+
expect(message).toContain("ethereum.provider");
|
|
79
|
+
expect(message).toContain("Connected to chain with ID");
|
|
80
|
+
expect(message).toContain(chainId);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
describe("warnings", () => {
|
|
85
|
+
it("should return enableDeprecation warning", () => {
|
|
86
|
+
const message = messages.warnings.enableDeprecation;
|
|
87
|
+
expect(message).toContain("ethereum.provider");
|
|
88
|
+
expect(message).toContain("ethereum.enable()");
|
|
89
|
+
expect(message).toContain("deprecated");
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it("should return sendDeprecation warning", () => {
|
|
93
|
+
const message = messages.warnings.sendDeprecation;
|
|
94
|
+
expect(message).toContain("ethereum.provider");
|
|
95
|
+
expect(message).toContain("ethereum.send(...)");
|
|
96
|
+
expect(message).toContain("deprecated");
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it("should return experimentalMethods warning", () => {
|
|
100
|
+
const message = messages.warnings.experimentalMethods;
|
|
101
|
+
expect(message).toContain("ethereum.provider");
|
|
102
|
+
expect(message).toContain("non-standard, experimental methods");
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
describe("events", () => {
|
|
106
|
+
it("should return close event deprecation warning", () => {
|
|
107
|
+
const message = messages.warnings.events.close;
|
|
108
|
+
expect(message).toContain("ethereum.provider");
|
|
109
|
+
expect(message).toContain("'close'");
|
|
110
|
+
expect(message).toContain("deprecated");
|
|
111
|
+
expect(message).toContain("disconnect");
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it("should return data event deprecation warning", () => {
|
|
115
|
+
const message = messages.warnings.events.data;
|
|
116
|
+
expect(message).toContain("ethereum.provider");
|
|
117
|
+
expect(message).toContain("'data'");
|
|
118
|
+
expect(message).toContain("deprecated");
|
|
119
|
+
expect(message).toContain("message");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it("should return networkChanged event deprecation warning", () => {
|
|
123
|
+
const message = messages.warnings.events.networkChanged;
|
|
124
|
+
expect(message).toContain("ethereum.provider");
|
|
125
|
+
expect(message).toContain("'networkChanged'");
|
|
126
|
+
expect(message).toContain("deprecated");
|
|
127
|
+
expect(message).toContain("chainChanged");
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it("should return notification event deprecation warning", () => {
|
|
131
|
+
const message = messages.warnings.events.notification;
|
|
132
|
+
expect(message).toContain("ethereum.provider");
|
|
133
|
+
expect(message).toContain("'notification'");
|
|
134
|
+
expect(message).toContain("deprecated");
|
|
135
|
+
expect(message).toContain("message");
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
});
|
|
139
|
+
});
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from "vitest";
|
|
2
|
+
import { ReadyPromise } from "../utils/ready-promise";
|
|
3
|
+
|
|
4
|
+
describe("ReadyPromise", () => {
|
|
5
|
+
describe("constructor", () => {
|
|
6
|
+
it("should create instance with specified count", () => {
|
|
7
|
+
const readyPromise = new ReadyPromise(3);
|
|
8
|
+
expect(readyPromise).toBeInstanceOf(ReadyPromise);
|
|
9
|
+
});
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
describe("check and uncheck", () => {
|
|
13
|
+
it("should mark index as checked", () => {
|
|
14
|
+
const readyPromise = new ReadyPromise(2);
|
|
15
|
+
readyPromise.check(1);
|
|
16
|
+
readyPromise.check(2);
|
|
17
|
+
|
|
18
|
+
// After all checks, tasks should proceed
|
|
19
|
+
const task1 = vi.fn().mockResolvedValue("result1");
|
|
20
|
+
const promise1 = readyPromise.call(task1);
|
|
21
|
+
|
|
22
|
+
return promise1.then(() => {
|
|
23
|
+
expect(task1).toHaveBeenCalled();
|
|
24
|
+
});
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("should uncheck index", () => {
|
|
28
|
+
const readyPromise = new ReadyPromise(2);
|
|
29
|
+
readyPromise.check(1);
|
|
30
|
+
readyPromise.check(2);
|
|
31
|
+
readyPromise.uncheck(1);
|
|
32
|
+
|
|
33
|
+
// After uncheck, tasks should not proceed
|
|
34
|
+
const task1 = vi.fn().mockResolvedValue("result1");
|
|
35
|
+
const promise1 = readyPromise.call(task1);
|
|
36
|
+
|
|
37
|
+
// Wait a bit to ensure task doesn't execute
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
setTimeout(() => {
|
|
40
|
+
expect(task1).not.toHaveBeenCalled();
|
|
41
|
+
resolve(undefined);
|
|
42
|
+
}, 100);
|
|
43
|
+
});
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("should proceed only when all checks are done", async () => {
|
|
47
|
+
const readyPromise = new ReadyPromise(3);
|
|
48
|
+
const task1 = vi.fn().mockResolvedValue("result1");
|
|
49
|
+
const promise1 = readyPromise.call(task1);
|
|
50
|
+
|
|
51
|
+
// Task should not execute yet
|
|
52
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
53
|
+
expect(task1).not.toHaveBeenCalled();
|
|
54
|
+
|
|
55
|
+
// Check first two
|
|
56
|
+
readyPromise.check(1);
|
|
57
|
+
readyPromise.check(2);
|
|
58
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
59
|
+
expect(task1).not.toHaveBeenCalled();
|
|
60
|
+
|
|
61
|
+
// Check third - now should proceed
|
|
62
|
+
readyPromise.check(3);
|
|
63
|
+
await promise1;
|
|
64
|
+
expect(task1).toHaveBeenCalled();
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe("call", () => {
|
|
69
|
+
it("should execute function when all checks are done", async () => {
|
|
70
|
+
const readyPromise = new ReadyPromise(2);
|
|
71
|
+
readyPromise.check(1);
|
|
72
|
+
readyPromise.check(2);
|
|
73
|
+
|
|
74
|
+
const task = vi.fn().mockResolvedValue("result");
|
|
75
|
+
const result = await readyPromise.call(task);
|
|
76
|
+
|
|
77
|
+
expect(task).toHaveBeenCalled();
|
|
78
|
+
expect(result).toBe("result");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it("should queue multiple tasks and execute them in order", async () => {
|
|
82
|
+
const readyPromise = new ReadyPromise(1);
|
|
83
|
+
readyPromise.check(1);
|
|
84
|
+
|
|
85
|
+
const task1 = vi.fn().mockResolvedValue("result1");
|
|
86
|
+
const task2 = vi.fn().mockResolvedValue("result2");
|
|
87
|
+
const task3 = vi.fn().mockResolvedValue("result3");
|
|
88
|
+
|
|
89
|
+
const promise1 = readyPromise.call(task1);
|
|
90
|
+
const promise2 = readyPromise.call(task2);
|
|
91
|
+
const promise3 = readyPromise.call(task3);
|
|
92
|
+
|
|
93
|
+
const results = await Promise.all([promise1, promise2, promise3]);
|
|
94
|
+
|
|
95
|
+
expect(task1).toHaveBeenCalled();
|
|
96
|
+
expect(task2).toHaveBeenCalled();
|
|
97
|
+
expect(task3).toHaveBeenCalled();
|
|
98
|
+
expect(results).toEqual(["result1", "result2", "result3"]);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it("should handle async functions", async () => {
|
|
102
|
+
const readyPromise = new ReadyPromise(1);
|
|
103
|
+
readyPromise.check(1);
|
|
104
|
+
|
|
105
|
+
const task = vi.fn().mockImplementation(async () => {
|
|
106
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
107
|
+
return "async-result";
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const result = await readyPromise.call(task);
|
|
111
|
+
expect(result).toBe("async-result");
|
|
112
|
+
});
|
|
113
|
+
});
|
|
114
|
+
});
|