bitget.rb 0.4.0 → 0.5.0

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.
@@ -2,22 +2,57 @@ require_relative '../helper'
2
2
  require_relative '../../lib/Bitget/V2/Client'
3
3
 
4
4
  describe Bitget::V2::Client do
5
+ let(:api_key){ENV.fetch('BITGET_API_KEY', '<API_KEY>')}
6
+ let(:api_secret){ENV.fetch('BITGET_API_SECRET', '<API_SECRET>')}
7
+ let(:api_passphrase){ENV.fetch('BITGET_API_PASSPHRASE', '<API_PASSPHRASE>')}
8
+
5
9
  let(:client) do
6
10
  Bitget::V2::Client.new(
7
- api_key: ENV.fetch('BITGET_API_KEY', '<API_KEY>'),
8
- api_secret: ENV.fetch('BITGET_API_SECRET', '<API_SECRET>'),
9
- api_passphrase: ENV.fetch('BITGET_API_PASSPHRASE', '<API_PASSPHRASE>')
11
+ api_key: api_key,
12
+ api_secret: api_secret,
13
+ api_passphrase: api_passphrase
10
14
  )
11
15
  end
12
16
 
17
+ # Market
18
+
13
19
  describe "#spot_public_coins" do
14
20
  context "when a coin is NOT supplied" do
15
21
  it "retrieves a list of all coins" do
16
22
  VCR.use_cassette('v2/spot/public/coins-when_coin_is_not_supplied') do
17
23
  response = client.spot_public_coins
24
+ _(response['code']).must_equal('00000')
25
+ _(response['msg']).must_equal('success')
26
+ _(response).must_include('requestTime')
18
27
  _(response).must_include('data')
19
- _(response['data'].first).must_include('coinId')
20
- _(response['data'].first).must_include('coin')
28
+ _(response['data']).must_be_kind_of(Array)
29
+
30
+ coin = response['data'].first
31
+ _(coin).must_include('coinId')
32
+ _(coin).must_include('coin')
33
+ _(coin).must_include('transfer')
34
+ _(coin).must_include('areaCoin')
35
+ _(coin['areaCoin']).must_match(/^(yes|no)$/)
36
+ _(coin).must_include('chains')
37
+ _(coin['chains']).must_be_kind_of(Array)
38
+
39
+ chain = coin['chains'].first
40
+ _(chain).must_include('chain')
41
+ _(chain).must_include('needTag')
42
+ _(chain).must_include('withdrawable')
43
+ _(chain).must_include('rechargeable')
44
+ _(chain).must_include('withdrawFee')
45
+ _(chain).must_include('extraWithdrawFee')
46
+ _(chain).must_include('depositConfirm')
47
+ _(chain).must_include('withdrawConfirm')
48
+ _(chain).must_include('minDepositAmount')
49
+ _(chain).must_include('minWithdrawAmount')
50
+ _(chain).must_include('browserUrl')
51
+ _(chain).must_include('contractAddress')
52
+ _(chain).must_include('withdrawStep')
53
+ _(chain).must_include('withdrawMinScale')
54
+ _(chain).must_include('congestion')
55
+
21
56
  assert_operator response['data'].count, :>, 1500
22
57
  end
23
58
  end
@@ -27,61 +62,627 @@ describe Bitget::V2::Client do
27
62
  it "retrieves one coin" do
28
63
  VCR.use_cassette('v2/spot/public/coins-when_coin_is_supplied') do
29
64
  response = client.spot_public_coins(coin: 'BTC')
65
+ _(response['code']).must_equal('00000')
66
+ _(response['msg']).must_equal('success')
67
+ _(response).must_include('requestTime')
30
68
  _(response).must_include('data')
31
- _(response['data'].first).must_include('coinId')
32
- _(response['data'].first).must_include('coin')
69
+ _(response['data']).must_be_kind_of(Array)
33
70
  _(response['data'].count).must_equal(1)
71
+
72
+ coin = response['data'].first
73
+ _(coin).must_include('coinId')
74
+ _(coin).must_include('coin')
75
+ _(coin['coin']).must_equal('BTC')
76
+ _(coin).must_include('transfer')
77
+ _(coin).must_include('areaCoin')
78
+ _(coin['areaCoin']).must_match(/^(yes|no)$/)
79
+ _(coin).must_include('chains')
80
+ _(coin['chains']).must_be_kind_of(Array)
81
+
82
+ chain = coin['chains'].first
83
+ _(chain).must_include('chain')
84
+ _(chain).must_include('needTag')
85
+ _(chain).must_include('withdrawable')
86
+ _(chain).must_include('rechargeable')
87
+ _(chain).must_include('withdrawFee')
88
+ _(chain).must_include('extraWithdrawFee')
89
+ _(chain).must_include('depositConfirm')
90
+ _(chain).must_include('withdrawConfirm')
91
+ _(chain).must_include('minDepositAmount')
92
+ _(chain).must_include('minWithdrawAmount')
93
+ _(chain).must_include('browserUrl')
94
+ _(chain).must_include('contractAddress')
95
+ _(chain).must_include('withdrawStep')
96
+ _(chain).must_include('withdrawMinScale')
97
+ _(chain).must_include('congestion')
34
98
  end
35
99
  end
36
100
  end
101
+ end
37
102
 
