@3rd-eye-labs/openmm 0.1.6 → 0.1.9

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.
Files changed (216) hide show
  1. package/dist/api/routes/health.js +1 -1
  2. package/dist/api/routes/health.js.map +1 -1
  3. package/dist/cli/commands/grid.d.ts +3 -0
  4. package/dist/cli/commands/grid.d.ts.map +1 -0
  5. package/dist/cli/commands/grid.js +103 -0
  6. package/dist/cli/commands/grid.js.map +1 -0
  7. package/dist/cli/commands/multi-trade.d.ts +3 -0
  8. package/dist/cli/commands/multi-trade.d.ts.map +1 -0
  9. package/dist/cli/commands/multi-trade.js +175 -0
  10. package/dist/cli/commands/multi-trade.js.map +1 -0
  11. package/dist/cli/commands/trade.js +1 -1
  12. package/dist/cli/exchange-factory.d.ts +8 -0
  13. package/dist/cli/exchange-factory.d.ts.map +1 -1
  14. package/dist/cli/exchange-factory.js +16 -0
  15. package/dist/cli/exchange-factory.js.map +1 -1
  16. package/dist/cli/pool-discovery.d.ts +56 -0
  17. package/dist/cli/pool-discovery.d.ts.map +1 -0
  18. package/dist/cli/pool-discovery.js +283 -0
  19. package/dist/cli/pool-discovery.js.map +1 -0
  20. package/dist/config/environment.d.ts +23 -0
  21. package/dist/config/environment.d.ts.map +1 -1
  22. package/dist/config/environment.js +99 -59
  23. package/dist/config/environment.js.map +1 -1
  24. package/dist/core/price-aggregation/price-cache.d.ts +55 -0
  25. package/dist/core/price-aggregation/price-cache.d.ts.map +1 -0
  26. package/dist/core/price-aggregation/price-cache.js +152 -0
  27. package/dist/core/price-aggregation/price-cache.js.map +1 -0
  28. package/dist/examples/mexc-connector-comprehensive-test.d.ts +15 -0
  29. package/dist/examples/mexc-connector-comprehensive-test.d.ts.map +1 -0
  30. package/dist/examples/mexc-connector-comprehensive-test.js +514 -0
  31. package/dist/examples/mexc-connector-comprehensive-test.js.map +1 -0
  32. package/dist/examples/mexc-order-update-test.d.ts +4 -0
  33. package/dist/examples/mexc-order-update-test.d.ts.map +1 -0
  34. package/dist/examples/mexc-order-update-test.js +186 -0
  35. package/dist/examples/mexc-order-update-test.js.map +1 -0
  36. package/dist/examples/mexc-test.d.ts +9 -0
  37. package/dist/examples/mexc-test.d.ts.map +1 -0
  38. package/dist/examples/mexc-test.js +218 -0
  39. package/dist/examples/mexc-test.js.map +1 -0
  40. package/dist/examples/mexc-trades-debug.d.ts +2 -0
  41. package/dist/examples/mexc-trades-debug.d.ts.map +1 -0
  42. package/dist/examples/mexc-trades-debug.js +101 -0
  43. package/dist/examples/mexc-trades-debug.js.map +1 -0
  44. package/dist/examples/mexc-trades-subscription-debug.d.ts +2 -0
  45. package/dist/examples/mexc-trades-subscription-debug.d.ts.map +1 -0
  46. package/dist/examples/mexc-trades-subscription-debug.js +150 -0
  47. package/dist/examples/mexc-trades-subscription-debug.js.map +1 -0
  48. package/dist/examples/mexc-websocket-test.d.ts +8 -0
  49. package/dist/examples/mexc-websocket-test.d.ts.map +1 -0
  50. package/dist/examples/mexc-websocket-test.js +115 -0
  51. package/dist/examples/mexc-websocket-test.js.map +1 -0
  52. package/dist/examples/test-protobuf-status-detection.d.ts +9 -0
  53. package/dist/examples/test-protobuf-status-detection.d.ts.map +1 -0
  54. package/dist/examples/test-protobuf-status-detection.js +83 -0
  55. package/dist/examples/test-protobuf-status-detection.js.map +1 -0
  56. package/dist/exchanges/base-exchange-connector.d.ts +33 -0
  57. package/dist/exchanges/base-exchange-connector.d.ts.map +1 -0
  58. package/dist/exchanges/base-exchange-connector.js +55 -0
  59. package/dist/exchanges/base-exchange-connector.js.map +1 -0
  60. package/dist/exchanges/kraken/test-kraken-websocket.d.ts +19 -0
  61. package/dist/exchanges/kraken/test-kraken-websocket.d.ts.map +1 -0
  62. package/dist/exchanges/kraken/test-kraken-websocket.js +413 -0
  63. package/dist/exchanges/kraken/test-kraken-websocket.js.map +1 -0
  64. package/dist/mcp/resources/index.d.ts +3 -0
  65. package/dist/mcp/resources/index.d.ts.map +1 -0
  66. package/dist/mcp/resources/index.js +11 -0
  67. package/dist/mcp/resources/index.js.map +1 -0
  68. package/dist/mcp/server.d.ts +4 -0
  69. package/dist/mcp/server.d.ts.map +1 -0
  70. package/dist/mcp/server.js +29 -0
  71. package/dist/mcp/server.js.map +1 -0
  72. package/dist/mcp/tools/index.d.ts +3 -0
  73. package/dist/mcp/tools/index.d.ts.map +1 -0
  74. package/dist/mcp/tools/index.js +12 -0
  75. package/dist/mcp/tools/index.js.map +1 -0
  76. package/dist/tests/fixtures/test-helpers.d.ts +5 -0
  77. package/dist/tests/fixtures/test-helpers.d.ts.map +1 -0
  78. package/dist/tests/fixtures/test-helpers.js +8 -0
  79. package/dist/tests/fixtures/test-helpers.js.map +1 -0
  80. package/dist/tests/integration/exchanges/mexc/mexc-integration.test.d.ts +2 -0
  81. package/dist/tests/integration/exchanges/mexc/mexc-integration.test.d.ts.map +1 -0
  82. package/dist/tests/integration/exchanges/mexc/mexc-integration.test.js +237 -0
  83. package/dist/tests/integration/exchanges/mexc/mexc-integration.test.js.map +1 -0
  84. package/dist/tests/integration/price-aggregation/cardano-price-service.test.d.ts +2 -0
  85. package/dist/tests/integration/price-aggregation/cardano-price-service.test.d.ts.map +1 -0
  86. package/dist/tests/integration/price-aggregation/cardano-price-service.test.js +57 -0
  87. package/dist/tests/integration/price-aggregation/cardano-price-service.test.js.map +1 -0
  88. package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.d.ts +2 -0
  89. package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.d.ts.map +1 -0
  90. package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.js +141 -0
  91. package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.js.map +1 -0
  92. package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.d.ts +2 -0
  93. package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.d.ts.map +1 -0
  94. package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.js +375 -0
  95. package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.js.map +1 -0
  96. package/dist/tests/unit/cli/exchange-factory.test.d.ts +2 -0
  97. package/dist/tests/unit/cli/exchange-factory.test.d.ts.map +1 -0
  98. package/dist/tests/unit/cli/exchange-factory.test.js +148 -0
  99. package/dist/tests/unit/cli/exchange-factory.test.js.map +1 -0
  100. package/dist/tests/unit/config/environment.test.d.ts +2 -0
  101. package/dist/tests/unit/config/environment.test.d.ts.map +1 -0
  102. package/dist/tests/unit/config/environment.test.js +158 -0
  103. package/dist/tests/unit/config/environment.test.js.map +1 -0
  104. package/dist/tests/unit/config/launcher-config.test.d.ts +2 -0
  105. package/dist/tests/unit/config/launcher-config.test.d.ts.map +1 -0
  106. package/dist/tests/unit/config/launcher-config.test.js +117 -0
  107. package/dist/tests/unit/config/launcher-config.test.js.map +1 -0
  108. package/dist/tests/unit/config/price-aggregation.test.d.ts +2 -0
  109. package/dist/tests/unit/config/price-aggregation.test.d.ts.map +1 -0
  110. package/dist/tests/unit/config/price-aggregation.test.js +144 -0
  111. package/dist/tests/unit/config/price-aggregation.test.js.map +1 -0
  112. package/dist/tests/unit/core/exchange/base-exchange-connector.test.d.ts +2 -0
  113. package/dist/tests/unit/core/exchange/base-exchange-connector.test.d.ts.map +1 -0
  114. package/dist/tests/unit/core/exchange/base-exchange-connector.test.js +191 -0
  115. package/dist/tests/unit/core/exchange/base-exchange-connector.test.js.map +1 -0
  116. package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.d.ts +2 -0
  117. package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.d.ts.map +1 -0
  118. package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.js +324 -0
  119. package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.js.map +1 -0
  120. package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.d.ts +2 -0
  121. package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.d.ts.map +1 -0
  122. package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.js +177 -0
  123. package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.js.map +1 -0
  124. package/dist/tests/unit/core/price-aggregation/iris-api-client.test.d.ts +2 -0
  125. package/dist/tests/unit/core/price-aggregation/iris-api-client.test.d.ts.map +1 -0
  126. package/dist/tests/unit/core/price-aggregation/iris-api-client.test.js +168 -0
  127. package/dist/tests/unit/core/price-aggregation/iris-api-client.test.js.map +1 -0
  128. package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.d.ts +2 -0
  129. package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.d.ts.map +1 -0
  130. package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.js +217 -0
  131. package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.js.map +1 -0
  132. package/dist/tests/unit/core/price-aggregation/price-calculator.test.d.ts +2 -0
  133. package/dist/tests/unit/core/price-aggregation/price-calculator.test.d.ts.map +1 -0
  134. package/dist/tests/unit/core/price-aggregation/price-calculator.test.js +229 -0
  135. package/dist/tests/unit/core/price-aggregation/price-calculator.test.js.map +1 -0
  136. package/dist/tests/unit/core/risk-management/risk-manager.test.d.ts +2 -0
  137. package/dist/tests/unit/core/risk-management/risk-manager.test.d.ts.map +1 -0
  138. package/dist/tests/unit/core/risk-management/risk-manager.test.js +194 -0
  139. package/dist/tests/unit/core/risk-management/risk-manager.test.js.map +1 -0
  140. package/dist/tests/unit/core/strategy/base-strategy.test.d.ts +2 -0
  141. package/dist/tests/unit/core/strategy/base-strategy.test.d.ts.map +1 -0
  142. package/dist/tests/unit/core/strategy/base-strategy.test.js +254 -0
  143. package/dist/tests/unit/core/strategy/base-strategy.test.js.map +1 -0
  144. package/dist/tests/unit/core/strategy/strategy-factory.test.d.ts +2 -0
  145. package/dist/tests/unit/core/strategy/strategy-factory.test.d.ts.map +1 -0
  146. package/dist/tests/unit/core/strategy/strategy-factory.test.js +213 -0
  147. package/dist/tests/unit/core/strategy/strategy-factory.test.js.map +1 -0
  148. package/dist/tests/unit/exchanges/mexc/mexc-auth.test.d.ts +2 -0
  149. package/dist/tests/unit/exchanges/mexc/mexc-auth.test.d.ts.map +1 -0
  150. package/dist/tests/unit/exchanges/mexc/mexc-auth.test.js +452 -0
  151. package/dist/tests/unit/exchanges/mexc/mexc-auth.test.js.map +1 -0
  152. package/dist/tests/unit/exchanges/mexc/mexc-connector.test.d.ts +2 -0
  153. package/dist/tests/unit/exchanges/mexc/mexc-connector.test.d.ts.map +1 -0
  154. package/dist/tests/unit/exchanges/mexc/mexc-connector.test.js +1419 -0
  155. package/dist/tests/unit/exchanges/mexc/mexc-connector.test.js.map +1 -0
  156. package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.d.ts +2 -0
  157. package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.d.ts.map +1 -0
  158. package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.js +435 -0
  159. package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.js.map +1 -0
  160. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.d.ts +2 -0
  161. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.d.ts.map +1 -0
  162. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.js +314 -0
  163. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.js.map +1 -0
  164. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.d.ts +2 -0
  165. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.d.ts.map +1 -0
  166. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.js +178 -0
  167. package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.js.map +1 -0
  168. package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.d.ts +2 -0
  169. package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.d.ts.map +1 -0
  170. package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.js +502 -0
  171. package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.js.map +1 -0
  172. package/dist/tests/unit/exchanges/mexc/mexc-utils.test.d.ts +2 -0
  173. package/dist/tests/unit/exchanges/mexc/mexc-utils.test.d.ts.map +1 -0
  174. package/dist/tests/unit/exchanges/mexc/mexc-utils.test.js +317 -0
  175. package/dist/tests/unit/exchanges/mexc/mexc-utils.test.js.map +1 -0
  176. package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.d.ts +2 -0
  177. package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.d.ts.map +1 -0
  178. package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.js +843 -0
  179. package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.js.map +1 -0
  180. package/dist/tests/unit/strategies/grid/grid-calculator.test.d.ts +2 -0
  181. package/dist/tests/unit/strategies/grid/grid-calculator.test.d.ts.map +1 -0
  182. package/dist/tests/unit/strategies/grid/grid-calculator.test.js +67 -0
  183. package/dist/tests/unit/strategies/grid/grid-calculator.test.js.map +1 -0
  184. package/dist/tests/unit/strategies/grid/grid-order-manager.test.d.ts +2 -0
  185. package/dist/tests/unit/strategies/grid/grid-order-manager.test.d.ts.map +1 -0
  186. package/dist/tests/unit/strategies/grid/grid-order-manager.test.js +211 -0
  187. package/dist/tests/unit/strategies/grid/grid-order-manager.test.js.map +1 -0
  188. package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.d.ts +2 -0
  189. package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.d.ts.map +1 -0
  190. package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.js +197 -0
  191. package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.js.map +1 -0
  192. package/dist/tests/unit/strategies/grid/grid-strategy.test.d.ts +2 -0
  193. package/dist/tests/unit/strategies/grid/grid-strategy.test.d.ts.map +1 -0
  194. package/dist/tests/unit/strategies/grid/grid-strategy.test.js +429 -0
  195. package/dist/tests/unit/strategies/grid/grid-strategy.test.js.map +1 -0
  196. package/dist/tests/unit/utils/logger.test.d.ts +2 -0
  197. package/dist/tests/unit/utils/logger.test.d.ts.map +1 -0
  198. package/dist/tests/unit/utils/logger.test.js +260 -0
  199. package/dist/tests/unit/utils/logger.test.js.map +1 -0
  200. package/dist/tests/unit/utils/symbol-utils.test.d.ts +2 -0
  201. package/dist/tests/unit/utils/symbol-utils.test.d.ts.map +1 -0
  202. package/dist/tests/unit/utils/symbol-utils.test.js +178 -0
  203. package/dist/tests/unit/utils/symbol-utils.test.js.map +1 -0
  204. package/dist/types/price-aggregation.d.ts +31 -0
  205. package/dist/types/price-aggregation.d.ts.map +1 -0
  206. package/dist/types/price-aggregation.js +6 -0
  207. package/dist/types/price-aggregation.js.map +1 -0
  208. package/dist/utils/crypto.d.ts +15 -0
  209. package/dist/utils/crypto.d.ts.map +1 -0
  210. package/dist/utils/crypto.js +50 -0
  211. package/dist/utils/crypto.js.map +1 -0
  212. package/dist/utils/validation.d.ts +36 -0
  213. package/dist/utils/validation.d.ts.map +1 -0
  214. package/dist/utils/validation.js +174 -0
  215. package/dist/utils/validation.js.map +1 -0
  216. package/package.json +1 -1
