@3rd-eye-labs/openmm 0.0.1 → 0.1.1
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/README.md +6 -1
- package/dist/cli/cli.js +4 -5
- package/dist/cli/cli.js.map +1 -1
- package/dist/cli/commands/balance.d.ts.map +1 -1
- package/dist/cli/commands/balance.js +1 -1
- package/dist/cli/commands/balance.js.map +1 -1
- package/dist/cli/commands/grid.d.ts +3 -0
- package/dist/cli/commands/grid.d.ts.map +1 -0
- package/dist/cli/commands/grid.js +103 -0
- package/dist/cli/commands/grid.js.map +1 -0
- package/dist/cli/commands/multi-trade.d.ts +3 -0
- package/dist/cli/commands/multi-trade.d.ts.map +1 -0
- package/dist/cli/commands/multi-trade.js +175 -0
- package/dist/cli/commands/multi-trade.js.map +1 -0
- package/dist/cli/commands/orderbook.js +1 -1
- package/dist/cli/commands/orderbook.js.map +1 -1
- package/dist/cli/commands/orders.d.ts.map +1 -1
- package/dist/cli/commands/orders.js +3 -4
- package/dist/cli/commands/orders.js.map +1 -1
- package/dist/cli/commands/pool-discovery.d.ts.map +1 -1
- package/dist/cli/commands/pool-discovery.js +15 -8
- package/dist/cli/commands/pool-discovery.js.map +1 -1
- package/dist/cli/commands/price-comparison.d.ts +3 -0
- package/dist/cli/commands/price-comparison.d.ts.map +1 -0
- package/dist/cli/commands/price-comparison.js +103 -0
- package/dist/cli/commands/price-comparison.js.map +1 -0
- package/dist/cli/commands/ticker.d.ts.map +1 -1
- package/dist/cli/commands/ticker.js.map +1 -1
- package/dist/cli/commands/trade.d.ts.map +1 -1
- package/dist/cli/commands/trade.js +135 -18
- package/dist/cli/commands/trade.js.map +1 -1
- package/dist/cli/commands/trades.d.ts.map +1 -1
- package/dist/cli/commands/trades.js +2 -3
- package/dist/cli/commands/trades.js.map +1 -1
- package/dist/cli/exchange-factory.d.ts.map +1 -1
- package/dist/cli/exchange-factory.js +6 -6
- package/dist/cli/exchange-factory.js.map +1 -1
- package/dist/cli/pool-discovery-core.d.ts +2 -1
- package/dist/cli/pool-discovery-core.d.ts.map +1 -1
- package/dist/cli/pool-discovery-core.js +69 -39
- package/dist/cli/pool-discovery-core.js.map +1 -1
- package/dist/cli/pool-discovery.d.ts +56 -0
- package/dist/cli/pool-discovery.d.ts.map +1 -0
- package/dist/cli/pool-discovery.js +283 -0
- package/dist/cli/pool-discovery.js.map +1 -0
- package/dist/cli/utils/error-handler.d.ts.map +1 -1
- package/dist/cli/utils/error-handler.js +6 -5
- package/dist/cli/utils/error-handler.js.map +1 -1
- package/dist/config/environment.d.ts.map +1 -1
- package/dist/config/environment.js +3 -1
- package/dist/config/environment.js.map +1 -1
- package/dist/config/launcher-config.d.ts +13 -0
- package/dist/config/launcher-config.d.ts.map +1 -1
- package/dist/config/launcher-config.js +3 -1
- package/dist/config/launcher-config.js.map +1 -1
- package/dist/config/price-aggregation.d.ts +1 -1
- package/dist/config/price-aggregation.d.ts.map +1 -1
- package/dist/config/price-aggregation.js +20 -20
- package/dist/config/price-aggregation.js.map +1 -1
- package/dist/core/exchange/base-exchange-connector.d.ts.map +1 -1
- package/dist/core/exchange/base-exchange-connector.js +1 -5
- package/dist/core/exchange/base-exchange-connector.js.map +1 -1
- package/dist/core/exchange/base-exchange-data-mapper.d.ts.map +1 -1
- package/dist/core/exchange/base-exchange-data-mapper.js +1 -1
- package/dist/core/exchange/base-exchange-data-mapper.js.map +1 -1
- package/dist/core/price-aggregation/cardano-price-service.d.ts +2 -2
- package/dist/core/price-aggregation/cardano-price-service.d.ts.map +1 -1
- package/dist/core/price-aggregation/cardano-price-service.js +13 -13
- package/dist/core/price-aggregation/cardano-price-service.js.map +1 -1
- package/dist/core/price-aggregation/index.d.ts +1 -1
- package/dist/core/price-aggregation/index.d.ts.map +1 -1
- package/dist/core/price-aggregation/iris-api-client.d.ts.map +1 -1
- package/dist/core/price-aggregation/iris-api-client.js +5 -5
- package/dist/core/price-aggregation/iris-api-client.js.map +1 -1
- package/dist/core/price-aggregation/iris-pool-discovery.d.ts +2 -2
- package/dist/core/price-aggregation/iris-pool-discovery.d.ts.map +1 -1
- package/dist/core/price-aggregation/iris-pool-discovery.js +3 -3
- package/dist/core/price-aggregation/iris-pool-discovery.js.map +1 -1
- package/dist/core/price-aggregation/multi-exchange-price-service.d.ts +38 -0
- package/dist/core/price-aggregation/multi-exchange-price-service.d.ts.map +1 -0
- package/dist/core/price-aggregation/multi-exchange-price-service.js +123 -0
- package/dist/core/price-aggregation/multi-exchange-price-service.js.map +1 -0
- package/dist/core/price-aggregation/price-cache.d.ts +55 -0
- package/dist/core/price-aggregation/price-cache.d.ts.map +1 -0
- package/dist/core/price-aggregation/price-cache.js +152 -0
- package/dist/core/price-aggregation/price-cache.js.map +1 -0
- package/dist/core/price-aggregation/price-calculator.d.ts.map +1 -1
- package/dist/core/price-aggregation/price-calculator.js +3 -3
- package/dist/core/price-aggregation/price-calculator.js.map +1 -1
- package/dist/core/risk-management/risk-manager.d.ts.map +1 -1
- package/dist/core/risk-management/risk-manager.js +2 -2
- package/dist/core/risk-management/risk-manager.js.map +1 -1
- package/dist/core/strategy/strategy-factory.d.ts +5 -0
- package/dist/core/strategy/strategy-factory.d.ts.map +1 -1
- package/dist/core/strategy/strategy-factory.js +127 -5
- package/dist/core/strategy/strategy-factory.js.map +1 -1
- package/dist/examples/mexc-connector-comprehensive-test.d.ts +15 -0
- package/dist/examples/mexc-connector-comprehensive-test.d.ts.map +1 -0
- package/dist/examples/mexc-connector-comprehensive-test.js +514 -0
- package/dist/examples/mexc-connector-comprehensive-test.js.map +1 -0
- package/dist/examples/mexc-order-update-test.d.ts +4 -0
- package/dist/examples/mexc-order-update-test.d.ts.map +1 -0
- package/dist/examples/mexc-order-update-test.js +186 -0
- package/dist/examples/mexc-order-update-test.js.map +1 -0
- package/dist/examples/mexc-test.d.ts +9 -0
- package/dist/examples/mexc-test.d.ts.map +1 -0
- package/dist/examples/mexc-test.js +218 -0
- package/dist/examples/mexc-test.js.map +1 -0
- package/dist/examples/mexc-trades-debug.d.ts +2 -0
- package/dist/examples/mexc-trades-debug.d.ts.map +1 -0
- package/dist/examples/mexc-trades-debug.js +101 -0
- package/dist/examples/mexc-trades-debug.js.map +1 -0
- package/dist/examples/mexc-trades-subscription-debug.d.ts +2 -0
- package/dist/examples/mexc-trades-subscription-debug.d.ts.map +1 -0
- package/dist/examples/mexc-trades-subscription-debug.js +150 -0
- package/dist/examples/mexc-trades-subscription-debug.js.map +1 -0
- package/dist/examples/mexc-websocket-test.d.ts +8 -0
- package/dist/examples/mexc-websocket-test.d.ts.map +1 -0
- package/dist/examples/mexc-websocket-test.js +115 -0
- package/dist/examples/mexc-websocket-test.js.map +1 -0
- package/dist/examples/test-protobuf-status-detection.d.ts +9 -0
- package/dist/examples/test-protobuf-status-detection.d.ts.map +1 -0
- package/dist/examples/test-protobuf-status-detection.js +83 -0
- package/dist/examples/test-protobuf-status-detection.js.map +1 -0
- package/dist/exchanges/base-exchange-connector.d.ts +33 -0
- package/dist/exchanges/base-exchange-connector.d.ts.map +1 -0
- package/dist/exchanges/base-exchange-connector.js +55 -0
- package/dist/exchanges/base-exchange-connector.js.map +1 -0
- package/dist/exchanges/bitget/bitget-auth.d.ts +66 -0
- package/dist/exchanges/bitget/bitget-auth.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-auth.js +203 -0
- package/dist/exchanges/bitget/bitget-auth.js.map +1 -0
- package/dist/exchanges/bitget/bitget-connector.d.ts +255 -0
- package/dist/exchanges/bitget/bitget-connector.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-connector.js +709 -0
- package/dist/exchanges/bitget/bitget-connector.js.map +1 -0
- package/dist/exchanges/bitget/bitget-data-mapper.d.ts +47 -0
- package/dist/exchanges/bitget/bitget-data-mapper.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-data-mapper.js +147 -0
- package/dist/exchanges/bitget/bitget-data-mapper.js.map +1 -0
- package/dist/exchanges/bitget/bitget-user-stream.d.ts +126 -0
- package/dist/exchanges/bitget/bitget-user-stream.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-user-stream.js +474 -0
- package/dist/exchanges/bitget/bitget-user-stream.js.map +1 -0
- package/dist/exchanges/bitget/bitget-utils.d.ts +17 -0
- package/dist/exchanges/bitget/bitget-utils.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-utils.js +60 -0
- package/dist/exchanges/bitget/bitget-utils.js.map +1 -0
- package/dist/exchanges/bitget/bitget-websocket.d.ts +124 -0
- package/dist/exchanges/bitget/bitget-websocket.d.ts.map +1 -0
- package/dist/exchanges/bitget/bitget-websocket.js +434 -0
- package/dist/exchanges/bitget/bitget-websocket.js.map +1 -0
- package/dist/exchanges/gateio/gateio-auth.d.ts +69 -0
- package/dist/exchanges/gateio/gateio-auth.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-auth.js +205 -0
- package/dist/exchanges/gateio/gateio-auth.js.map +1 -0
- package/dist/exchanges/gateio/gateio-connector.d.ts +182 -0
- package/dist/exchanges/gateio/gateio-connector.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-connector.js +605 -0
- package/dist/exchanges/gateio/gateio-connector.js.map +1 -0
- package/dist/exchanges/gateio/gateio-data-mapper.d.ts +57 -0
- package/dist/exchanges/gateio/gateio-data-mapper.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-data-mapper.js +184 -0
- package/dist/exchanges/gateio/gateio-data-mapper.js.map +1 -0
- package/dist/exchanges/gateio/gateio-user-stream.d.ts +120 -0
- package/dist/exchanges/gateio/gateio-user-stream.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-user-stream.js +384 -0
- package/dist/exchanges/gateio/gateio-user-stream.js.map +1 -0
- package/dist/exchanges/gateio/gateio-utils.d.ts +45 -0
- package/dist/exchanges/gateio/gateio-utils.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-utils.js +138 -0
- package/dist/exchanges/gateio/gateio-utils.js.map +1 -0
- package/dist/exchanges/gateio/gateio-websocket.d.ts +145 -0
- package/dist/exchanges/gateio/gateio-websocket.d.ts.map +1 -0
- package/dist/exchanges/gateio/gateio-websocket.js +469 -0
- package/dist/exchanges/gateio/gateio-websocket.js.map +1 -0
- package/dist/exchanges/kraken/kraken-auth.d.ts +12 -0
- package/dist/exchanges/kraken/kraken-auth.d.ts.map +1 -0
- package/dist/exchanges/kraken/kraken-auth.js +68 -0
- package/dist/exchanges/kraken/kraken-auth.js.map +1 -0
- package/dist/exchanges/kraken/kraken-connector.d.ts +38 -0
- package/dist/exchanges/kraken/kraken-connector.d.ts.map +1 -0
- package/dist/exchanges/kraken/kraken-connector.js +355 -0
- package/dist/exchanges/kraken/kraken-connector.js.map +1 -0
- package/dist/exchanges/kraken/kraken-data-mapper.d.ts +14 -0
- package/dist/exchanges/kraken/kraken-data-mapper.d.ts.map +1 -0
- package/dist/exchanges/kraken/kraken-data-mapper.js +169 -0
- package/dist/exchanges/kraken/kraken-data-mapper.js.map +1 -0
- package/dist/exchanges/kraken/kraken-utils.d.ts +52 -0
- package/dist/exchanges/kraken/kraken-utils.d.ts.map +1 -0
- package/dist/exchanges/kraken/kraken-utils.js +206 -0
- package/dist/exchanges/kraken/kraken-utils.js.map +1 -0
- package/dist/exchanges/kraken/kraken-websocket.d.ts +64 -0
- package/dist/exchanges/kraken/kraken-websocket.d.ts.map +1 -0
- package/dist/exchanges/kraken/kraken-websocket.js +667 -0
- package/dist/exchanges/kraken/kraken-websocket.js.map +1 -0
- package/dist/exchanges/kraken/test-kraken-websocket.d.ts +19 -0
- package/dist/exchanges/kraken/test-kraken-websocket.d.ts.map +1 -0
- package/dist/exchanges/kraken/test-kraken-websocket.js +413 -0
- package/dist/exchanges/kraken/test-kraken-websocket.js.map +1 -0
- package/dist/exchanges/mexc/mexc-auth.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-auth.js +5 -5
- package/dist/exchanges/mexc/mexc-auth.js.map +1 -1
- package/dist/exchanges/mexc/mexc-connector.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-connector.js +12 -13
- package/dist/exchanges/mexc/mexc-connector.js.map +1 -1
- package/dist/exchanges/mexc/mexc-data-mapper.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-data-mapper.js +6 -6
- package/dist/exchanges/mexc/mexc-data-mapper.js.map +1 -1
- package/dist/exchanges/mexc/mexc-protobuf-decoder.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-protobuf-decoder.js +14 -13
- package/dist/exchanges/mexc/mexc-protobuf-decoder.js.map +1 -1
- package/dist/exchanges/mexc/mexc-user-stream.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-user-stream.js +5 -5
- package/dist/exchanges/mexc/mexc-user-stream.js.map +1 -1
- package/dist/exchanges/mexc/mexc-utils.d.ts +1 -5
- package/dist/exchanges/mexc/mexc-utils.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-utils.js +33 -39
- package/dist/exchanges/mexc/mexc-utils.js.map +1 -1
- package/dist/exchanges/mexc/mexc-websocket.d.ts.map +1 -1
- package/dist/exchanges/mexc/mexc-websocket.js +45 -31
- package/dist/exchanges/mexc/mexc-websocket.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/resources/index.d.ts +3 -0
- package/dist/mcp/resources/index.d.ts.map +1 -0
- package/dist/mcp/resources/index.js +11 -0
- package/dist/mcp/resources/index.js.map +1 -0
- package/dist/mcp/server.d.ts +4 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +29 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools/index.d.ts +3 -0
- package/dist/mcp/tools/index.d.ts.map +1 -0
- package/dist/mcp/tools/index.js +12 -0
- package/dist/mcp/tools/index.js.map +1 -0
- package/dist/strategies/grid/grid-calculator.d.ts +63 -4
- package/dist/strategies/grid/grid-calculator.d.ts.map +1 -1
- package/dist/strategies/grid/grid-calculator.js +190 -15
- package/dist/strategies/grid/grid-calculator.js.map +1 -1
- package/dist/strategies/grid/grid-order-manager.d.ts +9 -4
- package/dist/strategies/grid/grid-order-manager.d.ts.map +1 -1
- package/dist/strategies/grid/grid-order-manager.js +58 -15
- package/dist/strategies/grid/grid-order-manager.js.map +1 -1
- package/dist/strategies/grid/grid-strategy.d.ts +11 -0
- package/dist/strategies/grid/grid-strategy.d.ts.map +1 -1
- package/dist/strategies/grid/grid-strategy.js +127 -20
- package/dist/strategies/grid/grid-strategy.js.map +1 -1
- package/dist/strategies/grid/volatility-tracker.d.ts +67 -0
- package/dist/strategies/grid/volatility-tracker.d.ts.map +1 -0
- package/dist/strategies/grid/volatility-tracker.js +109 -0
- package/dist/strategies/grid/volatility-tracker.js.map +1 -0
- package/dist/tests/fixtures/test-helpers.d.ts +5 -0
- package/dist/tests/fixtures/test-helpers.d.ts.map +1 -0
- package/dist/tests/fixtures/test-helpers.js +8 -0
- package/dist/tests/fixtures/test-helpers.js.map +1 -0
- package/dist/tests/integration/exchanges/mexc/mexc-integration.test.d.ts +2 -0
- package/dist/tests/integration/exchanges/mexc/mexc-integration.test.d.ts.map +1 -0
- package/dist/tests/integration/exchanges/mexc/mexc-integration.test.js +237 -0
- package/dist/tests/integration/exchanges/mexc/mexc-integration.test.js.map +1 -0
- package/dist/tests/integration/price-aggregation/cardano-price-service.test.d.ts +2 -0
- package/dist/tests/integration/price-aggregation/cardano-price-service.test.d.ts.map +1 -0
- package/dist/tests/integration/price-aggregation/cardano-price-service.test.js +57 -0
- package/dist/tests/integration/price-aggregation/cardano-price-service.test.js.map +1 -0
- package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.d.ts +2 -0
- package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.d.ts.map +1 -0
- package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.js +141 -0
- package/dist/tests/integration/price-aggregation/price-aggregation-integration.test.js.map +1 -0
- package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.d.ts +2 -0
- package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.d.ts.map +1 -0
- package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.js +375 -0
- package/dist/tests/integration/strategies/grid/grid-strategy-e2e.test.js.map +1 -0
- package/dist/tests/unit/cli/exchange-factory.test.d.ts +2 -0
- package/dist/tests/unit/cli/exchange-factory.test.d.ts.map +1 -0
- package/dist/tests/unit/cli/exchange-factory.test.js +148 -0
- package/dist/tests/unit/cli/exchange-factory.test.js.map +1 -0
- package/dist/tests/unit/config/environment.test.d.ts +2 -0
- package/dist/tests/unit/config/environment.test.d.ts.map +1 -0
- package/dist/tests/unit/config/environment.test.js +158 -0
- package/dist/tests/unit/config/environment.test.js.map +1 -0
- package/dist/tests/unit/config/launcher-config.test.d.ts +2 -0
- package/dist/tests/unit/config/launcher-config.test.d.ts.map +1 -0
- package/dist/tests/unit/config/launcher-config.test.js +117 -0
- package/dist/tests/unit/config/launcher-config.test.js.map +1 -0
- package/dist/tests/unit/config/price-aggregation.test.d.ts +2 -0
- package/dist/tests/unit/config/price-aggregation.test.d.ts.map +1 -0
- package/dist/tests/unit/config/price-aggregation.test.js +144 -0
- package/dist/tests/unit/config/price-aggregation.test.js.map +1 -0
- package/dist/tests/unit/core/exchange/base-exchange-connector.test.d.ts +2 -0
- package/dist/tests/unit/core/exchange/base-exchange-connector.test.d.ts.map +1 -0
- package/dist/tests/unit/core/exchange/base-exchange-connector.test.js +191 -0
- package/dist/tests/unit/core/exchange/base-exchange-connector.test.js.map +1 -0
- package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.d.ts +2 -0
- package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.d.ts.map +1 -0
- package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.js +324 -0
- package/dist/tests/unit/core/exchange/base-exchange-data-mapper.test.js.map +1 -0
- package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.d.ts +2 -0
- package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.d.ts.map +1 -0
- package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.js +177 -0
- package/dist/tests/unit/core/price-aggregation/cardano-price-service.test.js.map +1 -0
- package/dist/tests/unit/core/price-aggregation/iris-api-client.test.d.ts +2 -0
- package/dist/tests/unit/core/price-aggregation/iris-api-client.test.d.ts.map +1 -0
- package/dist/tests/unit/core/price-aggregation/iris-api-client.test.js +168 -0
- package/dist/tests/unit/core/price-aggregation/iris-api-client.test.js.map +1 -0
- package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.d.ts +2 -0
- package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.d.ts.map +1 -0
- package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.js +217 -0
- package/dist/tests/unit/core/price-aggregation/iris-pool-discovery.test.js.map +1 -0
- package/dist/tests/unit/core/price-aggregation/price-calculator.test.d.ts +2 -0
- package/dist/tests/unit/core/price-aggregation/price-calculator.test.d.ts.map +1 -0
- package/dist/tests/unit/core/price-aggregation/price-calculator.test.js +229 -0
- package/dist/tests/unit/core/price-aggregation/price-calculator.test.js.map +1 -0
- package/dist/tests/unit/core/risk-management/risk-manager.test.d.ts +2 -0
- package/dist/tests/unit/core/risk-management/risk-manager.test.d.ts.map +1 -0
- package/dist/tests/unit/core/risk-management/risk-manager.test.js +194 -0
- package/dist/tests/unit/core/risk-management/risk-manager.test.js.map +1 -0
- package/dist/tests/unit/core/strategy/base-strategy.test.d.ts +2 -0
- package/dist/tests/unit/core/strategy/base-strategy.test.d.ts.map +1 -0
- package/dist/tests/unit/core/strategy/base-strategy.test.js +254 -0
- package/dist/tests/unit/core/strategy/base-strategy.test.js.map +1 -0
- package/dist/tests/unit/core/strategy/strategy-factory.test.d.ts +2 -0
- package/dist/tests/unit/core/strategy/strategy-factory.test.d.ts.map +1 -0
- package/dist/tests/unit/core/strategy/strategy-factory.test.js +213 -0
- package/dist/tests/unit/core/strategy/strategy-factory.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-auth.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-auth.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-auth.test.js +452 -0
- package/dist/tests/unit/exchanges/mexc/mexc-auth.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-connector.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-connector.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-connector.test.js +1419 -0
- package/dist/tests/unit/exchanges/mexc/mexc-connector.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.js +435 -0
- package/dist/tests/unit/exchanges/mexc/mexc-data-mapper.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.js +314 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-decoder.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.js +178 -0
- package/dist/tests/unit/exchanges/mexc/mexc-protobuf-status-detection.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.js +502 -0
- package/dist/tests/unit/exchanges/mexc/mexc-user-stream.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-utils.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-utils.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-utils.test.js +317 -0
- package/dist/tests/unit/exchanges/mexc/mexc-utils.test.js.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.d.ts +2 -0
- package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.d.ts.map +1 -0
- package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.js +843 -0
- package/dist/tests/unit/exchanges/mexc/mexc-websocket.test.js.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-calculator.test.d.ts +2 -0
- package/dist/tests/unit/strategies/grid/grid-calculator.test.d.ts.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-calculator.test.js +67 -0
- package/dist/tests/unit/strategies/grid/grid-calculator.test.js.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-order-manager.test.d.ts +2 -0
- package/dist/tests/unit/strategies/grid/grid-order-manager.test.d.ts.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-order-manager.test.js +211 -0
- package/dist/tests/unit/strategies/grid/grid-order-manager.test.js.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.d.ts +2 -0
- package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.d.ts.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.js +197 -0
- package/dist/tests/unit/strategies/grid/grid-strategy-simple.test.js.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-strategy.test.d.ts +2 -0
- package/dist/tests/unit/strategies/grid/grid-strategy.test.d.ts.map +1 -0
- package/dist/tests/unit/strategies/grid/grid-strategy.test.js +429 -0
- package/dist/tests/unit/strategies/grid/grid-strategy.test.js.map +1 -0
- package/dist/tests/unit/utils/logger.test.d.ts +2 -0
- package/dist/tests/unit/utils/logger.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/logger.test.js +260 -0
- package/dist/tests/unit/utils/logger.test.js.map +1 -0
- package/dist/tests/unit/utils/symbol-utils.test.d.ts +2 -0
- package/dist/tests/unit/utils/symbol-utils.test.d.ts.map +1 -0
- package/dist/tests/unit/utils/symbol-utils.test.js +178 -0
- package/dist/tests/unit/utils/symbol-utils.test.js.map +1 -0
- package/dist/types/bitget-raw.d.ts +75 -0
- package/dist/types/bitget-raw.d.ts.map +1 -0
- package/dist/types/bitget-raw.js +10 -0
- package/dist/types/bitget-raw.js.map +1 -0
- package/dist/types/bitget.d.ts +35 -0
- package/dist/types/bitget.d.ts.map +1 -0
- package/dist/types/bitget.js +8 -0
- package/dist/types/bitget.js.map +1 -0
- package/dist/types/gateio-raw.d.ts +104 -0
- package/dist/types/gateio-raw.d.ts.map +1 -0
- package/dist/types/gateio-raw.js +7 -0
- package/dist/types/gateio-raw.js.map +1 -0
- package/dist/types/gateio.d.ts +41 -0
- package/dist/types/gateio.d.ts.map +1 -0
- package/dist/types/gateio.js +8 -0
- package/dist/types/gateio.js.map +1 -0
- package/dist/types/grid.d.ts +77 -0
- package/dist/types/grid.d.ts.map +1 -1
- package/dist/types/index.d.ts +6 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +6 -0
- package/dist/types/index.js.map +1 -1
- package/dist/types/kraken-raw.d.ts +89 -0
- package/dist/types/kraken-raw.d.ts.map +1 -0
- package/dist/types/kraken-raw.js +10 -0
- package/dist/types/kraken-raw.js.map +1 -0
- package/dist/types/kraken.d.ts +44 -0
- package/dist/types/kraken.d.ts.map +1 -0
- package/dist/types/kraken.js +3 -0
- package/dist/types/kraken.js.map +1 -0
- package/dist/types/mexc.d.ts +9 -0
- package/dist/types/mexc.d.ts.map +1 -1
- package/dist/types/price-aggregation.d.ts +31 -0
- package/dist/types/price-aggregation.d.ts.map +1 -0
- package/dist/types/price-aggregation.js +6 -0
- package/dist/types/price-aggregation.js.map +1 -0
- package/dist/types/price.d.ts +23 -0
- package/dist/types/price.d.ts.map +1 -1
- package/dist/types/strategy.d.ts +5 -0
- package/dist/types/strategy.d.ts.map +1 -1
- package/dist/utils/crypto.d.ts +15 -0
- package/dist/utils/crypto.d.ts.map +1 -0
- package/dist/utils/crypto.js +50 -0
- package/dist/utils/crypto.js.map +1 -0
- package/dist/utils/exchange-utils.d.ts +194 -0
- package/dist/utils/exchange-utils.d.ts.map +1 -0
- package/dist/utils/exchange-utils.js +455 -0
- package/dist/utils/exchange-utils.js.map +1 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +3 -1
- package/dist/utils/index.js.map +1 -1
- package/dist/utils/logger.d.ts +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +7 -7
- package/dist/utils/logger.js.map +1 -1
- package/dist/utils/validation.d.ts +36 -0
- package/dist/utils/validation.d.ts.map +1 -0
- package/dist/utils/validation.js +174 -0
- package/dist/utils/validation.js.map +1 -0
- package/package.json +7 -1
|
@@ -0,0 +1,843 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const mexc_websocket_1 = require("../../../../exchanges/mexc/mexc-websocket");
|
|
7
|
+
const mexc_protobuf_decoder_1 = require("../../../../exchanges/mexc/mexc-protobuf-decoder");
|
|
8
|
+
const mexc_utils_1 = require("../../../../exchanges/mexc/mexc-utils");
|
|
9
|
+
const utils_1 = require("../../../../utils");
|
|
10
|
+
const symbol_utils_1 = require("../../../../utils/symbol-utils");
|
|
11
|
+
jest.mock('../../../../utils/symbol-utils');
|
|
12
|
+
const MockedToStandardFormat = symbol_utils_1.toStandardFormat;
|
|
13
|
+
const MockedToExchangeFormat = symbol_utils_1.toExchangeFormat;
|
|
14
|
+
const ws_1 = __importDefault(require("ws"));
|
|
15
|
+
jest.mock('ws');
|
|
16
|
+
jest.mock('../../../../exchanges/mexc/mexc-protobuf-decoder');
|
|
17
|
+
jest.mock('../../../../exchanges/mexc/mexc-utils');
|
|
18
|
+
jest.mock('../../../../utils');
|
|
19
|
+
const MockedWebSocket = ws_1.default;
|
|
20
|
+
const MockedMexcProtobufDecoder = mexc_protobuf_decoder_1.MexcProtobufDecoder;
|
|
21
|
+
const MockedMexcUtils = mexc_utils_1.MexcUtils;
|
|
22
|
+
const MockedCreateLogger = utils_1.createLogger;
|
|
23
|
+
describe('MexcWebSocket', () => {
|
|
24
|
+
let mexcWebSocket;
|
|
25
|
+
let mockWs;
|
|
26
|
+
let mockLogger;
|
|
27
|
+
const connectWebSocket = async (wsInstance = mexcWebSocket) => {
|
|
28
|
+
const connectPromise = wsInstance.connectWebSocket();
|
|
29
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
30
|
+
if (openCall) {
|
|
31
|
+
openCall[1]();
|
|
32
|
+
}
|
|
33
|
+
await connectPromise;
|
|
34
|
+
};
|
|
35
|
+
const setupTradesSubscription = async (symbol = 'BTC/USDT') => {
|
|
36
|
+
const callback = jest.fn();
|
|
37
|
+
await mexcWebSocket.subscribeTrades(symbol, callback);
|
|
38
|
+
return callback;
|
|
39
|
+
};
|
|
40
|
+
const setupTickerSubscription = async (symbol = 'BTC/USDT') => {
|
|
41
|
+
const callback = jest.fn();
|
|
42
|
+
await mexcWebSocket.subscribeTicker(symbol, callback);
|
|
43
|
+
return callback;
|
|
44
|
+
};
|
|
45
|
+
const triggerMessage = (messageContent, decodedMessage) => {
|
|
46
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
47
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
48
|
+
if (messageCall) {
|
|
49
|
+
const buffer = Buffer.from(messageContent);
|
|
50
|
+
messageCall[1](buffer);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
const createMockTickerMessage = (overrides = {}) => ({
|
|
54
|
+
type: 'ticker',
|
|
55
|
+
raw: 'spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT',
|
|
56
|
+
channel: 'spot@public.aggre.bookTicker.v3.api.pb',
|
|
57
|
+
symbol: 'BTCUSDT',
|
|
58
|
+
decoded: {
|
|
59
|
+
bidprice: '50000',
|
|
60
|
+
askprice: '50100',
|
|
61
|
+
bidquantity: '1.0',
|
|
62
|
+
askquantity: '1.5'
|
|
63
|
+
},
|
|
64
|
+
...overrides
|
|
65
|
+
});
|
|
66
|
+
const createMockTradesMessage = (overrides = {}) => ({
|
|
67
|
+
type: 'trades',
|
|
68
|
+
raw: 'spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT',
|
|
69
|
+
channel: 'spot@public.aggre.deals.v3.api.pb',
|
|
70
|
+
symbol: 'BTCUSDT',
|
|
71
|
+
decoded: {
|
|
72
|
+
dealsList: [{
|
|
73
|
+
price: '50000',
|
|
74
|
+
quantity: '1.0',
|
|
75
|
+
time: '1640995200000',
|
|
76
|
+
tradetype: 1
|
|
77
|
+
}],
|
|
78
|
+
eventtype: 'trade'
|
|
79
|
+
},
|
|
80
|
+
...overrides
|
|
81
|
+
});
|
|
82
|
+
const createMockOrderMessage = (overrides = {}) => ({
|
|
83
|
+
type: 'order',
|
|
84
|
+
raw: 'spot@private.orders.v3.api.pbBTCUSDT',
|
|
85
|
+
channel: 'spot@private.orders.v3.api.pb',
|
|
86
|
+
symbol: 'BTCUSDT',
|
|
87
|
+
decoded: {
|
|
88
|
+
orderId: 'order123',
|
|
89
|
+
symbol: 'BTCUSDT',
|
|
90
|
+
price: 50000,
|
|
91
|
+
quantity: 1.0,
|
|
92
|
+
side: 'buy',
|
|
93
|
+
status: 'filled',
|
|
94
|
+
timestamp: Date.now(),
|
|
95
|
+
channel: 'spot@private.orders.v3.api.pb'
|
|
96
|
+
},
|
|
97
|
+
...overrides
|
|
98
|
+
});
|
|
99
|
+
const createMockOrder = (overrides = {}) => ({
|
|
100
|
+
id: 'order123',
|
|
101
|
+
symbol: 'BTC/USDT',
|
|
102
|
+
type: 'limit',
|
|
103
|
+
side: 'buy',
|
|
104
|
+
amount: 1.0,
|
|
105
|
+
price: 50000,
|
|
106
|
+
filled: 1.0,
|
|
107
|
+
remaining: 0,
|
|
108
|
+
status: 'filled',
|
|
109
|
+
timestamp: Date.now(),
|
|
110
|
+
...overrides
|
|
111
|
+
});
|
|
112
|
+
beforeEach(() => {
|
|
113
|
+
jest.clearAllMocks();
|
|
114
|
+
mockLogger = {
|
|
115
|
+
info: jest.fn(),
|
|
116
|
+
warn: jest.fn(),
|
|
117
|
+
error: jest.fn(),
|
|
118
|
+
debug: jest.fn()
|
|
119
|
+
};
|
|
120
|
+
MockedCreateLogger.mockReturnValue(mockLogger);
|
|
121
|
+
mockWs = {
|
|
122
|
+
on: jest.fn(),
|
|
123
|
+
send: jest.fn(),
|
|
124
|
+
close: jest.fn(),
|
|
125
|
+
get readyState() { return ws_1.default.OPEN; }
|
|
126
|
+
};
|
|
127
|
+
MockedWebSocket.mockImplementation(() => mockWs);
|
|
128
|
+
MockedToStandardFormat.mockImplementation((symbol) => {
|
|
129
|
+
if (symbol.includes('/'))
|
|
130
|
+
return symbol;
|
|
131
|
+
return symbol.replace(/([A-Z]+)(USDT|BTC|ETH)$/, '$1/$2');
|
|
132
|
+
});
|
|
133
|
+
MockedToExchangeFormat.mockImplementation((symbol) => symbol.replace('/', ''));
|
|
134
|
+
mexcWebSocket = new mexc_websocket_1.MexcWebSocket();
|
|
135
|
+
});
|
|
136
|
+
describe('constructor', () => {
|
|
137
|
+
it('should initialize with default websocket URL', () => {
|
|
138
|
+
const ws = new mexc_websocket_1.MexcWebSocket();
|
|
139
|
+
expect(ws).toBeInstanceOf(mexc_websocket_1.MexcWebSocket);
|
|
140
|
+
expect(MockedCreateLogger).toHaveBeenCalledWith('mexc-websocket');
|
|
141
|
+
});
|
|
142
|
+
it('should initialize with custom websocket URL', () => {
|
|
143
|
+
const customUrl = 'wss://custom.mexc.com/ws';
|
|
144
|
+
const ws = new mexc_websocket_1.MexcWebSocket(customUrl);
|
|
145
|
+
expect(ws).toBeInstanceOf(mexc_websocket_1.MexcWebSocket);
|
|
146
|
+
});
|
|
147
|
+
it('should have initial status as disconnected', () => {
|
|
148
|
+
const ws = new mexc_websocket_1.MexcWebSocket();
|
|
149
|
+
expect(ws.getWebSocketStatus()).toBe('disconnected');
|
|
150
|
+
expect(ws.isConnected()).toBe(false);
|
|
151
|
+
});
|
|
152
|
+
});
|
|
153
|
+
describe('connectWebSocket()', () => {
|
|
154
|
+
it('should successfully connect to WebSocket via onOpen()', async () => {
|
|
155
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
156
|
+
const onCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
157
|
+
if (onCall && onCall[1]) {
|
|
158
|
+
onCall[1]();
|
|
159
|
+
}
|
|
160
|
+
await connectPromise;
|
|
161
|
+
expect(MockedWebSocket).toHaveBeenCalledWith('wss://wbs-api.mexc.com/ws');
|
|
162
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('connected');
|
|
163
|
+
expect(mockLogger.info).toHaveBeenCalledWith('✅ WebSocket connected successfully');
|
|
164
|
+
});
|
|
165
|
+
it('should handle WebSocket connection error via onError()', async () => {
|
|
166
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
167
|
+
const error = new Error('Connection failed');
|
|
168
|
+
const errorCall = mockWs.on.mock.calls.find(([event]) => event === 'error');
|
|
169
|
+
if (errorCall) {
|
|
170
|
+
errorCall[1](error);
|
|
171
|
+
}
|
|
172
|
+
await expect(connectPromise).rejects.toThrow('Connection failed');
|
|
173
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('error');
|
|
174
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ WebSocket error:', { error: 'Connection failed' });
|
|
175
|
+
});
|
|
176
|
+
it('should handle WebSocket close event via onClose()', async () => {
|
|
177
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
178
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
179
|
+
if (openCall) {
|
|
180
|
+
openCall[1]();
|
|
181
|
+
}
|
|
182
|
+
await connectPromise;
|
|
183
|
+
const closeCall = mockWs.on.mock.calls.find(([event]) => event === 'close');
|
|
184
|
+
if (closeCall) {
|
|
185
|
+
closeCall[1]();
|
|
186
|
+
}
|
|
187
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('disconnected');
|
|
188
|
+
});
|
|
189
|
+
it('should handle connection setup errors via onError()', async () => {
|
|
190
|
+
MockedWebSocket.mockImplementation(() => {
|
|
191
|
+
throw new Error('WebSocket creation failed');
|
|
192
|
+
});
|
|
193
|
+
await expect(mexcWebSocket.connectWebSocket()).rejects.toThrow('WebSocket creation failed');
|
|
194
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('error');
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('onMessage() - Message handler', () => {
|
|
198
|
+
beforeEach(async () => {
|
|
199
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
200
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
201
|
+
if (openCall) {
|
|
202
|
+
openCall[1]();
|
|
203
|
+
}
|
|
204
|
+
await connectPromise;
|
|
205
|
+
});
|
|
206
|
+
it('should process valid spot messages', () => {
|
|
207
|
+
const mockDecodedMessage = createMockTickerMessage();
|
|
208
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(mockDecodedMessage);
|
|
209
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
210
|
+
if (messageCall) {
|
|
211
|
+
const buffer = Buffer.from('spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT');
|
|
212
|
+
messageCall[1](buffer);
|
|
213
|
+
}
|
|
214
|
+
expect(MockedMexcProtobufDecoder.decode).toHaveBeenCalledWith('spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT');
|
|
215
|
+
});
|
|
216
|
+
it('should ignore non-spot messages', () => {
|
|
217
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
218
|
+
if (messageCall) {
|
|
219
|
+
const buffer = Buffer.from('non-spot-message');
|
|
220
|
+
messageCall[1](buffer);
|
|
221
|
+
}
|
|
222
|
+
expect(MockedMexcProtobufDecoder.decode).not.toHaveBeenCalled();
|
|
223
|
+
});
|
|
224
|
+
it('should handle messages with decode errors', () => {
|
|
225
|
+
const mockDecodedMessage = {
|
|
226
|
+
type: 'unknown',
|
|
227
|
+
raw: 'invalid-message',
|
|
228
|
+
channel: 'unknown',
|
|
229
|
+
error: 'Decode error occurred'
|
|
230
|
+
};
|
|
231
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(mockDecodedMessage);
|
|
232
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
233
|
+
if (messageCall) {
|
|
234
|
+
const buffer = Buffer.from('spot@invalid.message');
|
|
235
|
+
messageCall[1](buffer);
|
|
236
|
+
}
|
|
237
|
+
expect(mockLogger.warn).toHaveBeenCalledWith('Protobuf decode error:', { error: 'Decode error occurred' });
|
|
238
|
+
});
|
|
239
|
+
it('should handle message processing errors', () => {
|
|
240
|
+
MockedMexcProtobufDecoder.decode.mockImplementation(() => {
|
|
241
|
+
throw new Error('Processing error');
|
|
242
|
+
});
|
|
243
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
244
|
+
if (messageCall) {
|
|
245
|
+
const buffer = Buffer.from('spot@test.message');
|
|
246
|
+
messageCall[1](buffer);
|
|
247
|
+
}
|
|
248
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Message handling error:', { error: expect.any(Error) });
|
|
249
|
+
});
|
|
250
|
+
});
|
|
251
|
+
describe('processDecodedMessage() - Process decoded message based on type', () => {
|
|
252
|
+
let orderCallback;
|
|
253
|
+
let tickerCallback;
|
|
254
|
+
let tradesCallback;
|
|
255
|
+
let orderbookCallback;
|
|
256
|
+
beforeEach(async () => {
|
|
257
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
258
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
259
|
+
if (openCall) {
|
|
260
|
+
openCall[1]();
|
|
261
|
+
}
|
|
262
|
+
await connectPromise;
|
|
263
|
+
orderCallback = jest.fn();
|
|
264
|
+
tickerCallback = jest.fn();
|
|
265
|
+
tradesCallback = jest.fn();
|
|
266
|
+
orderbookCallback = jest.fn();
|
|
267
|
+
await mexcWebSocket.subscribeOrders(orderCallback);
|
|
268
|
+
await mexcWebSocket.subscribeTicker('BTC/USDT', tickerCallback);
|
|
269
|
+
await mexcWebSocket.subscribeTrades('BTC/USDT', tradesCallback);
|
|
270
|
+
await mexcWebSocket.subscribeOrderBook('BTC/USDT', orderbookCallback);
|
|
271
|
+
});
|
|
272
|
+
it('should process order messages via onOrderUpdate()', () => {
|
|
273
|
+
const mockOrder = createMockOrder();
|
|
274
|
+
MockedMexcUtils.transformOrder.mockReturnValue(mockOrder);
|
|
275
|
+
const decodedMessage = createMockOrderMessage();
|
|
276
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
277
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
278
|
+
if (messageCall) {
|
|
279
|
+
const buffer = Buffer.from('spot@private.orders.v3.api.pbBTCUSDT');
|
|
280
|
+
messageCall[1](buffer);
|
|
281
|
+
}
|
|
282
|
+
expect(MockedMexcUtils.transformOrder).toHaveBeenCalled();
|
|
283
|
+
expect(orderCallback).toHaveBeenCalledWith(mockOrder);
|
|
284
|
+
});
|
|
285
|
+
it('should process ticker messages via onTickerUpdate() and onOrderBookUpdate()', () => {
|
|
286
|
+
const decodedMessage = createMockTickerMessage();
|
|
287
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
288
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
289
|
+
if (messageCall) {
|
|
290
|
+
const buffer = Buffer.from('spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT');
|
|
291
|
+
messageCall[1](buffer);
|
|
292
|
+
}
|
|
293
|
+
expect(tickerCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
294
|
+
symbol: 'BTC/USDT',
|
|
295
|
+
bid: 50000,
|
|
296
|
+
ask: 50100,
|
|
297
|
+
baseVolume: 2.5
|
|
298
|
+
}));
|
|
299
|
+
expect(orderbookCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
300
|
+
symbol: 'BTC/USDT',
|
|
301
|
+
bids: [{ price: 50000, amount: 1.0 }],
|
|
302
|
+
asks: [{ price: 50100, amount: 1.5 }]
|
|
303
|
+
}));
|
|
304
|
+
});
|
|
305
|
+
it('should process trades messages via onTradesUpdate()', () => {
|
|
306
|
+
const decodedMessage = createMockTradesMessage();
|
|
307
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
308
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
309
|
+
if (messageCall) {
|
|
310
|
+
const buffer = Buffer.from('spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT');
|
|
311
|
+
messageCall[1](buffer);
|
|
312
|
+
}
|
|
313
|
+
expect(tradesCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
314
|
+
symbol: 'BTC/USDT',
|
|
315
|
+
side: 'buy',
|
|
316
|
+
amount: 1.0,
|
|
317
|
+
price: 50000,
|
|
318
|
+
timestamp: 1640995200000
|
|
319
|
+
}));
|
|
320
|
+
});
|
|
321
|
+
it('should handle unknown message types', () => {
|
|
322
|
+
const decodedMessage = {
|
|
323
|
+
type: 'unknown',
|
|
324
|
+
raw: 'spot@unknown.message',
|
|
325
|
+
channel: 'spot@unknown.message'
|
|
326
|
+
};
|
|
327
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
328
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
329
|
+
if (messageCall) {
|
|
330
|
+
const buffer = Buffer.from('spot@unknown.message');
|
|
331
|
+
messageCall[1](buffer);
|
|
332
|
+
}
|
|
333
|
+
expect(mockLogger.debug).toHaveBeenCalledWith('Unhandled message type: unknown');
|
|
334
|
+
});
|
|
335
|
+
it('should handle order processing errors in onOrderUpdate()', () => {
|
|
336
|
+
MockedMexcUtils.transformOrder.mockImplementation(() => {
|
|
337
|
+
throw new Error('Transform error');
|
|
338
|
+
});
|
|
339
|
+
const decodedMessage = createMockOrderMessage();
|
|
340
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
341
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
342
|
+
if (messageCall) {
|
|
343
|
+
const buffer = Buffer.from('spot@private.orders.v3.api.pbBTCUSDT');
|
|
344
|
+
messageCall[1](buffer);
|
|
345
|
+
}
|
|
346
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error handling protobuf user data message:', { error: expect.any(Error), message: expect.any(String) });
|
|
347
|
+
});
|
|
348
|
+
it('should handle ticker processing errors gracefully', () => {
|
|
349
|
+
MockedToStandardFormat.mockImplementation(() => {
|
|
350
|
+
throw new Error('Format error');
|
|
351
|
+
});
|
|
352
|
+
const decodedMessage = createMockTickerMessage();
|
|
353
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
354
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
355
|
+
if (messageCall) {
|
|
356
|
+
const buffer = Buffer.from('spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT');
|
|
357
|
+
messageCall[1](buffer);
|
|
358
|
+
}
|
|
359
|
+
// Should handle symbol conversion error gracefully by using original symbol
|
|
360
|
+
expect(tickerCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
361
|
+
symbol: 'BTCUSDT', // Falls back to original symbol
|
|
362
|
+
bid: 50000,
|
|
363
|
+
ask: 50100
|
|
364
|
+
}));
|
|
365
|
+
});
|
|
366
|
+
it('should handle trades processing errors gracefully', () => {
|
|
367
|
+
MockedToStandardFormat.mockImplementation(() => {
|
|
368
|
+
throw new Error('Format error');
|
|
369
|
+
});
|
|
370
|
+
const decodedMessage = createMockTradesMessage();
|
|
371
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
372
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
373
|
+
if (messageCall) {
|
|
374
|
+
const buffer = Buffer.from('spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT');
|
|
375
|
+
messageCall[1](buffer);
|
|
376
|
+
}
|
|
377
|
+
// Should handle symbol conversion error gracefully by using original symbol
|
|
378
|
+
expect(tradesCallback).toHaveBeenCalledWith(expect.objectContaining({
|
|
379
|
+
symbol: 'BTCUSDT', // Falls back to original symbol
|
|
380
|
+
side: 'buy',
|
|
381
|
+
amount: 1.0,
|
|
382
|
+
price: 50000
|
|
383
|
+
}));
|
|
384
|
+
});
|
|
385
|
+
it('should skip processing messages without required data in onOrderUpdate(), onTickerUpdate(), onTradesUpdate()', () => {
|
|
386
|
+
const decodedMessages = [
|
|
387
|
+
{ type: 'order', raw: 'test', channel: 'test' },
|
|
388
|
+
{ type: 'ticker', raw: 'test', channel: 'test', decoded: {} },
|
|
389
|
+
{ type: 'trades', raw: 'test', channel: 'test', symbol: 'BTCUSDT' }
|
|
390
|
+
];
|
|
391
|
+
decodedMessages.forEach((decodedMessage) => {
|
|
392
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
393
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
394
|
+
if (messageCall) {
|
|
395
|
+
const buffer = Buffer.from('spot@test.message');
|
|
396
|
+
messageCall[1](buffer);
|
|
397
|
+
}
|
|
398
|
+
});
|
|
399
|
+
expect(orderCallback).not.toHaveBeenCalled();
|
|
400
|
+
expect(tickerCallback).not.toHaveBeenCalled();
|
|
401
|
+
expect(tradesCallback).not.toHaveBeenCalled();
|
|
402
|
+
});
|
|
403
|
+
});
|
|
404
|
+
describe('subscription methods - subscribeTicker(), subscribeTrades(), subscribeOrderBook(), subscribeOrders()', () => {
|
|
405
|
+
beforeEach(async () => {
|
|
406
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
407
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
408
|
+
if (openCall) {
|
|
409
|
+
openCall[1]();
|
|
410
|
+
}
|
|
411
|
+
await connectPromise;
|
|
412
|
+
});
|
|
413
|
+
it('should subscribe to ticker updates', async () => {
|
|
414
|
+
const callback = jest.fn();
|
|
415
|
+
const subscriptionId = await mexcWebSocket.subscribeTicker('BTC/USDT', callback);
|
|
416
|
+
expect(subscriptionId).toMatch(/^ticker_BTCUSDT_\d+$/);
|
|
417
|
+
expect(mockWs.send).toHaveBeenCalledWith(JSON.stringify({
|
|
418
|
+
method: 'SUBSCRIPTION',
|
|
419
|
+
params: ['spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT']
|
|
420
|
+
}));
|
|
421
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Subscribed to ticker: BTC/USDT (spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT)');
|
|
422
|
+
});
|
|
423
|
+
it('should subscribe to trades updates', async () => {
|
|
424
|
+
const callback = jest.fn();
|
|
425
|
+
const subscriptionId = await mexcWebSocket.subscribeTrades('BTC/USDT', callback);
|
|
426
|
+
expect(subscriptionId).toMatch(/^trades_BTCUSDT_\d+$/);
|
|
427
|
+
expect(mockWs.send).toHaveBeenCalledWith(JSON.stringify({
|
|
428
|
+
method: 'SUBSCRIPTION',
|
|
429
|
+
params: ['spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT']
|
|
430
|
+
}));
|
|
431
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Subscribed to trades: BTC/USDT (spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT)');
|
|
432
|
+
});
|
|
433
|
+
it('should subscribe to orderbook updates', async () => {
|
|
434
|
+
const callback = jest.fn();
|
|
435
|
+
const subscriptionId = await mexcWebSocket.subscribeOrderBook('BTC/USDT', callback);
|
|
436
|
+
expect(subscriptionId).toMatch(/^orderbook_BTCUSDT_\d+$/);
|
|
437
|
+
expect(mockWs.send).toHaveBeenCalledWith(JSON.stringify({
|
|
438
|
+
method: 'SUBSCRIPTION',
|
|
439
|
+
params: ['spot@public.bookTicker.batch.v3.api.pb@BTCUSDT']
|
|
440
|
+
}));
|
|
441
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Subscribed to orderbook: BTC/USDT (spot@public.bookTicker.batch.v3.api.pb@BTCUSDT)');
|
|
442
|
+
});
|
|
443
|
+
it('should subscribe to user orders', async () => {
|
|
444
|
+
const callback = jest.fn();
|
|
445
|
+
const subscriptionId = await mexcWebSocket.subscribeOrders(callback);
|
|
446
|
+
expect(subscriptionId).toMatch(/^orders_\d+$/);
|
|
447
|
+
expect(mockLogger.info).toHaveBeenCalledWith('Subscribed to user orders (orders stream)');
|
|
448
|
+
});
|
|
449
|
+
it('should subscribe to user data', async () => {
|
|
450
|
+
const callback = jest.fn();
|
|
451
|
+
const subscriptionId = await mexcWebSocket.subscribeToUserData(callback);
|
|
452
|
+
expect(subscriptionId).toMatch(/^user_data_\d+$/);
|
|
453
|
+
});
|
|
454
|
+
it('should throw error when subscribing without connection', async () => {
|
|
455
|
+
await mexcWebSocket.disconnectWebSocket();
|
|
456
|
+
const callback = jest.fn();
|
|
457
|
+
await expect(mexcWebSocket.subscribeTicker('BTC/USDT', callback)).rejects.toThrow('WebSocket not connected');
|
|
458
|
+
await expect(mexcWebSocket.subscribeTrades('BTC/USDT', callback)).rejects.toThrow('WebSocket not connected');
|
|
459
|
+
await expect(mexcWebSocket.subscribeOrderBook('BTC/USDT', callback)).rejects.toThrow('WebSocket not connected');
|
|
460
|
+
});
|
|
461
|
+
});
|
|
462
|
+
describe('unsubscribe() - Unsubscribe from subscription', () => {
|
|
463
|
+
it('should unsubscribe from existing subscription', async () => {
|
|
464
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
465
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
466
|
+
if (openCall) {
|
|
467
|
+
openCall[1]();
|
|
468
|
+
}
|
|
469
|
+
await connectPromise;
|
|
470
|
+
const callback = jest.fn();
|
|
471
|
+
const subscriptionId = await mexcWebSocket.subscribeTicker('BTC/USDT', callback);
|
|
472
|
+
await mexcWebSocket.unsubscribe(subscriptionId);
|
|
473
|
+
expect(mockLogger.info).toHaveBeenCalledWith(`Unsubscribed: ${subscriptionId}`);
|
|
474
|
+
});
|
|
475
|
+
it('should warn when unsubscribing non-existent subscription', async () => {
|
|
476
|
+
await mexcWebSocket.unsubscribe('non-existent-id');
|
|
477
|
+
expect(mockLogger.warn).toHaveBeenCalledWith('Subscription non-existent-id not found');
|
|
478
|
+
});
|
|
479
|
+
});
|
|
480
|
+
describe('disconnectWebSocket() - Disconnect and cleanup', () => {
|
|
481
|
+
it('should disconnect and cleanup', async () => {
|
|
482
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
483
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
484
|
+
if (openCall) {
|
|
485
|
+
openCall[1]();
|
|
486
|
+
}
|
|
487
|
+
await connectPromise;
|
|
488
|
+
await mexcWebSocket.subscribeTicker('BTC/USDT', jest.fn());
|
|
489
|
+
await mexcWebSocket.disconnectWebSocket();
|
|
490
|
+
expect(mockWs.close).toHaveBeenCalled();
|
|
491
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('disconnected');
|
|
492
|
+
expect(mexcWebSocket.isConnected()).toBe(false);
|
|
493
|
+
});
|
|
494
|
+
it('should handle disconnect when not connected', async () => {
|
|
495
|
+
await mexcWebSocket.disconnectWebSocket();
|
|
496
|
+
expect(mockWs.close).not.toHaveBeenCalled();
|
|
497
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('disconnected');
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
describe('status methods - isConnected(), getWebSocketStatus()', () => {
|
|
501
|
+
it('should return correct connection status', () => {
|
|
502
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('disconnected');
|
|
503
|
+
expect(mexcWebSocket.isConnected()).toBe(false);
|
|
504
|
+
});
|
|
505
|
+
it('should return true when connected', async () => {
|
|
506
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
507
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
508
|
+
if (openCall) {
|
|
509
|
+
openCall[1]();
|
|
510
|
+
}
|
|
511
|
+
await connectPromise;
|
|
512
|
+
expect(mexcWebSocket.getWebSocketStatus()).toBe('connected');
|
|
513
|
+
expect(mexcWebSocket.isConnected()).toBe(true);
|
|
514
|
+
});
|
|
515
|
+
it('should return false when WebSocket readyState is not OPEN', async () => {
|
|
516
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
517
|
+
const openCall = mockWs.on.mock.calls.find(([event]) => event === 'open');
|
|
518
|
+
if (openCall) {
|
|
519
|
+
openCall[1]();
|
|
520
|
+
}
|
|
521
|
+
await connectPromise;
|
|
522
|
+
mexcWebSocket.ws = {
|
|
523
|
+
...mockWs,
|
|
524
|
+
get readyState() {
|
|
525
|
+
return ws_1.default.CLOSED;
|
|
526
|
+
}
|
|
527
|
+
};
|
|
528
|
+
expect(mexcWebSocket.isConnected()).toBe(false);
|
|
529
|
+
});
|
|
530
|
+
});
|
|
531
|
+
describe('edge cases - onTradesUpdate(), onTickerUpdate()', () => {
|
|
532
|
+
it('should handle trades with empty dealsList in onTradesUpdate()', async () => {
|
|
533
|
+
await connectWebSocket();
|
|
534
|
+
const callback = await setupTradesSubscription();
|
|
535
|
+
const decodedMessage = createMockTradesMessage({
|
|
536
|
+
decoded: {
|
|
537
|
+
dealsList: [],
|
|
538
|
+
eventtype: 'trade'
|
|
539
|
+
}
|
|
540
|
+
});
|
|
541
|
+
triggerMessage('spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT', decodedMessage);
|
|
542
|
+
expect(callback).not.toHaveBeenCalled();
|
|
543
|
+
});
|
|
544
|
+
it('should handle trades with null dealsList in onTradesUpdate()', async () => {
|
|
545
|
+
await connectWebSocket();
|
|
546
|
+
const callback = await setupTradesSubscription();
|
|
547
|
+
const decodedMessage = createMockTradesMessage({
|
|
548
|
+
decoded: {
|
|
549
|
+
dealsList: null,
|
|
550
|
+
eventtype: 'trade'
|
|
551
|
+
}
|
|
552
|
+
});
|
|
553
|
+
triggerMessage('spot@public.aggre.deals.v3.api.pb@100ms@BTCUSDT', decodedMessage);
|
|
554
|
+
expect(callback).not.toHaveBeenCalled();
|
|
555
|
+
});
|
|
556
|
+
it('should handle ticker data with zero values in onTickerUpdate()', async () => {
|
|
557
|
+
await connectWebSocket();
|
|
558
|
+
const callback = await setupTickerSubscription();
|
|
559
|
+
const decodedMessage = createMockTickerMessage({
|
|
560
|
+
decoded: {
|
|
561
|
+
bidprice: '0',
|
|
562
|
+
askprice: '0',
|
|
563
|
+
bidquantity: '0',
|
|
564
|
+
askquantity: '0'
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
triggerMessage('spot@public.aggre.bookTicker.v3.api.pb@100ms@BTCUSDT', decodedMessage);
|
|
568
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining({
|
|
569
|
+
symbol: 'BTC/USDT',
|
|
570
|
+
bid: 0,
|
|
571
|
+
ask: 0,
|
|
572
|
+
baseVolume: 0
|
|
573
|
+
}));
|
|
574
|
+
});
|
|
575
|
+
});
|
|
576
|
+
describe('error handling coverage', () => {
|
|
577
|
+
beforeEach(() => {
|
|
578
|
+
jest.useFakeTimers();
|
|
579
|
+
});
|
|
580
|
+
afterEach(() => {
|
|
581
|
+
jest.useRealTimers();
|
|
582
|
+
});
|
|
583
|
+
it('should handle WebSocket constructor error (line 51-53)', async () => {
|
|
584
|
+
MockedWebSocket.mockImplementationOnce(() => {
|
|
585
|
+
throw new Error('WebSocket constructor failed');
|
|
586
|
+
});
|
|
587
|
+
await expect(mexcWebSocket.connectWebSocket()).rejects.toThrow('WebSocket constructor failed');
|
|
588
|
+
});
|
|
589
|
+
it('should handle onError with reject callback (line 84-90)', async () => {
|
|
590
|
+
const connectPromise = mexcWebSocket.connectWebSocket();
|
|
591
|
+
const errorCall = mockWs.on.mock.calls.find(([event]) => event === 'error');
|
|
592
|
+
expect(errorCall).toBeDefined();
|
|
593
|
+
const errorHandler = errorCall[1];
|
|
594
|
+
const testError = new Error('Connection error');
|
|
595
|
+
errorHandler(testError);
|
|
596
|
+
await expect(connectPromise).rejects.toThrow('Connection error');
|
|
597
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ WebSocket error:', { error: 'Connection error' });
|
|
598
|
+
});
|
|
599
|
+
it('should handle onError without reject callback after reconnect attempts (line 84-90)', async () => {
|
|
600
|
+
await connectWebSocket();
|
|
601
|
+
mexcWebSocket.reconnectAttempts = 1;
|
|
602
|
+
const errorCall = mockWs.on.mock.calls.find(([event]) => event === 'error');
|
|
603
|
+
const errorHandler = errorCall[1];
|
|
604
|
+
errorHandler(new Error('Post-connection error'));
|
|
605
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ WebSocket error:', { error: 'Post-connection error' });
|
|
606
|
+
});
|
|
607
|
+
it('should handle message processing error (line 117-119)', async () => {
|
|
608
|
+
await connectWebSocket();
|
|
609
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
610
|
+
const messageHandler = messageCall[1];
|
|
611
|
+
const mockBuffer = {
|
|
612
|
+
toString: jest.fn(() => {
|
|
613
|
+
throw new Error('Buffer conversion error');
|
|
614
|
+
})
|
|
615
|
+
};
|
|
616
|
+
messageHandler(mockBuffer);
|
|
617
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Message handling error:', { error: expect.any(Error) });
|
|
618
|
+
});
|
|
619
|
+
it('should handle protobuf decode error in handleProtobufUserDataMessage (line 145-147)', async () => {
|
|
620
|
+
await connectWebSocket();
|
|
621
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
622
|
+
const messageHandler = messageCall[1];
|
|
623
|
+
MockedMexcProtobufDecoder.decode.mockImplementationOnce(() => {
|
|
624
|
+
throw new Error('Protobuf decode error');
|
|
625
|
+
});
|
|
626
|
+
const mockBuffer = Buffer.from('spot@private.orders.v3.api.pb');
|
|
627
|
+
messageHandler(mockBuffer);
|
|
628
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error handling protobuf user data message:', {
|
|
629
|
+
error: expect.any(Error),
|
|
630
|
+
message: 'spot@private.orders.v3.api.pb'
|
|
631
|
+
});
|
|
632
|
+
});
|
|
633
|
+
it('should handle JSON parsing error in handleUserDataMessage (line 169-171)', async () => {
|
|
634
|
+
await connectWebSocket();
|
|
635
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
636
|
+
const messageHandler = messageCall[1];
|
|
637
|
+
const invalidJsonBuffer = Buffer.from('{"invalid": json}');
|
|
638
|
+
messageHandler(invalidJsonBuffer);
|
|
639
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error handling user data message:', {
|
|
640
|
+
error: expect.any(Error),
|
|
641
|
+
message: '{"invalid": json}'
|
|
642
|
+
});
|
|
643
|
+
});
|
|
644
|
+
it('should handle symbol conversion error in transformUserOrderUpdate (line 184-185)', async () => {
|
|
645
|
+
await connectWebSocket();
|
|
646
|
+
MockedToStandardFormat.mockImplementationOnce(() => {
|
|
647
|
+
throw new Error('Symbol conversion failed');
|
|
648
|
+
});
|
|
649
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
650
|
+
const messageHandler = messageCall[1];
|
|
651
|
+
const orderData = JSON.stringify({
|
|
652
|
+
e: 'executionReport',
|
|
653
|
+
s: 'INVALID_SYMBOL',
|
|
654
|
+
i: '12345'
|
|
655
|
+
});
|
|
656
|
+
const mockBuffer = Buffer.from(orderData);
|
|
657
|
+
messageHandler(mockBuffer);
|
|
658
|
+
expect(MockedToStandardFormat).toHaveBeenCalledWith('INVALID_SYMBOL');
|
|
659
|
+
});
|
|
660
|
+
it('should handle order processing error in onOrderUpdate (line 233-235)', async () => {
|
|
661
|
+
await connectWebSocket();
|
|
662
|
+
const subscription = await mexcWebSocket.subscribeOrders(jest.fn());
|
|
663
|
+
MockedMexcUtils.transformOrder.mockImplementationOnce(() => {
|
|
664
|
+
throw new Error('Order transformation failed');
|
|
665
|
+
});
|
|
666
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
667
|
+
const messageHandler = messageCall[1];
|
|
668
|
+
const decodedMessage = {
|
|
669
|
+
type: 'order',
|
|
670
|
+
raw: 'spot@test',
|
|
671
|
+
channel: 'spot@test',
|
|
672
|
+
symbol: 'BTCUSDT',
|
|
673
|
+
decoded: {
|
|
674
|
+
orderId: '123',
|
|
675
|
+
symbol: 'BTCUSDT',
|
|
676
|
+
price: 50000,
|
|
677
|
+
quantity: 1.0,
|
|
678
|
+
side: 'buy',
|
|
679
|
+
status: 'filled',
|
|
680
|
+
timestamp: Date.now(),
|
|
681
|
+
channel: 'spot@test'
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
685
|
+
const mockBuffer = Buffer.from('spot@test');
|
|
686
|
+
messageHandler(mockBuffer);
|
|
687
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error processing order update:', { error: expect.any(Error) });
|
|
688
|
+
});
|
|
689
|
+
it('should handle ticker processing error in onTickerUpdate (line 267-269)', async () => {
|
|
690
|
+
await connectWebSocket();
|
|
691
|
+
const callback = await setupTickerSubscription();
|
|
692
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
693
|
+
const messageHandler = messageCall[1];
|
|
694
|
+
const decodedMessage = {
|
|
695
|
+
type: 'ticker',
|
|
696
|
+
raw: 'spot@test',
|
|
697
|
+
channel: 'spot@test',
|
|
698
|
+
symbol: 'BTCUSDT',
|
|
699
|
+
decoded: {
|
|
700
|
+
askprice: 'invalid_number',
|
|
701
|
+
bidprice: '50000',
|
|
702
|
+
bidquantity: '1.0',
|
|
703
|
+
askquantity: '1.5'
|
|
704
|
+
}
|
|
705
|
+
};
|
|
706
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
707
|
+
const originalParseFloat = global.parseFloat;
|
|
708
|
+
global.parseFloat = jest.fn(() => {
|
|
709
|
+
throw new Error('Parse error');
|
|
710
|
+
});
|
|
711
|
+
const mockBuffer = Buffer.from('spot@test');
|
|
712
|
+
messageHandler(mockBuffer);
|
|
713
|
+
global.parseFloat = originalParseFloat;
|
|
714
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error processing ticker update:', { error: expect.any(Error) });
|
|
715
|
+
});
|
|
716
|
+
it('should handle trades processing error in onTradesUpdate (line 306-308)', async () => {
|
|
717
|
+
await connectWebSocket();
|
|
718
|
+
const callback = await setupTradesSubscription();
|
|
719
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
720
|
+
const messageHandler = messageCall[1];
|
|
721
|
+
const decodedMessage = {
|
|
722
|
+
type: 'trades',
|
|
723
|
+
raw: 'spot@test',
|
|
724
|
+
channel: 'spot@test',
|
|
725
|
+
symbol: 'BTCUSDT',
|
|
726
|
+
decoded: {
|
|
727
|
+
dealsList: [{
|
|
728
|
+
quantity: 'invalid',
|
|
729
|
+
price: '50000',
|
|
730
|
+
time: '1234567890',
|
|
731
|
+
tradetype: 1
|
|
732
|
+
}],
|
|
733
|
+
eventtype: 'trade'
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
737
|
+
const originalParseFloat = global.parseFloat;
|
|
738
|
+
global.parseFloat = jest.fn(() => {
|
|
739
|
+
throw new Error('Parse error');
|
|
740
|
+
});
|
|
741
|
+
const mockBuffer = Buffer.from('spot@test');
|
|
742
|
+
messageHandler(mockBuffer);
|
|
743
|
+
global.parseFloat = originalParseFloat;
|
|
744
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error processing trades update:', { error: expect.any(Error) });
|
|
745
|
+
});
|
|
746
|
+
it('should handle orderbook processing error in onOrderBookUpdate (line 344-346)', async () => {
|
|
747
|
+
await connectWebSocket();
|
|
748
|
+
const callback = await setupTickerSubscription();
|
|
749
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
750
|
+
const messageHandler = messageCall[1];
|
|
751
|
+
const decodedMessage = {
|
|
752
|
+
type: 'ticker',
|
|
753
|
+
raw: 'spot@test',
|
|
754
|
+
channel: 'spot@test',
|
|
755
|
+
symbol: 'BTCUSDT',
|
|
756
|
+
decoded: {
|
|
757
|
+
askprice: '51000',
|
|
758
|
+
bidprice: '50000',
|
|
759
|
+
bidquantity: '1.0',
|
|
760
|
+
askquantity: '1.5'
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
764
|
+
// Mock Date.now to throw for testing
|
|
765
|
+
const originalDateNow = Date.now;
|
|
766
|
+
Date.now = jest.fn(() => {
|
|
767
|
+
throw new Error('Date error');
|
|
768
|
+
});
|
|
769
|
+
const mockBuffer = Buffer.from('spot@test');
|
|
770
|
+
messageHandler(mockBuffer);
|
|
771
|
+
Date.now = originalDateNow;
|
|
772
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Error processing orderbook update:', { error: expect.any(Error) });
|
|
773
|
+
});
|
|
774
|
+
it('should handle subscription error in subscribeToUserData (line 455-457)', async () => {
|
|
775
|
+
await connectWebSocket();
|
|
776
|
+
mockWs.send = jest.fn().mockImplementation(() => {
|
|
777
|
+
throw new Error('Send failed');
|
|
778
|
+
});
|
|
779
|
+
await mexcWebSocket.subscribeToUserData(jest.fn());
|
|
780
|
+
expect(mockLogger.error).toHaveBeenCalledWith('Failed to subscribe to protobuf user data channels:', { error: expect.any(Error) });
|
|
781
|
+
});
|
|
782
|
+
it('should throw error when subscribing to disconnected WebSocket (line 467)', async () => {
|
|
783
|
+
expect(mexcWebSocket.isConnected()).toBe(false);
|
|
784
|
+
await expect(mexcWebSocket.subscribeTicker('BTC/USDT', jest.fn()))
|
|
785
|
+
.rejects.toThrow('WebSocket not connected');
|
|
786
|
+
});
|
|
787
|
+
it('should handle reconnection error in scheduleReconnect callback (line 518-519)', async () => {
|
|
788
|
+
await connectWebSocket();
|
|
789
|
+
const closeCall = mockWs.on.mock.calls.find(([event]) => event === 'close');
|
|
790
|
+
const closeHandler = closeCall[1];
|
|
791
|
+
closeHandler();
|
|
792
|
+
const originalConnect = mexcWebSocket.connectWebSocket;
|
|
793
|
+
mexcWebSocket.connectWebSocket = jest.fn().mockRejectedValue(new Error('Reconnection failed'));
|
|
794
|
+
jest.advanceTimersByTime(5000);
|
|
795
|
+
await jest.runOnlyPendingTimersAsync();
|
|
796
|
+
mexcWebSocket.connectWebSocket = originalConnect;
|
|
797
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ Reconnection failed:', { error: 'Reconnection failed' });
|
|
798
|
+
});
|
|
799
|
+
it('should handle reconnection error in reconnect method (line 531-533)', async () => {
|
|
800
|
+
await connectWebSocket();
|
|
801
|
+
const originalConnect = mexcWebSocket.connectWebSocket;
|
|
802
|
+
mexcWebSocket.connectWebSocket = jest.fn().mockRejectedValue(new Error('Connection failed'));
|
|
803
|
+
await mexcWebSocket.reconnect();
|
|
804
|
+
mexcWebSocket.connectWebSocket = originalConnect;
|
|
805
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ Reconnection failed:', { error: 'Connection failed' });
|
|
806
|
+
});
|
|
807
|
+
it('should handle unknown error type in reconnect method (line 531-533)', async () => {
|
|
808
|
+
await connectWebSocket();
|
|
809
|
+
const originalConnect = mexcWebSocket.connectWebSocket;
|
|
810
|
+
mexcWebSocket.connectWebSocket = jest.fn().mockRejectedValue('string error');
|
|
811
|
+
await mexcWebSocket.reconnect();
|
|
812
|
+
mexcWebSocket.connectWebSocket = originalConnect;
|
|
813
|
+
expect(mockLogger.error).toHaveBeenCalledWith('❌ Reconnection failed:', { error: 'Unknown error' });
|
|
814
|
+
});
|
|
815
|
+
it('should handle symbol conversion errors in various methods', async () => {
|
|
816
|
+
await connectWebSocket();
|
|
817
|
+
MockedToStandardFormat.mockImplementationOnce(() => {
|
|
818
|
+
throw new Error('Symbol conversion failed');
|
|
819
|
+
});
|
|
820
|
+
const callback = await setupTickerSubscription();
|
|
821
|
+
const decodedMessage = {
|
|
822
|
+
type: 'ticker',
|
|
823
|
+
raw: 'spot@test',
|
|
824
|
+
channel: 'spot@test',
|
|
825
|
+
symbol: 'INVALID_SYMBOL',
|
|
826
|
+
decoded: {
|
|
827
|
+
askprice: '51000',
|
|
828
|
+
bidprice: '50000',
|
|
829
|
+
bidquantity: '1.0',
|
|
830
|
+
askquantity: '1.5'
|
|
831
|
+
}
|
|
832
|
+
};
|
|
833
|
+
MockedMexcProtobufDecoder.decode.mockReturnValue(decodedMessage);
|
|
834
|
+
const messageCall = mockWs.on.mock.calls.find(([event]) => event === 'message');
|
|
835
|
+
const messageHandler = messageCall[1];
|
|
836
|
+
messageHandler(Buffer.from('spot@test'));
|
|
837
|
+
expect(callback).toHaveBeenCalledWith(expect.objectContaining({
|
|
838
|
+
symbol: 'INVALID_SYMBOL'
|
|
839
|
+
}));
|
|
840
|
+
});
|
|
841
|
+
});
|
|
842
|
+
});
|
|
843
|
+
//# sourceMappingURL=mexc-websocket.test.js.map
|