38
- context "when an error occurs" do
39
- it "logs then raises an error" do
40
- VCR.use_cassette('v2/spot/public/coins-when_an_error_occurs') do
41
- assert_raises(Bitget::Error) do
42
- mocked_method = Minitest::Mock.new
43
- mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
44
- client.stub(:log_error, mocked_method) do
45
- client.spot_public_coins
46
- end
47
- mocked_method.verify
48
- end
103
+ describe "#spot_public_symbols" do
104
+ context "when a symbol is NOT supplied" do
105
+ it "retrieves a list of all symbols" do
106
+ VCR.use_cassette('v2/spot/public/symbols-when_symbol_is_not_supplied') do
107
+ response = client.spot_public_symbols
108
+ _(response['msg']).must_equal('success')
109
+ _(response).must_include('data')
110
+ _(response['data'].first).must_include('symbol')
111
+ _(response['data'].first).must_include('baseCoin')
112
+ _(response['data'].first).must_include('quoteCoin')
113
+ assert_operator response['data'].count, :>, 0
114
+ end
115
+ end
116
+ end
117
+
118
+ context "when a symbol IS supplied" do
119
+ it "retrieves one symbol" do
120
+ VCR.use_cassette('v2/spot/public/symbols-when_symbol_is_supplied') do
121
+ response = client.spot_public_symbols(symbol: 'BTCUSDT')
122
+ _(response['msg']).must_equal('success')
123
+ _(response).must_include('data')
124
+ _(response['data'].first).must_include('symbol')
125
+ _(response['data'].first).must_include('baseCoin')
126
+ _(response['data'].first).must_include('quoteCoin')
127
+ _(response['data'].count).must_equal(1)
128
+ _(response['data'].first['symbol']).must_equal('BTCUSDT')
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "#spot_market_vip_fee_rate" do
135
+ it "retrieves VIP fee rate information" do
136
+ VCR.use_cassette('v2/spot/market/vip-fee-rate') do
137
+ response = client.spot_market_vip_fee_rate
138
+ _(response['code']).must_equal('00000')
139
+ _(response['msg']).must_equal('success')
140
+ _(response).must_include('requestTime')
141
+ _(response).must_include('data')
142
+ _(response['data']).must_be_kind_of(Array)
143
+
144
+ vip_level = response['data'].first
145
+ _(vip_level).must_include('level')
146
+ _(vip_level).must_include('dealAmount')
147
+ _(vip_level).must_include('assetAmount')
148
+ _(vip_level).must_include('takerFeeRate')
149
+ _(vip_level).must_include('makerFeeRate')
150
+ _(vip_level).must_include('btcWithdrawAmount')
151
+ _(vip_level).must_include('usdtWithdrawAmount')
152
+ end
153
+ end
154
+ end
155
+
156
+ describe "#spot_market_tickers" do
157
+ context "when a symbol is NOT supplied" do
158
+ it "retrieves all tickers" do
159
+ VCR.use_cassette('v2/spot/market/tickers-when_symbol_is_not_supplied') do
160
+ response = client.spot_market_tickers
161
+ _(response['code']).must_equal('00000')
162
+ _(response['msg']).must_equal('success')
163
+ _(response).must_include('requestTime')
164
+ _(response).must_include('data')
165
+ _(response['data']).must_be_kind_of(Array)
166
+
167
+ ticker = response['data'].first
168
+ _(ticker).must_include('symbol')
169
+ _(ticker).must_include('high24h')
170
+ _(ticker).must_include('open')
171
+ _(ticker).must_include('low24h')
172
+ _(ticker).must_include('lastPr')
173
+ _(ticker).must_include('quoteVolume')
174
+ _(ticker).must_include('baseVolume')
175
+ _(ticker).must_include('usdtVolume')
176
+ _(ticker).must_include('bidPr')
177
+ _(ticker).must_include('askPr')
178
+ _(ticker).must_include('bidSz')
179
+ _(ticker).must_include('askSz')
180
+ _(ticker).must_include('openUtc')
181
+ _(ticker).must_include('ts')
182
+ _(ticker).must_include('changeUtc24h')
183
+ _(ticker).must_include('change24h')
184
+ end
185
+ end
186
+ end
187
+
188
+ context "when a symbol is supplied" do
189
+ it "retrieves ticker for the specified symbol" do
190
+ VCR.use_cassette('v2/spot/market/tickers-when_symbol_is_supplied') do
191
+ response = client.spot_market_tickers(symbol: 'BTCUSDT')
192
+ _(response['code']).must_equal('00000')
193
+ _(response['msg']).must_equal('success')
194
+ _(response).must_include('requestTime')
195
+ _(response).must_include('data')
196
+ _(response['data']).must_be_kind_of(Array)
197
+ _(response['data'].count).must_equal(1)
198
+
199
+ ticker = response['data'].first
200
+ _(ticker['symbol']).must_equal('BTCUSDT')
201
+ _(ticker).must_include('high24h')
202
+ _(ticker).must_include('open')
203
+ _(ticker).must_include('low24h')
204
+ _(ticker).must_include('lastPr')
205
+ _(ticker).must_include('quoteVolume')
206
+ _(ticker).must_include('baseVolume')
207
+ _(ticker).must_include('usdtVolume')
208
+ _(ticker).must_include('bidPr')
209
+ _(ticker).must_include('askPr')
210
+ _(ticker).must_include('bidSz')
211
+ _(ticker).must_include('askSz')
212
+ _(ticker).must_include('openUtc')
213
+ _(ticker).must_include('ts')
214
+ _(ticker).must_include('changeUtc24h')
215
+ _(ticker).must_include('change24h')
49
216
  end
50
217
  end
51
218
  end
52
219
  end
53
220
 