@@ -0,0 +1,1419 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const mexc_connector_1 = require("../../../../exchanges/mexc/mexc-connector");
4
+ const mexc_auth_1 = require("../../../../exchanges/mexc/mexc-auth");
5
+ const mexc_websocket_1 = require("../../../../exchanges/mexc/mexc-websocket");
6
+ const mexc_user_stream_1 = require("../../../../exchanges/mexc/mexc-user-stream");
7
+ const mexc_utils_1 = require("../../../../exchanges/mexc/mexc-utils");
8
+ const mexc_data_mapper_1 = require("../../../../exchanges/mexc/mexc-data-mapper");
9
+ const test_helpers_1 = require("../../../fixtures/test-helpers");
10
+ jest.mock('../../../../exchanges/mexc/mexc-auth');
11
+ jest.mock('../../../../exchanges/mexc/mexc-websocket');
12
+ jest.mock('../../../../exchanges/mexc/mexc-user-stream');
13
+ jest.mock('../../../../exchanges/mexc/mexc-utils');
14
+ jest.mock('../../../../exchanges/mexc/mexc-data-mapper');
15
+ jest.mock('../../../../utils');
16
+ const MockedMexcAuth = mexc_auth_1.MexcAuth;
17
+ const MockedMexcWebSocket = mexc_websocket_1.MexcWebSocket;
18
+ const MockedMexcUserStream = mexc_user_stream_1.MexcUserStream;
19
+ const MockedMexcUtils = mexc_utils_1.MexcUtils;
20
+ const MockedMexcDataMapper = mexc_data_mapper_1.MexcDataMapper;
21
+ class TestableMexcConnector extends mexc_connector_1.MexcConnector {
22
+ constructor(auth, webSocket, userStream) {
23
+ super();
24
+ this.testAuth = auth;
25
+ this.testWebSocket = webSocket;
26
+ this.testUserStream = userStream;
27
+ }
28
+ getCredentials() {
29
+ return {
30
+ apiKey: test_helpers_1.mockCredentials.apiKey,
31
+ secret: test_helpers_1.mockCredentials.apiSecret
32
+ };
33
+ }
34
+ handleError(error, operation) {
35
+ console.warn(`Test handleError called: ${operation}`, error);
36
+ const shouldThrowOperations = [
37
+ 'connect', 'getBalance', 'createOrder', 'cancelOrder', 'cancelAllOrders',
38
+ 'getTicker', 'getOrderBook', 'getRecentTrades', 'getOrder', 'getOpenOrders',
39
+ 'connectWebSocket', 'disconnectWebSocket', 'connectUserDataStream', 'subscribeTicker'
40
+ ];
41
+ const errorString = error instanceof Error ? error.message : String(error);
42
+ const shouldThrowMessages = [
43
+ 'WebSocket not connected', 'User stream not initialized',
44
+ 'MEXC connector not authenticated', 'Invalid MEXC credentials'
45
+ ];
46
+ const gracefulSubscriptions = ['subscribeUserOrders', 'subscribeUserTrades', 'subscribeOrderBook', 'subscribeTrades', 'subscribeOrders'];
47
+ const isSubscriptionError = gracefulSubscriptions.includes(operation) && errorString.includes('Subscribe failed');
48
+ const isUnsubscribeError = operation === 'unsubscribe' && errorString.includes('Unsubscribe failed');
49
+ const isDisconnectError = operation === 'disconnectUserDataStream' && errorString.includes('Disconnect failed');
50
+ const isLoggerError = errorString.includes('Cannot read properties of undefined (reading \'warn\')');
51
+ if (isSubscriptionError || isUnsubscribeError || isDisconnectError || isLoggerError) {
52
+ return undefined;
53
+ }
54
+ if (shouldThrowOperations.includes(operation) ||
55
+ shouldThrowMessages.some(msg => errorString.includes(msg))) {
56
+ throw error;
57
+ }
58
+ return undefined;
59
+ }
60
+ async connect() {
61
+ try {
62
+ const credentials = this.getCredentials();
63
+ if (this.testAuth) {
64
+ this['auth'] = this.testAuth;
65
+ }
66
+ else {
67
+ this['auth'] = new mexc_auth_1.MexcAuth(credentials, 'https://api.mexc.com/api/v3');
68
+ }
69
+ if (this.testUserStream) {
70
+ this['userStream'] = this.testUserStream;
71
+ }
72
+ else {
73
+ this['userStream'] = new mexc_user_stream_1.MexcUserStream((endpoint, params, method) => this['auth'].makeRequest(endpoint, params, method));
74
+ }
75
+ if (!this['auth'].validateCredentials()) {
76
+ throw new Error('Invalid MEXC credentials');
77
+ }
78
+ this['connected'] = true;
79
+ }
80
+ catch (error) {
81
+ this['connected'] = false;
82
+ this.handleError(error, 'connect');
83
+ }
84
+ }
85
+ async connectWebSocket() {
86
+ if (!this.testWebSocket && !this['ws']) {
87
+ this['ws'] = new mexc_websocket_1.MexcWebSocket();
88
+ }
89
+ else if (this.testWebSocket && !this['ws']) {
90
+ this['ws'] = this.testWebSocket;
91
+ }
92
+ await this['ws'].connectWebSocket();
93
+ }
94
+ isConnected() {
95
+ return this['connected'];
96
+ }
97
+ hasAuth() {
98
+ return !!this['auth'];
99
+ }
100
+ hasUserStream() {
101
+ return !!this['userStream'];
102
+ }
103
+ async testMakeRequest(endpoint, params = {}, method = 'GET') {
104
+ if (!this['auth']) {
105
+ throw new Error('MEXC connector not authenticated');
106
+ }
107
+ return this['auth'].makeRequest(endpoint, params, method);
108
+ }
109
+ async testMakePublicRequest(endpoint, params = {}) {
110
+ if (!this['auth']) {
111
+ throw new Error('MEXC connector not authenticated');
112
+ }
113
+ return this['auth'].makePublicRequest(endpoint, params);
114
+ }
115
+ }
116
+ describe('MexcConnector', () => {
117
+ let connector;
118
+ let mockAuth;
119
+ let mockWebSocket;
120
+ let mockUserStream;
121
+ let mockDataMapper;
122
+ beforeEach(() => {
123
+ jest.clearAllMocks();
124
+ jest.spyOn(mexc_data_mapper_1.MexcDataMapper, 'mapToOrderStatus').mockImplementation((status) => {
125
+ switch (status.toUpperCase()) {
126
+ case 'NEW': return 'open';
127
+ case 'FILLED': return 'filled';
128
+ case 'CANCELED':
129
+ case 'CANCELLED': return 'cancelled';
130
+ case 'REJECTED': return 'rejected';
131
+ default: return 'open';
132
+ }
133
+ });
134
+ mockAuth = {
135
+ validateCredentials: jest.fn().mockReturnValue(true),
136
+ makeRequest: jest.fn(),
137
+ makePublicRequest: jest.fn(),
138
+ createPublicHeaders: jest.fn().mockReturnValue({}),
139
+ };
140
+ mockWebSocket = {
141
+ connectWebSocket: jest.fn(),
142
+ disconnectWebSocket: jest.fn(),
143
+ subscribeTicker: jest.fn(),
144
+ subscribeOrderBook: jest.fn(),
145
+ subscribeTrades: jest.fn(),
146
+ subscribeOrders: jest.fn(),
147
+ unsubscribe: jest.fn(),
148
+ isConnected: jest.fn(),
149
+ getWebSocketStatus: jest.fn(),
150
+ subscribeToUserData: jest.fn(),
151
+ };
152
+ mockUserStream = {
153
+ connectUserDataStream: jest.fn(),
154
+ disconnectUserDataStream: jest.fn(),
155
+ subscribeUserOrders: jest.fn(),
156
+ subscribeUserTrades: jest.fn(),
157
+ isUserDataStreamConnected: jest.fn(),
158
+ getListenKey: jest.fn(),
159
+ keepAliveListenKey: jest.fn(),
160
+ deleteListenKey: jest.fn(),
161
+ };
162
+ mockDataMapper = {
163
+ mapOrder: jest.fn().mockReturnValue({
164
+ id: 'mock-order-id',
165
+ symbol: 'BTCUSDT',
166
+ type: 'limit',
167
+ side: 'buy',
168
+ amount: 1.0,
169
+ price: 50000,
170
+ filled: 0,
171
+ remaining: 1.0,
172
+ status: 'open',
173
+ timestamp: Date.now()
174
+ }),
175
+ mapAccountBalances: jest.fn().mockReturnValue({}),
176
+ mapTicker: jest.fn().mockReturnValue({
177
+ symbol: 'BTCUSDT',
178
+ last: 50000,
179
+ bid: 49999,
180
+ ask: 50001,
181
+ baseVolume: 1000,
182
+ timestamp: Date.now()
183
+ }),
184
+ mapOrderBook: jest.fn().mockReturnValue({
185
+ symbol: 'BTC/USDT',
186
+ bids: [[49999, 1.0]],
187
+ asks: [[50001, 1.0]],
188
+ timestamp: Date.now()
189
+ }),
190
+ mapTrade: jest.fn().mockReturnValue({
191
+ id: 'trade-1',
192
+ symbol: 'BTC/USDT',
193
+ side: 'buy',
194
+ amount: 1.0,
195
+ price: 50000,
196
+ timestamp: Date.now()
197
+ }),
198
+ };
199
+ MockedMexcAuth.mockImplementation(() => mockAuth);
200
+ MockedMexcWebSocket.mockImplementation(() => mockWebSocket);
201
+ MockedMexcUserStream.mockImplementation(() => mockUserStream);
202
+ MockedMexcDataMapper.mockImplementation(() => mockDataMapper);
203
+ connector = new TestableMexcConnector(mockAuth, mockWebSocket, mockUserStream);
204
+ });
205
+ describe('constructor', () => {
206
+ it('should initialize with correct base URL', () => {
207
+ expect(connector).toBeDefined();
208
+ expect(connector).toBeInstanceOf(mexc_connector_1.MexcConnector);
209
+ });
210
+ });
211
+ describe('connect', () => {
212
+ it('should successfully connect with valid credentials', async () => {
213
+ await connector.connect();
214
+ expect(mockAuth.validateCredentials).toHaveBeenCalled();
215
+ expect(connector.isConnected()).toBe(true);
216
+ expect(connector.hasAuth()).toBe(true);
217
+ expect(connector.hasUserStream()).toBe(true);
218
+ });
219
+ it('should fail to connect with invalid credentials', async () => {
220
+ mockAuth.validateCredentials.mockReturnValue(false);
221
+ await expect(connector.connect()).rejects.toThrow('Invalid MEXC credentials');
222
+ expect(connector.isConnected()).toBe(false);
223
+ });
224
+ it('should handle connection errors', async () => {
225
+ const error = new Error('Connection failed');
226
+ mockAuth.validateCredentials.mockImplementation(() => {
227
+ throw error;
228
+ });
229
+ await expect(connector.connect()).rejects.toThrow('Connection failed');
230
+ expect(connector.isConnected()).toBe(false);
231
+ });
232
+ });
233
+ describe('disconnect', () => {
234
+ beforeEach(async () => {
235
+ await connector.connect();
236
+ await connector.connectWebSocket();
237
+ });
238
+ it('should disconnect all components', async () => {
239
+ mockWebSocket.disconnectWebSocket.mockResolvedValue(undefined);
240
+ mockUserStream.disconnectUserDataStream.mockResolvedValue(undefined);
241
+ await connector.disconnect();
242
+ expect(mockWebSocket.disconnectWebSocket).toHaveBeenCalled();
243
+ expect(mockUserStream.disconnectUserDataStream).toHaveBeenCalled();
244
+ expect(connector.isConnected()).toBe(false);
245
+ expect(connector.hasAuth()).toBe(false);
246
+ expect(connector.hasUserStream()).toBe(false);
247
+ });
248
+ });
249
+ describe('getBalance', () => {
250
+ beforeEach(async () => {
251
+ await connector.connect();
252
+ });
253
+ it('should return all balances when no asset specified', async () => {
254
+ const mockAccountData = {
255
+ balances: [
256
+ { asset: 'BTC', free: '1.0', locked: '0.5' },
257
+ { asset: 'USDT', free: '1000.0', locked: '0.0' },
258
+ { asset: 'ETH', free: '0.0', locked: '0.0' }
259
+ ]
260
+ };
261
+ mockAuth.makeRequest.mockResolvedValue(mockAccountData);
262
+ mockDataMapper.mapAccountBalances.mockReturnValue({
263
+ BTC: {
264
+ asset: 'BTC',
265
+ free: 1.0,
266
+ used: 0.5,
267
+ total: 1.5,
268
+ available: 1.0
269
+ },
270
+ USDT: {
271
+ asset: 'USDT',
272
+ free: 1000.0,
273
+ used: 0.0,
274
+ total: 1000.0,
275
+ available: 1000.0
276
+ }
277
+ });
278
+ const result = await connector.getBalance();
279
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/account', {}, 'GET');
280
+ expect(result).toEqual({
281
+ BTC: {
282
+ asset: 'BTC',
283
+ free: 1.0,
284
+ used: 0.5,
285
+ total: 1.5,
286
+ available: 1.0
287
+ },
288
+ USDT: {
289
+ asset: 'USDT',
290
+ free: 1000.0,
291
+ used: 0.0,
292
+ total: 1000.0,
293
+ available: 1000.0
294
+ }
295
+ });
296
+ });
297
+ it('should return specific balance when asset specified', async () => {
298
+ const mockAccountData = {
299
+ balances: [
300
+ { asset: 'BTC', free: '1.0', locked: '0.5' }
301
+ ]
302
+ };
303
+ mockDataMapper.mapAccountBalances.mockReturnValueOnce({
304
+ BTC: {
305
+ asset: 'BTC',
306
+ free: 1.0,
307
+ used: 0.5,
308
+ total: 1.5,
309
+ available: 1.0
310
+ }
311
+ });
312
+ mockAuth.makeRequest.mockResolvedValue(mockAccountData);
313
+ const result = await connector.getBalance('BTC');
314
+ expect(result).toEqual({
315
+ asset: 'BTC',
316
+ free: 1.0,
317
+ used: 0.5,
318
+ total: 1.5,
319
+ available: 1.0
320
+ });
321
+ });
322
+ it('should return zero balance when asset not found', async () => {
323
+ const mockAccountData = { balances: [] };
324
+ mockAuth.makeRequest.mockResolvedValue(mockAccountData);
325
+ const result = await connector.getBalance('ETH');
326
+ expect(result).toEqual({
327
+ asset: 'ETH',
328
+ free: 0,
329
+ used: 0,
330
+ total: 0,
331
+ available: 0
332
+ });
333
+ });
334
+ it('should handle API errors', async () => {
335
+ const error = new Error('API Error');
336
+ mockAuth.makeRequest.mockRejectedValue(error);
337
+ await expect(connector.getBalance()).rejects.toThrow('API Error');
338
+ });
339
+ it('should require authentication', async () => {
340
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
341
+ await expect(unauthenticatedConnector.getBalance()).rejects.toThrow('MEXC connector not authenticated');
342
+ });
343
+ });
344
+ describe('createOrder', () => {
345
+ beforeEach(async () => {
346
+ await connector.connect();
347
+ });
348
+ it('should create a limit order successfully', async () => {
349
+ const mockOrderParams = {
350
+ symbol: 'BTCUSDT',
351
+ side: 'BUY',
352
+ type: 'LIMIT',
353
+ quantity: '1.5',
354
+ price: '50000',
355
+ timeInForce: 'GTC'
356
+ };
357
+ const mockApiResponse = { orderId: '12345' };
358
+ MockedMexcUtils.createOrderParams.mockReturnValue(mockOrderParams);
359
+ mockAuth.makeRequest.mockResolvedValue(mockApiResponse);
360
+ mockDataMapper.mapOrder.mockReturnValueOnce({
361
+ id: '12345',
362
+ symbol: 'BTCUSDT',
363
+ type: 'limit',
364
+ side: 'buy',
365
+ amount: 1.5,
366
+ price: 50000,
367
+ filled: 0,
368
+ remaining: 1.5,
369
+ status: 'open',
370
+ timestamp: Date.now()
371
+ });
372
+ const result = await connector.createOrder('BTC/USDT', 'limit', 'buy', 1.5, 50000);
373
+ expect(MockedMexcUtils.createOrderParams).toHaveBeenCalledWith('BTC/USDT', 'limit', 'buy', 1.5, 50000);
374
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/order', mockOrderParams, 'POST');
375
+ expect(result).toEqual(expect.objectContaining({
376
+ id: '12345',
377
+ symbol: 'BTCUSDT',
378
+ type: 'limit',
379
+ side: 'buy',
380
+ amount: 1.5,
381
+ price: 50000,
382
+ status: 'open'
383
+ }));
384
+ });
385
+ it('should create a market order successfully', async () => {
386
+ const mockOrderParams = {
387
+ symbol: 'BTCUSDT',
388
+ side: 'SELL',
389
+ type: 'MARKET',
390
+ quantity: '1.0'
391
+ };
392
+ const mockApiResponse = { orderId: '54321' };
393
+ MockedMexcUtils.createOrderParams.mockReturnValue(mockOrderParams);
394
+ mockAuth.makeRequest.mockResolvedValue(mockApiResponse);
395
+ mockDataMapper.mapOrder.mockReturnValueOnce({
396
+ id: '54321',
397
+ symbol: 'BTCUSDT',
398
+ type: 'market',
399
+ side: 'sell',
400
+ amount: 1.0,
401
+ price: 0,
402
+ filled: 0,
403
+ remaining: 1.0,
404
+ status: 'open',
405
+ timestamp: Date.now()
406
+ });
407
+ const result = await connector.createOrder('BTC/USDT', 'market', 'sell', 1.0);
408
+ expect(MockedMexcUtils.createOrderParams).toHaveBeenCalledWith('BTC/USDT', 'market', 'sell', 1.0, undefined);
409
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/order', mockOrderParams, 'POST');
410
+ expect(result).toEqual(expect.objectContaining({
411
+ id: '54321',
412
+ type: 'market',
413
+ side: 'sell',
414
+ amount: 1
415
+ }));
416
+ });
417
+ it('should handle order creation errors', async () => {
418
+ const error = new Error('Insufficient balance');
419
+ MockedMexcUtils.createOrderParams.mockReturnValue({});
420
+ mockAuth.makeRequest.mockRejectedValue(error);
421
+ await expect(connector.createOrder('BTC/USDT', 'limit', 'buy', 1.5, 50000)).rejects.toThrow('Insufficient balance');
422
+ });
423
+ it('should require authentication', async () => {
424
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
425
+ await expect(unauthenticatedConnector.createOrder('BTC/USDT', 'limit', 'buy', 1.5, 50000)).rejects.toThrow('MEXC connector not authenticated');
426
+ });
427
+ });
428
+ describe('cancelOrder', () => {
429
+ beforeEach(async () => {
430
+ await connector.connect();
431
+ });
432
+ it('should cancel an order successfully', async () => {
433
+ mockAuth.makeRequest.mockResolvedValue({});
434
+ await connector.cancelOrder('12345', 'BTC/USDT');
435
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/order', {
436
+ symbol: 'BTCUSDT',
437
+ orderId: '12345'
438
+ }, 'DELETE');
439
+ });
440
+ it('should handle cancellation errors', async () => {
441
+ const error = new Error('Order not found');
442
+ mockAuth.makeRequest.mockRejectedValue(error);
443
+ await expect(connector.cancelOrder('12345', 'BTC/USDT')).rejects.toThrow('Order not found');
444
+ });
445
+ it('should require authentication', async () => {
446
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
447
+ await expect(unauthenticatedConnector.cancelOrder('12345', 'BTC/USDT')).rejects.toThrow('MEXC connector not authenticated');
448
+ });
449
+ });
450
+ describe('cancelAllOrders', () => {
451
+ beforeEach(async () => {
452
+ await connector.connect();
453
+ });
454
+ it('should cancel all orders for a symbol successfully', async () => {
455
+ mockAuth.makeRequest.mockResolvedValue([
456
+ { orderId: '12345', status: 'CANCELED' },
457
+ { orderId: '67890', status: 'CANCELED' }
458
+ ]);
459
+ await connector.cancelAllOrders('INDY/USDT');
460
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/openOrders', {
461
+ symbol: 'INDYUSDT'
462
+ }, 'DELETE');
463
+ });
464
+ it('should handle bulk cancellation errors', async () => {
465
+ const error = new Error('Symbol not found');
466
+ mockAuth.makeRequest.mockRejectedValue(error);
467
+ await expect(connector.cancelAllOrders('INDY/USDT')).rejects.toThrow('Symbol not found');
468
+ });
469
+ it('should require authentication', async () => {
470
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
471
+ await expect(unauthenticatedConnector.cancelAllOrders('INDY/USDT')).rejects.toThrow('MEXC connector not authenticated');
472
+ });
473
+ it('should handle empty response for no open orders', async () => {
474
+ mockAuth.makeRequest.mockResolvedValue([]);
475
+ await expect(connector.cancelAllOrders('INDY/USDT')).resolves.not.toThrow();
476
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/openOrders', {
477
+ symbol: 'INDYUSDT'
478
+ }, 'DELETE');
479
+ });
480
+ it('should work with different symbol formats', async () => {
481
+ mockAuth.makeRequest.mockResolvedValue([]);
482
+ await connector.cancelAllOrders('BTC/USDT');
483
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/openOrders', {
484
+ symbol: 'BTCUSDT'
485
+ }, 'DELETE');
486
+ });
487
+ });
488
+ describe('getOrder', () => {
489
+ beforeEach(async () => {
490
+ await connector.connect();
491
+ });
492
+ it('should get order details successfully', async () => {
493
+ const mockApiResponse = [{
494
+ orderId: '12345',
495
+ symbol: 'BTCUSDT',
496
+ type: 'LIMIT',
497
+ side: 'BUY',
498
+ origQty: '1.5',
499
+ price: '50000',
500
+ executedQty: '0.5',
501
+ status: 'PARTIALLY_FILLED',
502
+ time: 1234567890
503
+ }];
504
+ mockAuth.makeRequest.mockResolvedValue(mockApiResponse);
505
+ mockDataMapper.mapOrder.mockReturnValueOnce({
506
+ id: '12345',
507
+ symbol: 'BTCUSDT',
508
+ type: 'limit',
509
+ side: 'buy',
510
+ amount: 1.5,
511
+ price: 50000,
512
+ filled: 0.5,
513
+ remaining: 1.0,
514
+ status: 'open',
515
+ timestamp: 1234567890
516
+ });
517
+ const result = await connector.getOrder('12345', 'BTC/USDT');
518
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/allOrders', {
519
+ symbol: 'BTCUSDT',
520
+ orderId: '12345'
521
+ }, 'GET');
522
+ expect(result).toEqual(expect.objectContaining({
523
+ id: '12345',
524
+ symbol: 'BTCUSDT',
525
+ type: 'limit',
526
+ side: 'buy'
527
+ }));
528
+ });
529
+ it('should handle order not found', async () => {
530
+ mockAuth.makeRequest.mockResolvedValue([]);
531
+ await expect(connector.getOrder('12345', 'BTC/USDT')).rejects.toThrow('Order not found');
532
+ });
533
+ it('should require authentication', async () => {
534
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
535
+ await expect(unauthenticatedConnector.getOrder('12345', 'BTC/USDT')).rejects.toThrow('MEXC connector not authenticated');
536
+ });
537
+ });
538
+ describe('getOpenOrders', () => {
539
+ beforeEach(async () => {
540
+ await connector.connect();
541
+ });
542
+ it('should get all open orders when no symbol specified', async () => {
543
+ const mockApiResponse = [
544
+ { orderId: '1', symbol: 'BTCUSDT', status: 'NEW' },
545
+ { orderId: '2', symbol: 'ETHUSDT', status: 'PARTIALLY_FILLED' }
546
+ ];
547
+ mockAuth.makeRequest.mockResolvedValue(mockApiResponse);
548
+ const result = await connector.getOpenOrders();
549
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/openOrders', {}, 'GET');
550
+ expect(result).toHaveLength(2);
551
+ expect(result[0]).toEqual(expect.objectContaining({
552
+ id: expect.any(String),
553
+ symbol: expect.any(String),
554
+ type: expect.any(String),
555
+ side: expect.any(String)
556
+ }));
557
+ });
558
+ it('should get open orders for specific symbol', async () => {
559
+ const mockApiResponse = [
560
+ { orderId: '1', symbol: 'BTCUSDT', status: 'NEW' }
561
+ ];
562
+ mockAuth.makeRequest.mockResolvedValue(mockApiResponse);
563
+ const result = await connector.getOpenOrders('BTC/USDT');
564
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith('/openOrders', { symbol: 'BTCUSDT' }, 'GET');
565
+ expect(result).toHaveLength(1);
566
+ expect(result[0]).toEqual(expect.objectContaining({
567
+ id: expect.any(String),
568
+ symbol: expect.any(String)
569
+ }));
570
+ });
571
+ it('should require authentication', async () => {
572
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
573
+ await expect(unauthenticatedConnector.getOpenOrders()).rejects.toThrow('MEXC connector not authenticated');
574
+ });
575
+ });
576
+ describe('getTicker', () => {
577
+ beforeEach(async () => {
578
+ await connector.connect();
579
+ });
580
+ it('should get ticker data successfully', async () => {
581
+ const mockPriceData = { symbol: 'BTCUSDT', price: '50000' };
582
+ const mockStatsData = { bidPrice: '49999', askPrice: '50001', volume: '100' };
583
+ mockAuth.makePublicRequest
584
+ .mockResolvedValueOnce(mockPriceData)
585
+ .mockResolvedValueOnce(mockStatsData);
586
+ const result = await connector.getTicker('BTC/USDT');
587
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith('/ticker/price', { symbol: 'BTCUSDT' });
588
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith('/ticker/24hr', { symbol: 'BTCUSDT' });
589
+ expect(result).toEqual(expect.objectContaining({
590
+ symbol: 'BTCUSDT',
591
+ last: 50000,
592
+ bid: 49999,
593
+ ask: 50001
594
+ }));
595
+ });
596
+ it('should handle API errors', async () => {
597
+ const error = new Error('Symbol not found');
598
+ mockAuth.makePublicRequest.mockRejectedValue(error);
599
+ await expect(connector.getTicker('BTC/USDT')).rejects.toThrow('Symbol not found');
600
+ });
601
+ it('should require authentication', async () => {
602
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
603
+ await expect(unauthenticatedConnector.getTicker('BTC/USDT')).rejects.toThrow('MEXC connector not authenticated');
604
+ });
605
+ });
606
+ describe('getOrderBook', () => {
607
+ beforeEach(async () => {
608
+ await connector.connect();
609
+ });
610
+ it('should get order book successfully', async () => {
611
+ const mockApiResponse = {
612
+ bids: [['49999', '1.0'], ['49998', '2.0']],
613
+ asks: [['50001', '1.5'], ['50002', '0.5']]
614
+ };
615
+ mockAuth.makePublicRequest.mockResolvedValue(mockApiResponse);
616
+ const result = await connector.getOrderBook('BTC/USDT');
617
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith('/depth', {
618
+ symbol: 'BTCUSDT',
619
+ limit: 100
620
+ });
621
+ expect(result).toEqual(expect.objectContaining({
622
+ symbol: 'BTC/USDT',
623
+ bids: expect.any(Array),
624
+ asks: expect.any(Array)
625
+ }));
626
+ });
627
+ it('should require authentication', async () => {
628
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
629
+ await expect(unauthenticatedConnector.getOrderBook('BTC/USDT')).rejects.toThrow('MEXC connector not authenticated');
630
+ });
631
+ });
632
+ describe('getRecentTrades', () => {
633
+ beforeEach(async () => {
634
+ await connector.connect();
635
+ });
636
+ it('should get recent trades successfully', async () => {
637
+ const mockApiResponse = [
638
+ { id: 1, price: '50000', qty: '1.0', time: 1234567890, isBuyerMaker: false },
639
+ { id: 2, price: '49999', qty: '0.5', time: 1234567891, isBuyerMaker: true }
640
+ ];
641
+ mockAuth.makePublicRequest.mockResolvedValue(mockApiResponse);
642
+ const result = await connector.getRecentTrades('BTC/USDT');
643
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith('/trades', {
644
+ symbol: 'BTCUSDT',
645
+ limit: 100
646
+ });
647
+ expect(result).toHaveLength(2);
648
+ expect(result[0]).toEqual(expect.objectContaining({
649
+ symbol: 'BTC/USDT',
650
+ side: 'buy',
651
+ amount: expect.any(Number),
652
+ price: expect.any(Number)
653
+ }));
654
+ });
655
+ it('should require authentication', async () => {
656
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
657
+ await expect(unauthenticatedConnector.getRecentTrades('BTC/USDT')).rejects.toThrow('MEXC connector not authenticated');
658
+ });
659
+ });
660
+ describe('WebSocket methods', () => {
661
+ beforeEach(async () => {
662
+ await connector.connect();
663
+ connector.ws = mockWebSocket;
664
+ });
665
+ describe('connectWebSocket', () => {
666
+ it('should connect WebSocket successfully', async () => {
667
+ mockWebSocket.connectWebSocket.mockResolvedValue(undefined);
668
+ await connector.connectWebSocket();
669
+ expect(mockWebSocket.connectWebSocket).toHaveBeenCalled();
670
+ });
671
+ it('should create new WebSocket if not exists', async () => {
672
+ connector.testWebSocket = undefined;
673
+ connector.ws = undefined;
674
+ mockWebSocket.connectWebSocket.mockResolvedValue(undefined);
675
+ await connector.connectWebSocket();
676
+ expect(MockedMexcWebSocket).toHaveBeenCalled();
677
+ expect(mockWebSocket.connectWebSocket).toHaveBeenCalled();
678
+ });
679
+ });
680
+ describe('disconnectWebSocket', () => {
681
+ it('should disconnect WebSocket if connected', async () => {
682
+ mockWebSocket.disconnectWebSocket.mockResolvedValue(undefined);
683
+ await connector.disconnectWebSocket();
684
+ expect(mockWebSocket.disconnectWebSocket).toHaveBeenCalled();
685
+ expect(connector.ws).toBeUndefined();
686
+ });
687
+ it('should handle when WebSocket is not connected', async () => {
688
+ connector.ws = undefined;
689
+ await connector.disconnectWebSocket();
690
+ expect(mockWebSocket.disconnectWebSocket).not.toHaveBeenCalled();
691
+ });
692
+ });
693
+ describe('subscribeTicker', () => {
694
+ it('should subscribe to ticker successfully', async () => {
695
+ const callback = jest.fn();
696
+ const subscriptionId = 'ticker_subscription_1';
697
+ mockWebSocket.subscribeTicker.mockResolvedValue(subscriptionId);
698
+ const result = await connector.subscribeTicker('BTC/USDT', callback);
699
+ expect(mockWebSocket.subscribeTicker).toHaveBeenCalledWith('BTC/USDT', callback);
700
+ expect(result).toBe(subscriptionId);
701
+ });
702
+ it('should throw error if WebSocket not connected', async () => {
703
+ connector.ws = undefined;
704
+ const callback = jest.fn();
705
+ await expect(connector.subscribeTicker('BTC/USDT', callback))
706
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
707
+ });
708
+ });
709
+ describe('subscribeOrderBook', () => {
710
+ it('should subscribe to order book successfully', async () => {
711
+ const callback = jest.fn();
712
+ const subscriptionId = 'orderbook_subscription_1';
713
+ mockWebSocket.subscribeOrderBook.mockResolvedValue(subscriptionId);
714
+ const result = await connector.subscribeOrderBook('BTC/USDT', callback);
715
+ expect(mockWebSocket.subscribeOrderBook).toHaveBeenCalledWith('BTC/USDT', callback);
716
+ expect(result).toBe(subscriptionId);
717
+ });
718
+ it('should throw error if WebSocket not connected', async () => {
719
+ connector.ws = undefined;
720
+ const callback = jest.fn();
721
+ await expect(connector.subscribeOrderBook('BTC/USDT', callback))
722
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
723
+ });
724
+ });
725
+ describe('subscribeTrades', () => {
726
+ it('should subscribe to trades successfully', async () => {
727
+ const callback = jest.fn();
728
+ const subscriptionId = 'trades_subscription_1';
729
+ mockWebSocket.subscribeTrades.mockResolvedValue(subscriptionId);
730
+ const result = await connector.subscribeTrades('BTC/USDT', callback);
731
+ expect(mockWebSocket.subscribeTrades).toHaveBeenCalledWith('BTC/USDT', callback);
732
+ expect(result).toBe(subscriptionId);
733
+ });
734
+ it('should throw error if WebSocket not connected', async () => {
735
+ connector.ws = undefined;
736
+ const callback = jest.fn();
737
+ await expect(connector.subscribeTrades('BTC/USDT', callback))
738
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
739
+ });
740
+ });
741
+ describe('subscribeOrders', () => {
742
+ it('should subscribe to orders successfully', async () => {
743
+ const callback = jest.fn();
744
+ const subscriptionId = 'orders_subscription_1';
745
+ mockWebSocket.subscribeOrders.mockResolvedValue(subscriptionId);
746
+ const result = await connector.subscribeOrders(callback);
747
+ expect(mockWebSocket.subscribeOrders).toHaveBeenCalledWith(callback);
748
+ expect(result).toBe(subscriptionId);
749
+ });
750
+ it('should throw error if WebSocket not connected', async () => {
751
+ connector.ws = undefined;
752
+ const callback = jest.fn();
753
+ await expect(connector.subscribeOrders(callback))
754
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
755
+ });
756
+ });
757
+ describe('unsubscribe', () => {
758
+ it('should unsubscribe successfully', async () => {
759
+ const subscriptionId = 'subscription_1';
760
+ mockWebSocket.unsubscribe.mockResolvedValue(undefined);
761
+ await connector.unsubscribe(subscriptionId);
762
+ expect(mockWebSocket.unsubscribe).toHaveBeenCalledWith(subscriptionId);
763
+ });
764
+ it('should throw error if WebSocket not connected', async () => {
765
+ connector.ws = undefined;
766
+ await expect(connector.unsubscribe('subscription_1'))
767
+ .rejects.toThrow('WebSocket not connected.');
768
+ });
769
+ });
770
+ describe('isWebSocketConnected', () => {
771
+ it('should return WebSocket connection status', () => {
772
+ mockWebSocket.isConnected.mockReturnValue(true);
773
+ const result = connector.isWebSocketConnected();
774
+ expect(mockWebSocket.isConnected).toHaveBeenCalled();
775
+ expect(result).toBe(true);
776
+ });
777
+ it('should return false when WebSocket not initialized', () => {
778
+ connector.ws = undefined;
779
+ const result = connector.isWebSocketConnected();
780
+ expect(result).toBe(false);
781
+ });
782
+ });
783
+ describe('getWebSocketStatus', () => {
784
+ it('should return WebSocket status', () => {
785
+ mockWebSocket.getWebSocketStatus.mockReturnValue('connected');
786
+ const result = connector.getWebSocketStatus();
787
+ expect(mockWebSocket.getWebSocketStatus).toHaveBeenCalled();
788
+ expect(result).toBe('connected');
789
+ });
790
+ it('should return disconnected when WebSocket not initialized', () => {
791
+ connector.ws = undefined;
792
+ const result = connector.getWebSocketStatus();
793
+ expect(result).toBe('disconnected');
794
+ });
795
+ });
796
+ });
797
+ describe('User Data Stream methods', () => {
798
+ beforeEach(async () => {
799
+ await connector.connect();
800
+ });
801
+ describe('connectUserDataStream', () => {
802
+ it('should connect user data stream successfully', async () => {
803
+ mockUserStream.connectUserDataStream.mockResolvedValue(undefined);
804
+ await connector.connectUserDataStream();
805
+ expect(mockUserStream.connectUserDataStream).toHaveBeenCalled();
806
+ });
807
+ it('should throw error if user stream not initialized', async () => {
808
+ connector.userStream = undefined;
809
+ await expect(connector.connectUserDataStream())
810
+ .rejects.toThrow('User stream not initialized');
811
+ });
812
+ });
813
+ describe('disconnectUserDataStream', () => {
814
+ it('should disconnect user data stream successfully', async () => {
815
+ mockUserStream.disconnectUserDataStream.mockResolvedValue(undefined);
816
+ await connector.disconnectUserDataStream();
817
+ expect(mockUserStream.disconnectUserDataStream).toHaveBeenCalled();
818
+ });
819
+ it('should handle gracefully when user stream not initialized', async () => {
820
+ connector.userStream = undefined;
821
+ await expect(connector.disconnectUserDataStream()).resolves.not.toThrow();
822
+ });
823
+ });
824
+ describe('subscribeUserOrders', () => {
825
+ it('should subscribe to user orders successfully', async () => {
826
+ const callback = jest.fn();
827
+ const subscriptionId = 'user_orders_subscription_1';
828
+ mockUserStream.subscribeUserOrders.mockResolvedValue(subscriptionId);
829
+ const result = await connector.subscribeUserOrders(callback);
830
+ expect(mockUserStream.subscribeUserOrders).toHaveBeenCalledWith(callback);
831
+ expect(result).toBe(subscriptionId);
832
+ });
833
+ it('should throw error if user stream not initialized', async () => {
834
+ connector.userStream = undefined;
835
+ const callback = jest.fn();
836
+ await expect(connector.subscribeUserOrders(callback))
837
+ .rejects.toThrow('User stream not initialized');
838
+ });
839
+ });
840
+ describe('subscribeUserTrades', () => {
841
+ it('should subscribe to user trades successfully', async () => {
842
+ const callback = jest.fn();
843
+ const subscriptionId = 'user_trades_subscription_1';
844
+ mockUserStream.subscribeUserTrades.mockResolvedValue(subscriptionId);
845
+ const result = await connector.subscribeUserTrades(callback);
846
+ expect(mockUserStream.subscribeUserTrades).toHaveBeenCalledWith(callback);
847
+ expect(result).toBe(subscriptionId);
848
+ });
849
+ it('should throw error if user stream not initialized', async () => {
850
+ connector.userStream = undefined;
851
+ const callback = jest.fn();
852
+ await expect(connector.subscribeUserTrades(callback))
853
+ .rejects.toThrow('User stream not initialized');
854
+ });
855
+ });
856
+ describe('isUserDataStreamConnected', () => {
857
+ it('should return user data stream connection status', () => {
858
+ mockUserStream.isUserDataStreamConnected.mockReturnValue(true);
859
+ const result = connector.isUserDataStreamConnected();
860
+ expect(mockUserStream.isUserDataStreamConnected).toHaveBeenCalled();
861
+ expect(result).toBe(true);
862
+ });
863
+ it('should return false when user stream not initialized', () => {
864
+ connector.userStream = undefined;
865
+ const result = connector.isUserDataStreamConnected();
866
+ expect(result).toBe(false);
867
+ });
868
+ });
869
+ });
870
+ describe('private methods', () => {
871
+ describe('makeRequest', () => {
872
+ beforeEach(async () => {
873
+ await connector.connect();
874
+ });
875
+ it('should delegate to auth makeRequest', async () => {
876
+ const endpoint = '/test';
877
+ const params = { param1: 'value1' };
878
+ const method = 'POST';
879
+ const expectedResponse = { result: 'success' };
880
+ mockAuth.makeRequest.mockResolvedValue(expectedResponse);
881
+ const result = await connector.testMakeRequest(endpoint, params, method);
882
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith(endpoint, params, method);
883
+ expect(result).toBe(expectedResponse);
884
+ });
885
+ it('should use default parameters', async () => {
886
+ const endpoint = '/test';
887
+ const expectedResponse = { result: 'success' };
888
+ mockAuth.makeRequest.mockResolvedValue(expectedResponse);
889
+ const result = await connector.testMakeRequest(endpoint);
890
+ expect(mockAuth.makeRequest).toHaveBeenCalledWith(endpoint, {}, 'GET');
891
+ expect(result).toBe(expectedResponse);
892
+ });
893
+ it('should throw error when not authenticated', async () => {
894
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
895
+ await expect(unauthenticatedConnector.makeRequest('/test'))
896
+ .rejects.toThrow('MEXC connector not authenticated');
897
+ });
898
+ });
899
+ describe('makePublicRequest', () => {
900
+ beforeEach(async () => {
901
+ await connector.connect();
902
+ });
903
+ it('should delegate to auth makePublicRequest', async () => {
904
+ const endpoint = '/test';
905
+ const params = { param1: 'value1' };
906
+ const expectedResponse = { result: 'success' };
907
+ mockAuth.makePublicRequest.mockResolvedValue(expectedResponse);
908
+ const result = await connector.testMakePublicRequest(endpoint, params);
909
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith(endpoint, params);
910
+ expect(result).toBe(expectedResponse);
911
+ });
912
+ it('should use default parameters', async () => {
913
+ const endpoint = '/test';
914
+ const expectedResponse = { result: 'success' };
915
+ mockAuth.makePublicRequest.mockResolvedValue(expectedResponse);
916
+ const result = await connector.testMakePublicRequest(endpoint);
917
+ expect(mockAuth.makePublicRequest).toHaveBeenCalledWith(endpoint, {});
918
+ expect(result).toBe(expectedResponse);
919
+ });
920
+ it('should throw error when not authenticated', async () => {
921
+ const unauthenticatedConnector = new mexc_connector_1.MexcConnector();
922
+ await expect(unauthenticatedConnector.makePublicRequest('/test'))
923
+ .rejects.toThrow('MEXC connector not authenticated');
924
+ });
925
+ });
926
+ });
927
+ describe('error handling', () => {
928
+ describe('connect method error paths', () => {
929
+ it('should handle credential validation failure', async () => {
930
+ const mockAuth = {
931
+ validateCredentials: jest.fn().mockReturnValue(false),
932
+ makeRequest: jest.fn(),
933
+ makePublicRequest: jest.fn()
934
+ };
935
+ const connector = new TestableMexcConnector(mockAuth);
936
+ await expect(connector.connect()).rejects.toThrow('Invalid MEXC credentials');
937
+ expect(connector.isConnected()).toBe(false);
938
+ });
939
+ it('should handle auth construction errors', async () => {
940
+ const connector = new TestableMexcConnector();
941
+ MockedMexcAuth.mockImplementationOnce(() => {
942
+ throw new Error('Auth construction failed');
943
+ });
944
+ await expect(connector.connect()).rejects.toThrow('Auth construction failed');
945
+ expect(connector.isConnected()).toBe(false);
946
+ });
947
+ it('should handle user stream construction errors', async () => {
948
+ const mockAuth = {
949
+ validateCredentials: jest.fn().mockReturnValue(true),
950
+ makeRequest: jest.fn(),
951
+ makePublicRequest: jest.fn()
952
+ };
953
+ MockedMexcUserStream.mockImplementationOnce(() => {
954
+ throw new Error('User stream construction failed');
955
+ });
956
+ const connector = new TestableMexcConnector(mockAuth);
957
+ await expect(connector.connect()).rejects.toThrow('User stream construction failed');
958
+ expect(connector.isConnected()).toBe(false);
959
+ });
960
+ });
961
+ describe('WebSocket error paths', () => {
962
+ beforeEach(async () => {
963
+ await connector.connect();
964
+ });
965
+ it('should handle WebSocket connection errors in connectWebSocket', async () => {
966
+ connector.ws = {
967
+ connectWebSocket: jest.fn().mockRejectedValue(new Error('WebSocket connection failed')),
968
+ disconnectWebSocket: jest.fn(),
969
+ subscribeTicker: jest.fn(),
970
+ subscribeOrderBook: jest.fn(),
971
+ subscribetTrades: jest.fn(),
972
+ subscribeOrders: jest.fn(),
973
+ unsubscribe: jest.fn(),
974
+ isConnected: jest.fn(),
975
+ getWebSocketStatus: jest.fn()
976
+ };
977
+ await expect(connector.connectWebSocket()).rejects.toThrow('WebSocket connection failed');
978
+ });
979
+ it('should handle WebSocket disconnection errors in disconnectWebSocket', async () => {
980
+ connector.ws = {
981
+ connectWebSocket: jest.fn(),
982
+ disconnectWebSocket: jest.fn().mockRejectedValue(new Error('WebSocket disconnect failed')),
983
+ subscribeTicker: jest.fn(),
984
+ subscribeOrderBook: jest.fn(),
985
+ subscribeTrades: jest.fn(),
986
+ subscribeOrders: jest.fn(),
987
+ unsubscribe: jest.fn(),
988
+ isConnected: jest.fn(),
989
+ getWebSocketStatus: jest.fn()
990
+ };
991
+ await expect(connector.disconnectWebSocket()).rejects.toThrow('WebSocket disconnect failed');
992
+ });
993
+ it('should handle subscribeTicker when WebSocket not connected', async () => {
994
+ connector.ws = undefined;
995
+ await expect(connector.subscribeTicker('BTCUSDT', jest.fn()))
996
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
997
+ });
998
+ it('should handle subscribeOrderBook when WebSocket not connected', async () => {
999
+ connector.ws = undefined;
1000
+ await expect(connector.subscribeOrderBook('BTCUSDT', jest.fn()))
1001
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
1002
+ });
1003
+ it('should handle subscribeTrades when WebSocket not connected', async () => {
1004
+ connector.ws = undefined;
1005
+ await expect(connector.subscribeTrades('BTCUSDT', jest.fn()))
1006
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
1007
+ });
1008
+ it('should handle subscribeOrders when WebSocket not connected', async () => {
1009
+ connector.ws = undefined;
1010
+ await expect(connector.subscribeOrders(jest.fn()))
1011
+ .rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
1012
+ });
1013
+ it('should handle unsubscribe when WebSocket not connected', async () => {
1014
+ connector.ws = undefined;
1015
+ await expect(connector.unsubscribe('test')).rejects.toThrow('WebSocket not connected.');
1016
+ });
1017
+ it('should handle WebSocket method errors during subscription', async () => {
1018
+ connector.ws = {
1019
+ connectWebSocket: jest.fn(),
1020
+ disconnectWebSocket: jest.fn(),
1021
+ subscribeTicker: jest.fn().mockRejectedValue(new Error('Subscribe failed')),
1022
+ subscribeOrderBook: jest.fn(),
1023
+ subscribeTrades: jest.fn(),
1024
+ subscribeOrders: jest.fn(),
1025
+ unsubscribe: jest.fn(),
1026
+ isConnected: jest.fn(),
1027
+ getWebSocketStatus: jest.fn()
1028
+ };
1029
+ await expect(connector.subscribeTicker('BTCUSDT', jest.fn()))
1030
+ .rejects.toThrow('Subscribe failed');
1031
+ });
1032
+ it('should handle WebSocket method errors during order book subscription', async () => {
1033
+ connector.ws = {
1034
+ connectWebSocket: jest.fn(),
1035
+ disconnectWebSocket: jest.fn(),
1036
+ subscribeTicker: jest.fn(),
1037
+ subscribeOrderBook: jest.fn().mockRejectedValue(new Error('Subscribe failed')),
1038
+ subscribeTrades: jest.fn(),
1039
+ subscribeOrders: jest.fn(),
1040
+ unsubscribe: jest.fn(),
1041
+ isConnected: jest.fn(),
1042
+ getWebSocketStatus: jest.fn()
1043
+ };
1044
+ const result = await connector.subscribeOrderBook('BTCUSDT', jest.fn());
1045
+ expect(result).toBe('');
1046
+ });
1047
+ it('should handle WebSocket method errors during trades subscription', async () => {
1048
+ connector.ws = {
1049
+ connectWebSocket: jest.fn(),
1050
+ disconnectWebSocket: jest.fn(),
1051
+ subscribeTicker: jest.fn(),
1052
+ subscribeOrderBook: jest.fn(),
1053
+ subscribeTrades: jest.fn().mockRejectedValue(new Error('Subscribe failed')),
1054
+ subscribeOrders: jest.fn(),
1055
+ unsubscribe: jest.fn(),
1056
+ isConnected: jest.fn(),
1057
+ getWebSocketStatus: jest.fn()
1058
+ };
1059
+ const result = await connector.subscribeTrades('BTCUSDT', jest.fn());
1060
+ expect(result).toBe('');
1061
+ });
1062
+ it('should handle WebSocket method errors during orders subscription', async () => {
1063
+ connector.ws = {
1064
+ connectWebSocket: jest.fn(),
1065
+ disconnectWebSocket: jest.fn(),
1066
+ subscribeTicker: jest.fn(),
1067
+ subscribeOrderBook: jest.fn(),
1068
+ subscribeTrades: jest.fn(),
1069
+ subscribeOrders: jest.fn().mockRejectedValue(new Error('Subscribe failed')),
1070
+ unsubscribe: jest.fn(),
1071
+ isConnected: jest.fn(),
1072
+ getWebSocketStatus: jest.fn()
1073
+ };
1074
+ const result = await connector.subscribeOrders(jest.fn());
1075
+ expect(result).toBe('');
1076
+ });
1077
+ it('should handle WebSocket method errors during unsubscribe', async () => {
1078
+ connector.ws = {
1079
+ connectWebSocket: jest.fn(),
1080
+ disconnectWebSocket: jest.fn(),
1081
+ subscribeTicker: jest.fn(),
1082
+ subscribeOrderBook: jest.fn(),
1083
+ subscribeTrades: jest.fn(),
1084
+ subscribeOrders: jest.fn(),
1085
+ unsubscribe: jest.fn().mockRejectedValue(new Error('Unsubscribe failed')),
1086
+ isConnected: jest.fn(),
1087
+ getWebSocketStatus: jest.fn()
1088
+ };
1089
+ await expect(connector.unsubscribe('test')).resolves.not.toThrow();
1090
+ });
1091
+ });
1092
+ describe('User data stream error paths', () => {
1093
+ beforeEach(async () => {
1094
+ await connector.connect();
1095
+ });
1096
+ it('should handle connectUserDataStream when user stream not initialized', async () => {
1097
+ connector.userStream = undefined;
1098
+ await expect(connector.connectUserDataStream()).rejects.toThrow('User stream not initialized');
1099
+ });
1100
+ it('should handle connectUserDataStream errors', async () => {
1101
+ mockUserStream.connectUserDataStream.mockRejectedValue(new Error('Connect failed'));
1102
+ await expect(connector.connectUserDataStream()).rejects.toThrow('Connect failed');
1103
+ });
1104
+ it('should handle subscribeUserOrders errors', async () => {
1105
+ mockUserStream.subscribeUserOrders.mockRejectedValue(new Error('Subscribe failed'));
1106
+ const result = await connector.subscribeUserOrders(jest.fn());
1107
+ expect(result).toBe('');
1108
+ });
1109
+ it('should handle subscribeUserTrades errors', async () => {
1110
+ mockUserStream.subscribeUserTrades.mockRejectedValue(new Error('Subscribe failed'));
1111
+ const result = await connector.subscribeUserTrades(jest.fn());
1112
+ expect(result).toBe('');
1113
+ });
1114
+ });
1115
+ describe('getOrder edge cases', () => {
1116
+ beforeEach(async () => {
1117
+ await connector.connect();
1118
+ });
1119
+ it('should handle getOrder with empty response', async () => {
1120
+ mockAuth.makeRequest.mockResolvedValue([]);
1121
+ await expect(connector.getOrder('123', 'BTCUSDT')).rejects.toThrow('Order not found');
1122
+ });
1123
+ it('should handle getOrder with null response', async () => {
1124
+ mockAuth.makeRequest.mockResolvedValue(null);
1125
+ await expect(connector.getOrder('123', 'BTCUSDT')).rejects.toThrow('Order not found');
1126
+ });
1127
+ });
1128
+ describe('uncovered error path tests', () => {
1129
+ it('should handle credentials validation failure in connect', async () => {
1130
+ mockAuth.validateCredentials.mockReturnValue(false);
1131
+ const newConnector = new TestableMexcConnector();
1132
+ await expect(newConnector.connect()).rejects.toThrow('Invalid MEXC credentials');
1133
+ expect(newConnector.isConnected()).toBe(false);
1134
+ });
1135
+ it('should handle auth creation failure in connect', async () => {
1136
+ MockedMexcAuth.mockImplementationOnce(() => {
1137
+ throw new Error('Auth initialization failed');
1138
+ });
1139
+ const newConnector = new TestableMexcConnector();
1140
+ await expect(newConnector.connect()).rejects.toThrow('Auth initialization failed');
1141
+ expect(newConnector.isConnected()).toBe(false);
1142
+ });
1143
+ it('should handle WebSocket creation error in connectWebSocket', async () => {
1144
+ MockedMexcWebSocket.mockImplementationOnce(() => {
1145
+ throw new Error('WebSocket creation failed');
1146
+ });
1147
+ const newConnector = new TestableMexcConnector();
1148
+ await newConnector.connect();
1149
+ await expect(newConnector.connectWebSocket()).rejects.toThrow('WebSocket creation failed');
1150
+ });
1151
+ it('should handle WebSocket connection failure in connectWebSocket', async () => {
1152
+ mockWebSocket.connectWebSocket.mockRejectedValue(new Error('WebSocket connection failed'));
1153
+ const newConnector = new TestableMexcConnector();
1154
+ await newConnector.connect();
1155
+ await expect(newConnector.connectWebSocket()).rejects.toThrow('WebSocket connection failed');
1156
+ });
1157
+ it('should handle subscribeTicker when WebSocket not connected', async () => {
1158
+ const newConnector = new TestableMexcConnector();
1159
+ await newConnector.connect();
1160
+ await expect(newConnector.subscribeTicker('BTCUSDT', jest.fn())).rejects.toThrow('WebSocket not connected. Call connectWebSocket() first.');
1161
+ });
1162
+ it('should handle subscribeTicker WebSocket error', async () => {
1163
+ const newConnector = new TestableMexcConnector();
1164
+ await newConnector.connect();
1165
+ await newConnector.connectWebSocket();
1166
+ mockWebSocket.subscribeTicker.mockRejectedValue(new Error('Subscribe failed'));
1167
+ await expect(newConnector.subscribeTicker('BTCUSDT', jest.fn())).rejects.toThrow('Subscribe failed');
1168
+ });
1169
+ it('should handle subscribeOrderBook when WebSocket not connected', async () => {
1170
+ const newConnector = new TestableMexcConnector();
1171
+ await newConnector.connect();
1172
+ try {
1173
+ await newConnector.subscribeOrderBook('BTCUSDT', jest.fn());
1174
+ }
1175
+ catch (error) {
1176
+ expect(error.message).toContain('WebSocket not connected');
1177
+ }
1178
+ });
1179
+ it('should handle subscribeTrades when WebSocket not connected', async () => {
1180
+ const newConnector = new TestableMexcConnector();
1181
+ await newConnector.connect();
1182
+ try {
1183
+ await newConnector.subscribeTrades('BTCUSDT', jest.fn());
1184
+ }
1185
+ catch (error) {
1186
+ expect(error.message).toContain('WebSocket not connected');
1187
+ }
1188
+ });
1189
+ it('should handle subscribeOrders when WebSocket not connected', async () => {
1190
+ const newConnector = new TestableMexcConnector();
1191
+ await newConnector.connect();
1192
+ try {
1193
+ await newConnector.subscribeOrders(jest.fn());
1194
+ }
1195
+ catch (error) {
1196
+ expect(error.message).toContain('WebSocket not connected');
1197
+ }
1198
+ });
1199
+ it('should handle unsubscribe when WebSocket not connected', async () => {
1200
+ const newConnector = new TestableMexcConnector();
1201
+ await newConnector.connect();
1202
+ try {
1203
+ await newConnector.unsubscribe('test-id');
1204
+ }
1205
+ catch (error) {
1206
+ expect(error.message).toContain('WebSocket not connected');
1207
+ }
1208
+ });
1209
+ it('should handle disconnectUserDataStream error via logger', async () => {
1210
+ const newConnector = new TestableMexcConnector();
1211
+ await newConnector.connect();
1212
+ const realLogger = newConnector.logger;
1213
+ newConnector.logger = {
1214
+ warn: jest.fn(),
1215
+ info: jest.fn(),
1216
+ error: jest.fn(),
1217
+ debug: jest.fn()
1218
+ };
1219
+ mockUserStream.disconnectUserDataStream.mockRejectedValue(new Error('Disconnect failed'));
1220
+ await newConnector.disconnectUserDataStream();
1221
+ expect(newConnector.logger.warn).toHaveBeenCalledWith('Error disconnecting user data stream', { error: expect.any(Error) });
1222
+ newConnector.logger = realLogger;
1223
+ });
1224
+ });
1225
+ describe('comprehensive error handling coverage for mexc-connector', () => {
1226
+ beforeEach(async () => {
1227
+ await connector.connect();
1228
+ });
1229
+ it('should handle getBalance API error (line 92)', async () => {
1230
+ mockAuth.makeRequest.mockRejectedValue(new Error('API request failed'));
1231
+ await expect(connector.getBalance()).rejects.toThrow('API request failed');
1232
+ });
1233
+ it('should handle getBalance for specific asset API error (line 92)', async () => {
1234
+ mockAuth.makeRequest.mockRejectedValue(new Error('API request failed'));
1235
+ await expect(connector.getBalance('BTC')).rejects.toThrow('API request failed');
1236
+ });
1237
+ it('should return default balance when asset not found in response', async () => {
1238
+ const balanceResponse = { balances: [] };
1239
+ mockAuth.makeRequest.mockResolvedValue(balanceResponse);
1240
+ mockDataMapper.mapAccountBalances.mockReturnValue({});
1241
+ const result = await connector.getBalance('BTC');
1242
+ expect(result).toEqual({
1243
+ asset: 'BTC',
1244
+ free: 0,
1245
+ used: 0,
1246
+ total: 0,
1247
+ available: 0
1248
+ });
1249
+ });
1250
+ it('should handle createOrder API error (line 123)', async () => {
1251
+ mockAuth.makeRequest.mockRejectedValue(new Error('Order creation failed'));
1252
+ await expect(connector.createOrder('BTC/USDT', 'limit', 'buy', 1, 50000))
1253
+ .rejects.toThrow('Order creation failed');
1254
+ });
1255
+ it('should handle cancelOrder API error (line 137)', async () => {
1256
+ mockAuth.makeRequest.mockRejectedValue(new Error('Cancel failed'));
1257
+ await expect(connector.cancelOrder('123', 'BTC/USDT'))
1258
+ .rejects.toThrow('Cancel failed');
1259
+ });
1260
+ it('should handle cancelAllOrders API error (line 150)', async () => {
1261
+ mockAuth.makeRequest.mockRejectedValue(new Error('Cancel all failed'));
1262
+ await expect(connector.cancelAllOrders('BTC/USDT'))
1263
+ .rejects.toThrow('Cancel all failed');
1264
+ });
1265
+ it('should handle getOrder API error (line 172)', async () => {
1266
+ mockAuth.makeRequest.mockRejectedValue(new Error('Get order failed'));
1267
+ await expect(connector.getOrder('123', 'BTC/USDT'))
1268
+ .rejects.toThrow('Get order failed');
1269
+ });
1270
+ it('should throw error when order not found (line 165-166)', async () => {
1271
+ mockAuth.makeRequest.mockResolvedValue([]);
1272
+ await expect(connector.getOrder('123', 'BTC/USDT')).rejects.toThrow('Order not found');
1273
+ });
1274
+ it('should throw error when orders response is null (line 165-166)', async () => {
1275
+ mockAuth.makeRequest.mockResolvedValue(null);
1276
+ await expect(connector.getOrder('123', 'BTC/USDT')).rejects.toThrow('Order not found');
1277
+ });
1278
+ it('should throw error when orders response is undefined (line 165-166)', async () => {
1279
+ mockAuth.makeRequest.mockResolvedValue(undefined);
1280
+ await expect(connector.getOrder('123', 'BTC/USDT')).rejects.toThrow('Order not found');
1281
+ });
1282
+ it('should handle getOpenOrders API error (line 189)', async () => {
1283
+ mockAuth.makeRequest.mockRejectedValue(new Error('Get open orders failed'));
1284
+ await expect(connector.getOpenOrders()).rejects.toThrow('Get open orders failed');
1285
+ });
1286
+ it('should handle getOpenOrders with symbol API error (line 189)', async () => {
1287
+ mockAuth.makeRequest.mockRejectedValue(new Error('Get open orders failed'));
1288
+ await expect(connector.getOpenOrders('BTC/USDT')).rejects.toThrow('Get open orders failed');
1289
+ });
1290
+ it('should handle getTicker API error (line 207)', async () => {
1291
+ mockAuth.makePublicRequest.mockRejectedValue(new Error('Get ticker failed'));
1292
+ await expect(connector.getTicker('BTC/USDT')).rejects.toThrow('Get ticker failed');
1293
+ });
1294
+ it('should handle getOrderBook API error (line 225)', async () => {
1295
+ mockAuth.makePublicRequest.mockRejectedValue(new Error('Get orderbook failed'));
1296
+ await expect(connector.getOrderBook('BTC/USDT')).rejects.toThrow('Get orderbook failed');
1297
+ });
1298
+ it('should handle getRecentTrades API error (line 243)', async () => {
1299
+ mockAuth.makePublicRequest.mockRejectedValue(new Error('Get trades failed'));
1300
+ await expect(connector.getRecentTrades('BTC/USDT')).rejects.toThrow('Get trades failed');
1301
+ });
1302
+ it('should handle connectWebSocket when WebSocket already exists but connection fails (line 260)', async () => {
1303
+ // Create WebSocket first
1304
+ await connector.connectWebSocket();
1305
+ // Now make the existing WebSocket fail on next connect attempt
1306
+ mockWebSocket.connectWebSocket.mockRejectedValue(new Error('Connection failed'));
1307
+ await expect(connector.connectWebSocket()).rejects.toThrow('Connection failed');
1308
+ });
1309
+ it('should handle disconnectWebSocket error (line 274)', async () => {
1310
+ await connector.connectWebSocket();
1311
+ mockWebSocket.disconnectWebSocket.mockRejectedValue(new Error('Disconnect failed'));
1312
+ await expect(connector.disconnectWebSocket()).rejects.toThrow('Disconnect failed');
1313
+ });
1314
+ it('should handle subscribeTicker WebSocket error after connection check (line 289-290)', async () => {
1315
+ await connector.connectWebSocket();
1316
+ mockWebSocket.subscribeTicker.mockRejectedValueOnce(new Error('Subscribe failed'));
1317
+ await expect(connector.subscribeTicker('BTC/USDT', jest.fn())).rejects.toThrow('Subscribe failed');
1318
+ });
1319
+ it('should handle subscribeOrderBook WebSocket error after connection check (line 305-306)', async () => {
1320
+ await connector.connectWebSocket();
1321
+ mockWebSocket.subscribeOrderBook.mockRejectedValueOnce(new Error('Subscribe failed'));
1322
+ const result = await connector.subscribeOrderBook('BTC/USDT', jest.fn());
1323
+ expect(result).toBe('');
1324
+ });
1325
+ it('should handle subscribeTrades WebSocket error after connection check (line 321-322)', async () => {
1326
+ await connector.connectWebSocket();
1327
+ mockWebSocket.subscribeTrades.mockRejectedValueOnce(new Error('Subscribe failed'));
1328
+ const result = await connector.subscribeTrades('BTC/USDT', jest.fn());
1329
+ expect(result).toBe('');
1330
+ });
1331
+ it('should handle subscribeOrders WebSocket error after connection check (line 337-338)', async () => {
1332
+ await connector.connectWebSocket();
1333
+ mockWebSocket.subscribeOrders.mockRejectedValueOnce(new Error('Subscribe failed'));
1334
+ const result = await connector.subscribeOrders(jest.fn());
1335
+ expect(result).toBe('');
1336
+ });
1337
+ it('should handle unsubscribe WebSocket error after connection check (line 353)', async () => {
1338
+ await connector.connectWebSocket();
1339
+ mockWebSocket.unsubscribe.mockRejectedValueOnce(new Error('Unsubscribe failed'));
1340
+ await connector.unsubscribe('test-id'); // Should not throw, handled gracefully
1341
+ expect(mockWebSocket.unsubscribe).toHaveBeenCalledWith('test-id');
1342
+ });
1343
+ it('should return false when WebSocket is undefined in isWebSocketConnected', () => {
1344
+ connector.ws = undefined;
1345
+ expect(connector.isWebSocketConnected()).toBe(false);
1346
+ });
1347
+ it('should return disconnected status when WebSocket is undefined in getWebSocketStatus', () => {
1348
+ connector.ws = undefined;
1349
+ expect(connector.getWebSocketStatus()).toBe('disconnected');
1350
+ });
1351
+ it('should handle connectUserDataStream error after user stream check (line 384)', async () => {
1352
+ mockUserStream.connectUserDataStream.mockRejectedValue(new Error('Connect failed'));
1353
+ await expect(connector.connectUserDataStream()).rejects.toThrow('Connect failed');
1354
+ });
1355
+ it('should handle subscribeUserOrders error after user stream check (line 412-413)', async () => {
1356
+ mockUserStream.subscribeUserOrders.mockRejectedValue(new Error('Subscribe failed'));
1357
+ const result = await connector.subscribeUserOrders(jest.fn());
1358
+ expect(result).toBe('');
1359
+ });
1360
+ it('should handle subscribeUserTrades error after user stream check (line 429-430)', async () => {
1361
+ mockUserStream.subscribeUserTrades.mockRejectedValue(new Error('Subscribe failed'));
1362
+ const result = await connector.subscribeUserTrades(jest.fn());
1363
+ expect(result).toBe('');
1364
+ });
1365
+ it('should handle makeRequest when auth is undefined (line 450)', async () => {
1366
+ connector.auth = undefined;
1367
+ await expect(connector.makeRequest('/test'))
1368
+ .rejects.toThrow('MEXC connector not authenticated');
1369
+ });
1370
+ it('should handle makePublicRequest when auth is undefined (line 460)', async () => {
1371
+ connector.auth = undefined;
1372
+ await expect(connector.makePublicRequest('/test'))
1373
+ .rejects.toThrow('MEXC connector not authenticated');
1374
+ });
1375
+ it('should handle disconnectUserDataStream error logging (line 397)', async () => {
1376
+ const warnSpy = jest.fn();
1377
+ connector.logger = { warn: warnSpy, info: jest.fn(), error: jest.fn(), debug: jest.fn() };
1378
+ mockUserStream.disconnectUserDataStream.mockRejectedValue(new Error('Disconnect failed'));
1379
+ await connector.disconnectUserDataStream();
1380
+ expect(warnSpy).toHaveBeenCalledWith('Error disconnecting user data stream', { error: expect.any(Error) });
1381
+ });
1382
+ it('should handle disconnect WebSocket when ws is undefined', async () => {
1383
+ connector.ws = undefined;
1384
+ await expect(connector.disconnectWebSocket()).resolves.not.toThrow();
1385
+ });
1386
+ it('should call disconnect on all components in disconnect method', async () => {
1387
+ await connector.connectWebSocket();
1388
+ const disconnectWebSocketSpy = jest.spyOn(connector, 'disconnectWebSocket');
1389
+ const disconnectUserDataStreamSpy = jest.spyOn(connector, 'disconnectUserDataStream');
1390
+ await connector.disconnect();
1391
+ expect(disconnectWebSocketSpy).toHaveBeenCalled();
1392
+ expect(disconnectUserDataStreamSpy).toHaveBeenCalled();
1393
+ expect(connector.isConnected()).toBe(false);
1394
+ expect(connector.auth).toBeUndefined();
1395
+ expect(connector.userStream).toBeUndefined();
1396
+ });
1397
+ it('should handle credentials validation and early return in connect (line 48-50)', async () => {
1398
+ const newConnector = new TestableMexcConnector();
1399
+ const mockAuth = {
1400
+ validateCredentials: jest.fn().mockReturnValue(false),
1401
+ makeRequest: jest.fn(),
1402
+ makePublicRequest: jest.fn()
1403
+ };
1404
+ MockedMexcAuth.mockImplementationOnce(() => mockAuth);
1405
+ await expect(newConnector.connect()).rejects.toThrow('Invalid MEXC credentials');
1406
+ expect(newConnector.isConnected()).toBe(false);
1407
+ });
1408
+ it('should handle getOpenOrders error when receives null response', async () => {
1409
+ mockAuth.makeRequest.mockResolvedValue(null);
1410
+ await expect(connector.getOpenOrders()).rejects.toThrow();
1411
+ });
1412
+ it('should handle getOpenOrders error when receives undefined response', async () => {
1413
+ mockAuth.makeRequest.mockResolvedValue(undefined);
1414
+ await expect(connector.getOpenOrders()).rejects.toThrow();
1415
+ });
1416
+ });
1417
+ });
1418
+ });
1419
+ //# sourceMappingURL=mexc-connector.test.js.map