221
+ describe "#spot_market_merge_depth" do
222
+ it "retrieves merge depth" do
223
+ VCR.use_cassette('v2/spot/market/merge-depth') do
224
+ response = client.spot_market_merge_depth(symbol: 'BTCUSDT')
225
+ _(response['msg']).must_equal('success')
226
+ _(response).must_include('data')
227
+ _(response['data']).must_include('asks')
228
+ _(response['data']).must_include('bids')
229
+ _(response['data']).must_include('ts')
230
+ end
231
+ end
232
+ end
233
+
234
+ describe "#spot_market_orderbook" do
235
+ it "retrieves orderbook" do
236
+ VCR.use_cassette('v2/spot/market/orderbook') do
237
+ response = client.spot_market_orderbook(symbol: 'BTCUSDT')
238
+ _(response['msg']).must_equal('success')
239
+ _(response).must_include('data')
240
+ _(response['data']).must_include('asks')
241
+ _(response['data']).must_include('bids')
242
+ _(response['data']).must_include('ts')
243
+ end
244
+ end
245
+ end
246
+
247
+ describe "#spot_market_candles" do
248
+ it "retrieves candles" do
249
+ VCR.use_cassette('v2/spot/market/candles') do
250
+ response = client.spot_market_candles(symbol: 'BTCUSDT', granularity: '1min')
251
+ _(response['msg']).must_equal('success')
252
+ _(response).must_include('data')
253
+ _(response['data'].first).must_be_kind_of(Array)
254
+ _(response['data'].first.length).must_equal(8) # [timestamp, open, high, low, close, base_volume, usdt_volume, quote_volume]
255
+ end
256
+ end
257
+ end
258
+
259
+ describe "#spot_market_history_candles" do
260
+ it "retrieves history candles" do
261
+ VCR.use_cassette('v2/spot/market/history-candles') do
262
+ response = client.spot_market_history_candles(symbol: 'BTCUSDT', granularity: '1min', end_time: 1690196141868)
263
+ _(response['msg']).must_equal('success')
264
+ _(response).must_include('data')
265
+ _(response['data'].first).must_be_kind_of(Array)
266
+ _(response['data'].first.length).must_equal(8) # [ts, open, high, low, close, base volume, USDT volume, quote volume]
267
+ end
268
+ end
269
+ end
270
+
271
+ describe "#spot_market_fills" do
272
+ it "retrieves recent trades" do
273
+ VCR.use_cassette('v2/spot/market/fills') do
274
+ response = client.spot_market_fills(symbol: 'BTCUSDT')
275
+ _(response['msg']).must_equal('success')
276
+ _(response).must_include('data')
277
+ _(response['data'].first).must_include('price')
278
+ _(response['data'].first).must_include('size')
279
+ _(response['data'].first).must_include('side')
280
+ _(response['data'].first).must_include('ts')
281
+ end
282
+ end
283
+ end
284
+
285
+ describe "#spot_market_fills_history" do
286
+ it "retrieves market trades history" do
287
+ VCR.use_cassette('v2/spot/market/fills-history') do
288
+ response = client.spot_market_fills_history(symbol: 'BTCUSDT')
289
+ _(response['msg']).must_equal('success')
290
+ _(response).must_include('data')
291
+ _(response['data'].first).must_include('price')
292
+ _(response['data'].first).must_include('size')
293
+ _(response['data'].first).must_include('side')
294
+ _(response['data'].first).must_include('ts')
295
+ end
296
+ end
297
+ end
298
+
299
+ # Trade
300
+
301
+ describe "#spot_trade_place_order" do
302
+ it "places an order" do
303
+ VCR.use_cassette('v2/spot/trade/place-order') do
304
+ response = client.spot_trade_place_order(
305
+ symbol: 'BTCUSDT',
306
+ side: 'buy',
307
+ order_type: 'limit',
308
+ force: 'gtc',
309
+ price: '30000',
310
+ size: '0.001'
311
+ )
312
+ _(response['msg']).must_equal('success')
313
+ _(response).must_include('data')
314
+ _(response['data']).must_include('orderId')
315
+ _(response['data']).must_include('clientOid')
316
+ end
317
+ end
318
+ end
319
+
320
+ describe "#spot_trade_cancel_replace_order" do
321
+ it "cancels and replaces an order" do
322
+ VCR.use_cassette('v2/spot/trade/cancel-replace-order') do
323
+ response = client.spot_trade_cancel_replace_order(
324
+ symbol: 'BTCUSDT',
325
+ price: '31000',
326
+ size: '0.001',
327
+ order_id: '123456'
328
+ )
329
+ _(response).must_include('data')
330
+ _(response['data']).must_include('orderId')
331
+ _(response['data']).must_include('clientOid')
332
+ end
333
+ end
334
+ end
335
+
336
+ describe "#spot_trade_batch_cancel_replace_order" do
337
+ it "batch cancels and replaces orders" do
338
+ VCR.use_cassette('v2/spot/trade/batch-cancel-replace-order') do
339
+ order_list = [
340
+ {
341
+ symbol: 'BTCUSDT',
342
+ price: '31000',
343
+ size: '0.001',
344
+ orderId: '123456',
345
+ },
346
+ {
347
+ symbol: 'ETHUSDT',
348
+ price: '2000',
349
+ size: '0.01',
350
+ orderId: '123457',
351
+ }
352
+ ]
353
+ response = client.spot_trade_batch_cancel_replace_order(order_list: order_list)
354
+ _(response['msg']).must_equal('success')
355
+ _(response).must_include('data')
356
+ _(response['data']).must_be_kind_of(Array)
357
+ _(response['data'].first).must_include('orderId')
358
+ _(response['data'].first).must_include('clientOid')
359
+ _(response['data'].first).must_include('success')
360
+ _(response['data'].first).must_include('msg')
361
+ end
362
+ end
363
+ end
364
+
365
+ describe "#spot_trade_cancel_order" do
366
+ it "cancels an order" do
367
+ VCR.use_cassette('v2/spot/trade/cancel-order') do
368
+ response = client.spot_trade_cancel_order(symbol: 'BTCUSDT')
369
+ _(response['message']).must_equal('success')
370
+ _(response).must_include('data')
371
+ _(response['data']).must_include('orderId')
372
+ _(response['data']).must_include('clientOid')
373
+ end
374
+ end
375
+ end
376
+
377
+ describe "#spot_trade_batch_orders" do
378
+ it "places batch orders" do
379
+ VCR.use_cassette('v2/spot/trade/batch-orders') do
380
+ order_list = [
381
+ {
382
+ symbol: 'BTCUSDT',
383
+ side: 'buy',
384
+ orderType: 'limit',
385
+ force: 'gtc',
386
+ price: '30000',
387
+ size: '0.001'
388
+ },
389
+ {
390
+ symbol: 'ETHUSDT',
391
+ side: 'buy',
392
+ orderType: 'limit',
393
+ force: 'gtc',
394
+ price: '2000',
395
+ size: '0.01'
396
+ }
397
+ ]
398
+ response = client.spot_trade_batch_orders(batch_mode: 'multiple', order_list: order_list)
399
+ _(response['msg']).must_equal('success')
400
+ _(response).must_include('data')
401
+ _(response['data']).must_include('successList')
402
+ _(response['data']).must_include('failureList')
403
+ _(response['data']['successList']).must_be_kind_of(Array)
404
+ _(response['data']['successList'].first).must_include('orderId')
405
+ _(response['data']['successList'].first).must_include('clientOid')
406
+ _(response['data']['failureList']).must_be_kind_of(Array)
407
+ end
408
+ end
409
+ end
410
+
411
+ describe "#spot_trade_batch_cancel_order" do
412
+ it "cancels batch orders" do
413
+ VCR.use_cassette('v2/spot/trade/batch-cancel-order') do
414
+ response = client.spot_trade_batch_cancel_order(symbol: 'BTCUSDT', order_list: ['123456', '123457'])
415
+ _(response['message']).must_equal('success')
416
+ _(response).must_include('data')
417
+ _(response['data']).must_be_kind_of(Hash)
418
+ _(response['data']).must_include('successList')
419
+ _(response['data']['successList'].first).must_include('orderId')
420
+ _(response['data']['successList'].first).must_include('clientOid')
421
+ _(response['data']).must_include('failureList')
422
+ _(response['data']['failureList'].first).must_include('orderId')
423
+ _(response['data']['failureList'].first).must_include('clientOid')
424
+ _(response['data']['failureList'].first).must_include('errorMsg')
425
+ end
426
+ end
427
+ end
428
+
429
+ describe "#spot_trade_cancel_symbol_order" do
430
+ it "cancels all orders for a symbol" do
431
+ VCR.use_cassette('v2/spot/trade/cancel-symbol-order') do
432
+ response = client.spot_trade_cancel_symbol_order(symbol: 'BTCUSDT')
433
+ _(response['msg']).must_equal('success')
434
+ _(response).must_include('data')
435
+ _(response['data']).must_be_kind_of(Hash)
436
+ _(response['data']).must_include('symbol')
437
+ end
438
+ end
439
+ end
440
+
441
+ describe "#spot_trade_order_info" do
442
+ it "retrieves order information" do
443
+ VCR.use_cassette('v2/spot/trade/orderInfo') do
444
+ response = client.spot_trade_order_info(order_id: '123456')
445
+ _(response['msg']).must_equal('success')
446
+ _(response).must_include('data')
447
+ _(response['data']).must_be_kind_of(Array)
448
+ _(response['data'].first).must_include('userId')
449
+ _(response['data'].first).must_include('symbol')
450
+ _(response['data'].first).must_include('orderId')
451
+ _(response['data'].first).must_include('clientOid')
452
+ _(response['data'].first).must_include('price')
453
+ _(response['data'].first).must_include('size')
454
+ _(response['data'].first).must_include('orderType')
455
+ _(response['data'].first).must_include('side')
456
+ _(response['data'].first).must_include('status')
457
+ _(response['data'].first).must_include('priceAvg')
458
+ _(response['data'].first).must_include('baseVolume')
459
+ _(response['data'].first).must_include('quoteVolume')
460
+ _(response['data'].first).must_include('enterPointSource')
461
+ _(response['data'].first).must_include('feeDetail')
462
+ _(response['data'].first).must_include('orderSource')
463
+ _(response['data'].first).must_include('cancelReason')
464
+ _(response['data'].first).must_include('cTime')
465
+ _(response['data'].first).must_include('orderType')
466
+ _(response['data'].first).must_include('uTime')
467
+ end
468
+ end
469
+ end
470
+
471
+ describe "#spot_trade_unfilled_orders" do
472
+ it "gets unfilled orders" do
473
+ VCR.use_cassette('v2/spot/trade/unfilled-orders') do
474
+ response = client.spot_trade_unfilled_orders(symbol: 'BTCUSDT')
475
+ _(response['message']).must_equal('success')
476
+ _(response).must_include('data')
477
+ _(response['data']).must_be_kind_of(Array)
478
+ _(response['data'].first).must_include('orderId')
479
+ _(response['data'].first).must_include('clientOid')
480
+ _(response['data'].first).must_include('symbol')
481
+ _(response['data'].first).must_include('status')
482
+ end
483
+ end
484
+ end
485
+
486
+ describe "#spot_trade_history_orders" do
487
+ it "gets history orders" do
488
+ VCR.use_cassette('v2/spot/trade/history-orders') do
489
+ response = client.spot_trade_history_orders(symbol: 'BTCUSDT')
490
+ _(response['message']).must_equal('success')
491
+ _(response).must_include('data')
492
+ _(response['data']).must_be_kind_of(Array)
493
+ _(response['data'].first).must_include('userId')
494
+ _(response['data'].first).must_include('symbol')
495
+ _(response['data'].first).must_include('orderId')
496
+ _(response['data'].first).must_include('clientOid')
497
+ _(response['data'].first).must_include('price')
498
+ _(response['data'].first).must_include('size')
499
+ _(response['data'].first).must_include('orderType')
500
+ _(response['data'].first).must_include('side')
501
+ _(response['data'].first).must_include('status')
502
+ _(response['data'].first).must_include('priceAvg')
503
+ _(response['data'].first).must_include('baseVolume')
504
+ _(response['data'].first).must_include('quoteVolume')
505
+ _(response['data'].first).must_include('enterPointSource')
506
+ _(response['data'].first).must_include('feeDetail')
507
+ _(response['data'].first).must_include('orderSource')
508
+ _(response['data'].first).must_include('cTime')
509
+ _(response['data'].first).must_include('uTime')
510
+ _(response['data'].first).must_include('tpslType')
511
+ _(response['data'].first).must_include('cancelReason')
512
+ _(response['data'].first).must_include('triggerPrice')
513
+ end
514
+ end
515
+ end
516
+
517
+ describe "#spot_trade_fills" do
518
+ it "gets trade fills" do
519
+ VCR.use_cassette('v2/spot/trade/fills') do
520
+ response = client.spot_trade_fills(symbol: 'BTCUSDT')
521
+ _(response['msg']).must_equal('success')
522
+ _(response).must_include('data')
523
+ _(response['data']).must_be_kind_of(Array)
524
+ _(response['data'].first).must_include('userId')
525
+ _(response['data'].first).must_include('symbol')
526
+ _(response['data'].first).must_include('orderId')
527
+ _(response['data'].first).must_include('tradeId')
528
+ _(response['data'].first).must_include('orderType')
529
+ _(response['data'].first).must_include('side')
530
+ _(response['data'].first).must_include('priceAvg')
531
+ _(response['data'].first).must_include('size')
532
+ _(response['data'].first).must_include('amount')
533
+ _(response['data'].first).must_include('feeDetail')
534
+ _(response['data'].first['feeDetail']).must_include('deduction')
535
+ _(response['data'].first['feeDetail']).must_include('feeCoin')
536
+ _(response['data'].first['feeDetail']).must_include('totalDeductionFee')
537
+ _(response['data'].first['feeDetail']).must_include('totalFee')
538
+ _(response['data'].first).must_include('tradeScope')
539
+ _(response['data'].first).must_include('cTime')
540
+ _(response['data'].first).must_include('uTime')
541
+ end
542
+ end
543
+ end
544
+
545
+ # Trigger
546
+
547
+ describe "#spot_trade_place_plan_order" do
548
+ it "places a plan order" do
549
+ VCR.use_cassette('v2/spot/trade/place-plan-order') do
550
+ response = client.spot_trade_place_plan_order(
551
+ symbol: 'BTCUSDT',
552
+ side: 'buy',
553
+ order_type: 'limit',
554
+ size: '0.001',
555
+ trigger_type: 'mark_price',
556
+ trigger_price: '30000',
557
+ execute_price: '30000'
558
+ )
559
+ _(response['msg']).must_equal('success')
560
+ _(response).must_include('data')
561
+ _(response['data']).must_include('orderId')
562
+ _(response['data']).must_include('clientOid')
563
+ end
564
+ end
565
+ end
566
+
567
+ describe "#spot_trade_modify_plan_order" do
568
+ it "modifies a plan order" do
569
+ VCR.use_cassette('v2/spot/trade/modify-plan-order') do
570
+ response = client.spot_trade_modify_plan_order(order_id: '123456')
571
+ _(response['msg']).must_equal('success')
572
+ _(response).must_include('data')
573
+ _(response['data']).must_include('orderId')
574
+ _(response['data']).must_include('clientOid')
575
+ end
576
+ end
577
+ end
578
+
579
+ describe "#spot_trade_cancel_plan_order" do
580
+ it "cancels a plan order" do
581
+ VCR.use_cassette('v2/spot/trade/cancel-plan-order') do
582
+ response = client.spot_trade_cancel_plan_order(order_id: '123456')
583
+ _(response['msg']).must_equal('success')
584
+ _(response).must_include('data')
585
+ _(response).must_be_kind_of(Hash)
586
+ _(response['data']).must_include('result')
587
+ _(response['data']['result']).must_equal('success')
588
+ end
589
+ end
590
+ end
591
+
592
+ describe "#spot_trade_current_plan_order" do
593
+ it "gets current plan orders" do
594
+ VCR.use_cassette('v2/spot/trade/current-plan-order') do
595
+ response = client.spot_trade_current_plan_order(symbol: 'BTCUSDT')
596
+ _(response['msg']).must_equal('success')
597
+ _(response).must_include('data')
598
+ _(response['data']).must_be_kind_of(Hash)
599
+ _(response['data']).must_include('nextFlag')
600
+ _(response['data']).must_include('idLessThan')
601
+ _(response['data']).must_include('orderList')
602
+ end
603
+ end
604
+ end
605
+
606
+ describe "#spot_trade_plan_sub_order" do
607
+ it "gets plan sub order" do
608
+ VCR.use_cassette('v2/spot/trade/plan-sub-order') do
609
+ response = client.spot_trade_plan_sub_order(order_id: '123456')
610
+ _(response['msg']).must_equal('success')
611
+ _(response).must_include('data')
612
+ _(response['data']).must_be_kind_of(Array)
613
+ _(response['data'].first).must_include('orderId')
614
+ _(response['data'].first).must_include('price')
615
+ _(response['data'].first).must_include('type')
616
+ _(response['data'].first).must_include('status')
617
+ end
618
+ end
619
+ end
620
+
621
+ describe "#spot_trade_history_plan_order" do
622
+ it "gets history plan orders" do
623
+ VCR.use_cassette('v2/spot/trade/history-plan-order') do
624
+ response = client.spot_trade_history_plan_order(
625
+ symbol: 'BTCUSDT',
626
+ start_time: 1747754739537,
627
+ end_time: 1747755739537
628
+ )
629
+ _(response['msg']).must_equal('success')
630
+ _(response).must_include('data')
631
+ _(response['data']).must_be_kind_of(Hash)
632
+ _(response['data']).must_include('nextFlag')
633
+ _(response['data']).must_include('idLessThan')
634
+ _(response['data']).must_include('orderList')
635
+ _(response['data']['orderList'].first).must_include('orderId')
636
+ _(response['data']['orderList'].first).must_include('clientOid')
637
+ _(response['data']['orderList'].first).must_include('symbol')
638
+ _(response['data']['orderList'].first).must_include('size')
639
+ _(response['data']['orderList'].first).must_include('executePrice')
640
+ _(response['data']['orderList'].first).must_include('triggerPrice')
641
+ _(response['data']['orderList'].first).must_include('status')
642
+ _(response['data']['orderList'].first).must_include('orderType')
643
+ _(response['data']['orderList'].first).must_include('side')
644
+ _(response['data']['orderList'].first).must_include('planType')
645
+ _(response['data']['orderList'].first).must_include('triggerType')
646
+ _(response['data']['orderList'].first).must_include('enterPointSource')
647
+ _(response['data']['orderList'].first).must_include('uTime')
648
+ _(response['data']['orderList'].first).must_include('cTime')
649
+ end
650
+ end
651
+ end
652
+
653
+ describe "#spot_trade_batch_cancel_plan_order" do
654
+ it "cancels batch plan orders" do
655
+ VCR.use_cassette('v2/spot/trade/batch-cancel-plan-order') do
656
+ response = client.spot_trade_batch_cancel_plan_order(symbol_list: ['BTCUSDT', 'ETHUSDT'])
657
+ _(response['msg']).must_equal('success')
658
+ _(response).must_include('data')
659
+ _(response['data']).must_be_kind_of(Hash)
660
+ _(response['data']).must_include('successList')
661
+ _(response['data']).must_include('failureList')
662
+ end
663
+ end
664
+ end
665
+
666
+ # Account
667
+
54
668
  describe "#spot_account_info" do
55
669
  it "retrieves account information" do
56
670
  VCR.use_cassette('v2/spot/account/info') do
57
671
  response = client.spot_account_info
672
+ _(response['msg']).must_equal('success')
58
673
  _(response).must_include('data')
59
674
  _(response['data']).must_include('userId')
60
675
  _(response['data']).must_include('channelCode')
61
676
  _(response['data']).must_include('authorities')
62
677
  end
63
678
  end
64
-
65
- context "when an error occurs" do
66
- it "logs then raises an error" do
67
- VCR.use_cassette('v2/spot/account/info-when_an_error_occurs') do
68
- assert_raises(Bitget::Error) do
69
- mocked_method = Minitest::Mock.new
70
- mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
71
- client.stub(:log_error, mocked_method) do
72
- client.spot_account_info
73
- end
74
- mocked_method.verify
75
- end
76
- end
77
- end
78
- end
79
679
  end
80
680
 
81
681
  describe "#spot_account_assets" do
82
682
  it "retrieves account assets" do
83
683
  VCR.use_cassette('v2/spot/account/assets') do
84
684
  response = client.spot_account_assets
685
+ _(response['msg']).must_equal('success')
85
686
  _(response).must_include('data')
86
687
  _(response['data'].first).must_include('coin')
87
688
  _(response['data'].first).must_include('available')
@@ -90,19 +691,458 @@ describe Bitget::V2::Client do
90
691
  _(response['data'].first).must_include('uTime')
91
692
  end
92
693
  end
694
+ end
695
+
696
+ describe "#spot_account_subaccount_assets" do
697
+ it "gets subaccount assets" do
698
+ VCR.use_cassette('v2/spot/account/subaccount-assets') do
699
+ response = client.spot_account_subaccount_assets
700
+ _(response['message']).must_equal('success')
701
+ _(response).must_include('data')
702
+ _(response['data']).must_be_kind_of(Array)
703
+ _(response['data'].first).must_include('id')
704
+ _(response['data'].first).must_include('userId')
705
+ _(response['data'].first).must_include('assetsList')
706
+ _(response['data'].first['assetsList']).must_be_kind_of(Array)
707
+ _(response['data'].first['assetsList'].first).must_include('coin')
708
+ _(response['data'].first['assetsList'].first).must_include('available')
709
+ _(response['data'].first['assetsList'].first).must_include('limitAvailable')
710
+ _(response['data'].first['assetsList'].first).must_include('frozen')
711
+ _(response['data'].first['assetsList'].first).must_include('locked')
712
+ _(response['data'].first['assetsList'].first).must_include('uTime')
713
+ end
714
+ end
715
+ end
716
+
717
+ describe "#spot_account_bills" do
718
+ it "gets account bills" do
719
+ VCR.use_cassette('v2/spot/account/bills') do
720
+ response = client.spot_account_bills
721
+ _(response['msg']).must_equal('success')
722
+ _(response).must_include('data')
723
+ _(response['data']).must_be_kind_of(Array)
724
+ _(response['data'].first).must_include('billId')
725
+ _(response['data'].first).must_include('coin')
726
+ _(response['data'].first).must_include('bizOrderId')
727
+ _(response['data'].first).must_include('coin')
728
+ _(response['data'].first).must_include('groupType')
729
+ _(response['data'].first).must_include('businessType')
730
+ _(response['data'].first).must_include('size')
731
+ _(response['data'].first).must_include('balance')
732
+ _(response['data'].first).must_include('fees')
733
+ _(response['data'].first).must_include('cTime')
734
+ end
735
+ end
736
+ end
737
+
738
+ describe "#spot_account_sub_main_trans_record" do
739
+ it "gets main-sub transfer records" do
740
+ VCR.use_cassette('v2/spot/account/sub-main-trans-record') do
741
+ response = client.spot_account_sub_main_trans_record
742
+ _(response['msg']).must_equal('success')
743
+ _(response).must_include('data')
744
+ _(response['data']).must_be_kind_of(Array)
745
+ _(response['data'].first).must_include('coin')
746
+ _(response['data'].first).must_include('status')
747
+ _(response['data'].first).must_include('toType')
748
+ _(response['data'].first).must_include('fromType')
749
+ _(response['data'].first).must_include('size')
750
+ _(response['data'].first).must_include('ts')
751
+ _(response['data'].first).must_include('clientOid')
752
+ _(response['data'].first).must_include('transferId')
753
+ _(response['data'].first).must_include('fromUserId')
754
+ _(response['data'].first).must_include('toUserId')
755
+ end
756
+ end
757
+ end
758
+
759
+ describe "#spot_account_transfer_records" do
760
+ it "gets transfer records" do
761
+ VCR.use_cassette('v2/spot/account/transferRecords') do
762
+ response = client.spot_account_transfer_records
763
+ _(response['msg']).must_equal('success')
764
+ _(response).must_include('data')
765
+ _(response['data']).must_be_kind_of(Array)
766
+ _(response['data'].first).must_include('coin')
767
+ _(response['data'].first).must_include('status')
768
+ _(response['data'].first).must_include('toType')
769
+ _(response['data'].first).must_include('fromType')
770
+ _(response['data'].first).must_include('fromSymbol')
771
+ _(response['data'].first).must_include('size')
772
+ _(response['data'].first).must_include('ts')
773
+ _(response['data'].first).must_include('clientOid')
774
+ _(response['data'].first).must_include('transferId')
775
+ end
776
+ end
777
+ end
778
+
779
+ describe "#spot_account_switch_deduct" do
780
+ it "switches BGB deduct" do
781
+ VCR.use_cassette('v2/spot/account/switch-deduct') do
782
+ response = client.spot_account_switch_deduct(deduct: 'on')
783
+ _(response['msg']).must_equal('success')
784
+ _(response).must_include('data')
785
+ _(response['data']).must_equal(true)
786
+ end
787
+ end
788
+ end
789
+
790
+ describe "#spot_account_deduct_info" do
791
+ it "gets BGB deduct info" do
792
+ VCR.use_cassette('v2/spot/account/deduct-info') do
793
+ response = client.spot_account_deduct_info
794
+ _(response['msg']).must_equal('success')
795
+ _(response).must_include('data')
796
+ _(response['data']).must_include('deduct')
797
+ end
798
+ end
799
+ end
800
+
801
+ describe "#spot_wallet_modify_deposit_account" do
802
+ it "modifies deposit account" do
803
+ VCR.use_cassette('v2/spot/wallet/modify-deposit-account') do
804
+ response = client.spot_wallet_modify_deposit_account(account_type: 'spot', coin: 'TRX')
805
+ _(response['msg']).must_equal('success')
806
+ _(response).must_include('data')
807
+ _(response['data']).must_include('success')
808
+ end
809
+ end
810
+ end
811
+
812
+ describe "#spot_wallet_transfer" do
813
+ it "transfers funds between accounts" do
814
+ VCR.use_cassette('v2/spot/wallet/transfer') do
815
+ response = client.spot_wallet_transfer(
816
+ from_type: 'spot',
817
+ to_type: 'isolated_margin',
818
+ amount: '100',
819
+ coin: 'USDT',
820
+ symbol: 'TRXUSDT'
821
+ )
822
+ _(response['msg']).must_equal('success')
823
+ _(response).must_include('data')
824
+ _(response['data']).must_include('transferId')
825
+ _(response['data']).must_include('clientOid')
826
+ end
827
+ end
828
+ end
829
+
830
+ describe "#spot_wallet_transfer_coin_info" do
831
+ it "gets transferable coin list" do
832
+ VCR.use_cassette('v2/spot/wallet/transfer-coin-info') do
833
+ response = client.spot_wallet_transfer_coin_info(from_type: 'spot', to_type: 'isolated_margin')
834
+ _(response['msg']).must_equal('success')
835
+ _(response).must_include('data')
836
+ _(response['data']).must_be_kind_of(Array)
837
+ _(response['data']).must_include('AGLD')
838
+ end
839
+ end
840
+ end
841
+
842
+ describe "#spot_wallet_subaccount_transfer" do
843
+ it "transfers funds between subaccounts" do
844
+ VCR.use_cassette('v2/spot/wallet/subaccount-transfer') do
845
+ response = client.spot_wallet_subaccount_transfer(
846
+ from_type: 'spot',
847
+ to_type: 'isolated_margin',
848
+ amount: '100',
849
+ coin: 'USDT'
850
+ )
851
+ _(response['msg']).must_equal('success')
852
+ _(response).must_include('data')
853
+ _(response['data']).must_be_kind_of(Hash)
854
+ _(response['data']).must_include('transferId')
855
+ _(response['data']).must_include('clientOid')
856
+ end
857
+ end
858
+ end
859
+
860
+ describe "#spot_wallet_withdrawal" do
861
+ it "withdraws funds" do
862
+ VCR.use_cassette('v2/spot/wallet/withdrawal') do
863
+ response = client.spot_wallet_withdrawal(
864
+ coin: 'USDT',
865
+ transfer_type: 'on_chain',
866
+ address: '0x1234567890abcdef',
867
+ chain: 'TRC20',
868
+ size: 100
869
+ )
870
+ _(response['msg']).must_equal('success')
871
+ _(response).must_include('data')
872
+ _(response).must_be_kind_of(Hash)
873
+ _(response['msg']).must_equal('success')
874
+ _(response['data']).must_include('orderId')
875
+ _(response['data']).must_include('clientOid')
876
+ end
877
+ end
878
+ end
879
+
880
+ describe "#spot_wallet_cancel_withdrawal" do
881
+ it "cancels a withdrawal" do
882
+ VCR.use_cassette('v2/spot/wallet/cancel-withdrawal') do
883
+ response = client.spot_wallet_cancel_withdrawal(order_id: '123456')
884
+ _(response).must_include('data')
885
+ _(response['data']).must_equal('success')
886
+ end
887
+ end
888
+ end
889
+
890
+ describe "#spot_wallet_deposit_address" do
891
+ it "gets deposit address" do
892
+ VCR.use_cassette('v2/spot/wallet/deposit-address') do
893
+ response = client.spot_wallet_deposit_address(coin: 'USDT', chain: 'TRC20')
894
+ _(response['msg']).must_equal('success')
895
+ _(response).must_include('data')
896
+ _(response['data']).must_include('address')
897
+ _(response['data']).must_include('chain')
898
+ _(response['data']).must_include('coin')
899
+ end
900
+ end
901
+ end
902
+
903
+ describe "#spot_wallet_subaccount_deposit_address" do
904
+ it "gets subaccount deposit address" do
905
+ VCR.use_cassette('v2/spot/wallet/subaccount-deposit-address') do
906
+ response = client.spot_wallet_subaccount_deposit_address(
907
+ subaccount_user_id: '123456',
908
+ coin: 'USDT',
909
+ chain: 'TRC20'
910
+ )
911
+ _(response['msg']).must_equal('success')
912
+ _(response).must_include('data')
913
+ _(response['data']).must_include('address')
914
+ _(response['data']).must_include('chain')
915
+ _(response['data']).must_include('coin')
916
+ _(response['data']).must_include('tag')
917
+ _(response['data']).must_include('url')
918
+ end
919
+ end
920
+ end
921
+
922
+ describe "#spot_wallet_subaccount_deposit_records" do
923
+ it "gets subaccount deposit records" do
924
+ VCR.use_cassette('v2/spot/wallet/subaccount-deposit-records') do
925
+ response = client.spot_wallet_subaccount_deposit_records(subaccount_user_id: '123456')
926
+ _(response['msg']).must_equal('success')
927
+ _(response).must_include('data')
928
+ _(response['data']).must_be_kind_of(Array)
929
+ _(response['data'].first).must_include('orderId')
930
+ _(response['data'].first).must_include('tradeId')
931
+ _(response['data'].first).must_include('coin')
932
+ _(response['data'].first).must_include('size')
933
+ _(response['data'].first).must_include('status')
934
+ _(response['data'].first).must_include('toAddress')
935
+ _(response['data'].first).must_include('dest')
936
+ _(response['data'].first).must_include('chain')
937
+ _(response['data'].first).must_include('fromAddress')
938
+ _(response['data'].first).must_include('cTime')
939
+ _(response['data'].first).must_include('uTime')
940
+ end
941
+ end
942
+ end
943
+
944
+ describe "#spot_wallet_withdrawal_records" do
945
+ it "gets withdrawal records" do
946
+ VCR.use_cassette('v2/spot/wallet/withdrawal-records') do
947
+ response = client.spot_wallet_withdrawal_records(start_time: 1690196141868, end_time: 1690197141868)
948
+ _(response['msg']).must_equal('success')
949
+ _(response).must_include('data')
950
+ _(response['data']).must_be_kind_of(Array)
951
+ _(response['data'].first).must_include('orderId')
952
+ _(response['data'].first).must_include('tradeId')
953
+ _(response['data'].first).must_include('coin')
954
+ _(response['data'].first).must_include('dest')
955
+ _(response['data'].first).must_include('clientOid')
956
+ _(response['data'].first).must_include('type')
957
+ _(response['data'].first).must_include('tag')
958
+ _(response['data'].first).must_include('size')
959
+ _(response['data'].first).must_include('fee')
960
+ _(response['data'].first).must_include('status')
961
+ _(response['data'].first).must_include('toAddress')
962
+ _(response['data'].first).must_include('fromAddress')
963
+ _(response['data'].first).must_include('confirm')
964
+ _(response['data'].first).must_include('chain')
965
+ _(response['data'].first).must_include('cTime')
966
+ _(response['data'].first).must_include('uTime')
967
+ end
968
+ end
969
+ end
970
+
971
+ describe "#spot_wallet_deposit_records" do
972
+ it "gets deposit records" do
973
+ VCR.use_cassette('v2/spot/wallet/deposit-records') do
974
+ response = client.spot_wallet_deposit_records(
975
+ start_time: 1690196141868,
976
+ end_time: 1690197141868
977
+ )
978
+ _(response['msg']).must_equal('success')
979
+ _(response).must_include('data')
980
+ _(response['data']).must_be_kind_of(Array)
981
+ _(response['data'].first).must_include('orderId')
982
+ _(response['data'].first).must_include('tradeId')
983
+ _(response['data'].first).must_include('coin')
984
+ _(response['data'].first).must_include('type')
985
+ _(response['data'].first).must_include('size')
986
+ _(response['data'].first).must_include('status')
987
+ _(response['data'].first).must_include('toAddress')
988
+ _(response['data'].first).must_include('dest')
989
+ _(response['data'].first).must_include('chain')
990
+ _(response['data'].first).must_include('fromAddress')
991
+ _(response['data'].first).must_include('cTime')
992
+ _(response['data'].first).must_include('uTime')
993
+ end
994
+ end
995
+ end
996
+
997
+ describe "error handling" do
998
+ let(:mock_error){Minitest::Mock.new}
999
+
1000
+ before do
1001
+ client.use_logging = true
1002
+ mock_error.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
1003
+ end
1004
+
1005
+ after do
1006
+ client.use_logging = false
1007
+ mock_error.verify
1008
+ end
1009
+
1010
+ it "handles errors for public GET endpoints with NO arguments" do
1011
+ VCR.use_cassette('v2/spot/public/coins-when_an_error_occurs') do
1012
+ assert_raises(Bitget::Error) do
1013
+ client.stub(:log_error, mock_error) do
1014
+ client.spot_public_coins
1015
+ end
1016
+ end
1017
+ end
1018
+ end
1019
+
1020
+ it "handles errors for public GET endpoints WITH arguments" do
1021
+ VCR.use_cassette('v2/spot/market/candles-when_an_error_occurs') do
1022
+ assert_raises(Bitget::Error) do
1023
+ client.stub(:log_error, mock_error) do
1024
+ client.spot_market_candles(symbol: 'INVALID', granularity: '1min')
1025
+ end
1026
+ end
1027
+ end
1028
+ end
1029
+
1030
+ it "handles errors for authenticated GET endpoints with NO arguments" do
1031
+ VCR.use_cassette('v2/spot/account/info-when_an_error_occurs') do
1032
+ assert_raises(Bitget::Error) do
1033
+ client.stub(:log_error, mock_error) do
1034
+ client.spot_account_info
1035
+ end
1036
+ end
1037
+ end
1038
+ end
1039
+
1040
+ it "handles errors for authenticated GET endpoints WITH arguments" do
1041
+ VCR.use_cassette('v2/spot/account/bills-when_an_error_occurs') do
1042
+ assert_raises(Bitget::Error) do
1043
+ client.stub(:log_error, mock_error) do
1044
+ client.spot_account_bills(
1045
+ coin: 'BTC',
1046
+ business_type: 'deposit',
1047
+ group_type: 'transfer'
1048
+ )
1049
+ end
1050
+ end
1051
+ end
1052
+ end
1053
+
1054
+ it "handles errors for authenticated POST endpoints WITH arguments" do
1055
+ VCR.use_cassette('v2/spot/trade/place-order-when_an_error_occurs') do
1056
+ assert_raises(Bitget::Error) do
1057
+ client.stub(:log_error, mock_error) do
1058
+ client.spot_trade_place_order(
1059
+ symbol: 'BTCUSDT',
1060
+ side: 'buy',
1061
+ order_type: 'limit',
1062
+ force: 'normal',
1063
+ price: '30000',
1064
+ size: '0.001'
1065
+ )
1066
+ end
1067
+ end
1068
+ end
1069
+ end
1070
+ end
1071
+
1072
+ describe "logging" do
1073
+ before do
1074
+ client.use_logging = true
1075
+ FileUtils.rm_f(client.class.log_file_path)
1076
+ client.class.instance_variable_set(:@log_file_path, nil)
1077
+ client.class.instance_variable_set(:@logger, nil)
1078
+ end
1079
+
1080
+ after do
1081
+ client.use_logging = false
1082
+ FileUtils.rm_f(client.class.log_file_path)
1083
+ end
1084
+
1085
+ describe "logging configuration" do
1086
+ it "uses the configured log file path" do
1087
+ client.class.log_file_path = '/tmp/path'
1088
+ _(client.class.log_file_path).must_equal(File.expand_path('/tmp/path'))
1089
+ end
1090
+
1091
+ it "creates log directory if it doesn't exist" do
1092
+ nested_path = File.join(Dir.tmpdir, 'bitget_test', 'nested', 'test.log')
1093
+ client.class.log_file_path = nested_path
1094
+ client.class.logger
1095
+ _(File.directory?(File.dirname(nested_path))).must_equal(true)
1096
+ end
1097
+
1098
+ it "creates a daily rotating logger" do
1099
+ _(client.class.logger).must_be_kind_of(Logger)
1100
+ _(File.exist?(client.class.log_file_path)).must_equal(true)
1101
+ end
1102
+ end
1103
+
1104
+ describe "request logging" do
1105
+ it "logs requests" do
1106
+ client.class.logger
1107
+ VCR.use_cassette('v2/spot/public/coins-when_coin_is_supplied') do
1108
+ client.spot_public_coins(coin: 'BTC')
1109
+ end
1110
+ client.class.logger.close
1111
+ log_content = File.read(client.class.log_file_path)
1112
+ _(log_content).must_match(/GET https:\/\/api.bitget.com\/api\/v2\/spot\/public\/coins/)
1113
+ _(log_content).must_match(/Args: \{coin: \"BTC\"}/)
1114
+ _(log_content).must_match(/Headers: .+\"Content-Type\" => \"application\/json\"/)
1115
+ end
1116
+ end
1117
+
1118
+ describe "response logging" do
1119
+ it "logs responses" do
1120
+ client.class.logger
1121
+ VCR.use_cassette('v2/spot/public/coins-when_coin_is_supplied') do
1122
+ client.spot_public_coins(coin: 'BTC')
1123
+ end
1124
+ client.class.logger.close
1125
+ log_content = File.read(client.class.log_file_path)
1126
+ _(log_content).must_match(/Code:/)
1127
+ _(log_content).must_match(/Message:/)
1128
+ _(log_content).must_match(/Body:/)
1129
+ end
1130
+ end
93
1131
 
94
- context "when an error occurs" do
95
- it "logs then raises an error" do
96
- VCR.use_cassette('v2/spot/account/assets-when_an_error_occurs') do
97
- assert_raises(Bitget::Error) do
98
- mocked_method = Minitest::Mock.new
99
- mocked_method.expect(:call, nil, [], code: '418', message: "I'm a teapot", body: '')
100
- client.stub(:log_error, mocked_method) do
101
- client.spot_account_assets
102
- end
103
- mocked_method.verify
1132
+ describe "error logging" do
1133
+ it "logs error responses" do
1134
+ client.class.logger
1135
+ VCR.use_cassette('v2/spot/public/coins-when_error_occurs') do
1136
+ begin
1137
+ client.spot_public_coins(coin: 'INVALID')
1138
+ rescue Bitget::Error
104
1139
  end
105
1140
  end
1141
+ client.class.logger.close
1142
+ log_content = File.read(client.class.log_file_path)
1143
+ _(log_content).must_match(/Code:/)
1144
+ _(log_content).must_match(/Message:/)
1145
+ _(log_content).must_match(/Body:/)
106
1146
  end
107
1147
  end
108
1148
  end