laplace-api 3.1.0 → 4.1.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.
@@ -1,15 +1,189 @@
1
- import { Logger } from 'winston';
2
- import { LaplaceConfiguration } from '../utilities/configuration';
3
- import { StockClient, AssetClass, HistoricalPricePeriod, HistoricalPriceInterval } from '../client/stocks';
4
- import { Region, Locale } from '../client/collections';
5
- import './client_test_suite';
1
+ import { Logger } from "winston";
2
+ import { LaplaceConfiguration } from "../utilities/configuration";
3
+ import {
4
+ StockClient,
5
+ HistoricalPricePeriod,
6
+ HistoricalPriceInterval,
7
+ AssetClass,
8
+ Stock,
9
+ AssetType,
10
+ Market,
11
+ StockPriceGraph,
12
+ MarketState,
13
+ EarningsTranscriptWithSummary,
14
+ EarningsTranscriptListItem
15
+ } from "../client/stocks";
16
+ import "./client_test_suite";
17
+ import { Region, Locale } from "../client/collections";
18
+ import { PaginatedResponse } from "../client/capital_increase";
6
19
 
20
+ const mockStocksResponse: Stock[] = [
21
+ {
22
+ id: "61dd0d6f0ec2114146342fd0",
23
+ assetType: AssetType.Stock,
24
+ name: "Tüpraş",
25
+ symbol: "TUPRS",
26
+ sectorId: "sector123",
27
+ industryId: "industry456",
28
+ updatedDate: "2024-03-14T10:00:00Z",
29
+ dailyChange: 2.5,
30
+ active: true
31
+ },
32
+ {
33
+ id: "61dd0d6f0ec2114146342fd1",
34
+ assetType: AssetType.Stock,
35
+ name: "Garanti Bankası",
36
+ symbol: "GARAN",
37
+ sectorId: "sector789",
38
+ industryId: "industry101",
39
+ updatedDate: "2024-03-14T10:00:00Z",
40
+ dailyChange: -1.2,
41
+ active: true
42
+ }
43
+ ];
7
44
 
8
- describe('Stocks', () => {
45
+ const mockStockDetailResponse = {
46
+ id: "61dd0d6f0ec2114146342fd0",
47
+ assetType: AssetType.Stock,
48
+ assetClass: AssetClass.Equity,
49
+ name: "Tüpraş",
50
+ symbol: "TUPRS",
51
+ sectorId: "sector123",
52
+ industryId: "industry456",
53
+ updatedDate: "2024-03-14T10:00:00Z",
54
+ dailyChange: 2.5,
55
+ active: true,
56
+ description: "Türkiye'nin en büyük rafineri şirketi",
57
+ shortDescription: "Rafineri şirketi",
58
+ region: Region.Tr,
59
+ localized_description: {
60
+ tr: "Türkiye'nin en büyük rafineri şirketi",
61
+ en: "Turkey's largest refinery company"
62
+ },
63
+ localizedShortDescription: {
64
+ tr: "Rafineri şirketi",
65
+ en: "Refinery company"
66
+ },
67
+ markets: [Market.Yildiz]
68
+ };
69
+
70
+ const mockHistoricalPricesResponse: StockPriceGraph[] = [
71
+ {
72
+ symbol: "TUPRS",
73
+ "1D": [
74
+ { d: 1710374400000, c: 425.5, h: 428.0, l: 422.0, o: 423.0 },
75
+ { d: 1710378000000, c: 426.8, h: 427.5, l: 425.0, o: 425.5 }
76
+ ],
77
+ "1W": [
78
+ { d: 1709856000000, c: 420.5, h: 422.0, l: 419.0, o: 419.5 },
79
+ { d: 1709942400000, c: 423.0, h: 424.5, l: 420.0, o: 420.5 }
80
+ ],
81
+ "1M": [
82
+ { d: 1707436800000, c: 415.0, h: 416.5, l: 414.0, o: 414.5 },
83
+ { d: 1707523200000, c: 417.2, h: 418.0, l: 415.0, o: 415.0 }
84
+ ],
85
+ "3M": [],
86
+ "1Y": [],
87
+ "2Y": [],
88
+ "3Y": [],
89
+ "5Y": []
90
+ }
91
+ ];
92
+
93
+ const mockStockRestrictionsResponse = [
94
+ {
95
+ id: 1,
96
+ title: "Bedelli Sermaye Artırımı",
97
+ description: "Şirket bedelli sermaye artırımı yapacaktır",
98
+ symbol: "TUPRS",
99
+ startDate: "2024-03-15T00:00:00Z",
100
+ endDate: "2024-03-20T00:00:00Z",
101
+ market: Market.Yildiz
102
+ },
103
+ {
104
+ id: 2,
105
+ title: "Temettü Ödemesi",
106
+ description: "Şirket temettü ödemesi yapacaktır",
107
+ symbol: "TUPRS",
108
+ startDate: "2024-04-01T00:00:00Z",
109
+ endDate: "2024-04-01T00:00:00Z",
110
+ market: Market.Yildiz
111
+ }
112
+ ];
113
+
114
+ const mockTickRulesResponse = {
115
+ basePrice: 425.5,
116
+ additionalPrice: 0.1,
117
+ lowerPriceLimit: 382.95,
118
+ upperPriceLimit: 468.05,
119
+ rules: [
120
+ { priceFrom: 0, priceTo: 20, tickSize: 0.01 },
121
+ { priceFrom: 20, priceTo: 50, tickSize: 0.02 },
122
+ { priceFrom: 50, priceTo: 100, tickSize: 0.05 }
123
+ ]
124
+ };
125
+
126
+ const mockEarningsTranscriptList: EarningsTranscriptListItem[] = [
127
+ {
128
+ symbol: "TUPRS",
129
+ year: 2024,
130
+ quarter: 1,
131
+ date: "2024-05-15",
132
+ fiscal_year: 2024
133
+ },
134
+ {
135
+ symbol: "TUPRS",
136
+ year: 2023,
137
+ quarter: 4,
138
+ date: "2024-02-20",
139
+ fiscal_year: 2023
140
+ }
141
+ ];
142
+
143
+ const mockEarningsTranscriptDetail: EarningsTranscriptWithSummary = {
144
+ symbol: "TUPRS",
145
+ year: 2024,
146
+ quarter: 1,
147
+ date: "2024-05-15",
148
+ content: "Q1 2024 earnings call transcript content...",
149
+ summary: "Strong Q1 performance with 15% revenue growth",
150
+ has_summary: true
151
+ };
152
+
153
+ const mockMarketStates: MarketState[] = [
154
+ {
155
+ id: 1,
156
+ marketSymbol: "XIST",
157
+ state: "OPEN",
158
+ lastTimestamp: "2024-03-14T10:00:00Z",
159
+ stockSymbol: "TUPRS"
160
+ },
161
+ {
162
+ id: 2,
163
+ marketSymbol: "XIST",
164
+ state: "CLOSED",
165
+ lastTimestamp: "2024-03-14T18:00:00Z",
166
+ stockSymbol: "GARAN"
167
+ }
168
+ ];
169
+
170
+ const mockPaginatedMarketStates: PaginatedResponse<MarketState> = {
171
+ recordCount: 2,
172
+ items: mockMarketStates
173
+ };
174
+
175
+ const mockSingleMarketState: MarketState = {
176
+ id: 1,
177
+ marketSymbol: "XIST",
178
+ state: "OPEN",
179
+ lastTimestamp: "2024-03-14T10:00:00Z",
180
+ stockSymbol: "TUPRS"
181
+ };
182
+
183
+ describe("Stocks Client", () => {
9
184
  let client: StockClient;
10
185
 
11
186
  beforeAll(() => {
12
- // Assuming global.testSuite is set up as in the previous example
13
187
  const config = (global as any).testSuite.config as LaplaceConfiguration;
14
188
  const logger: Logger = {
15
189
  info: jest.fn(),
@@ -21,77 +195,633 @@ describe('Stocks', () => {
21
195
  client = new StockClient(config, logger);
22
196
  });
23
197
 
24
- test('GetAllStocks', async () => {
25
- const resp = await client.getAllStocks(Region.Tr);
26
- expect(resp).not.toBeEmpty();
27
- });
198
+ describe("Integration Tests", () => {
199
+ describe("getAllStocks", () => {
200
+ test("should return stocks list for TR region", async () => {
201
+ const resp = await client.getAllStocks(Region.Tr);
28
202
 
203
+ expect(resp).not.toBeEmpty();
29
204
 
30
- test('GetAllStocksWithPagination', async () => {
31
- const resp = await client.getAllStocks(Region.Tr, 10, 10);
32
- expect(resp).not.toBeEmpty();
33
- expect(resp.length).toBe(10);
34
- });
205
+ const firstStock = resp[0];
206
+ expect(typeof firstStock.id).toBe("string");
207
+ expect(typeof firstStock.assetType).toBe("string");
208
+ expect(typeof firstStock.name).toBe("string");
209
+ expect(typeof firstStock.symbol).toBe("string");
210
+ expect(typeof firstStock.sectorId).toBe("string");
211
+ expect(typeof firstStock.industryId).toBe("string");
212
+ expect(typeof firstStock.updatedDate).toBe("string");
213
+ expect(typeof firstStock.active).toBe("boolean");
35
214
 
36
- test('GetStockDetailByID', async () => {
37
- const resp = await client.getStockDetailById("61dd0d6f0ec2114146342fd0", Locale.Tr);
38
- expect(resp).not.toBeEmpty();
39
- });
215
+ if (firstStock.dailyChange !== undefined) {
216
+ expect(typeof firstStock.dailyChange).toBe("number");
217
+ }
218
+ });
40
219
 
41
- test('GetStockDetailBySymbol', async () => {
42
- const resp = await client.getStockDetailBySymbol("TUPRS", AssetClass.Equity, Region.Tr, Locale.Tr);
43
- expect(resp).not.toBeEmpty();
44
- });
220
+ test("should handle pagination correctly", async () => {
221
+ const resp = await client.getAllStocks(Region.Tr, 10, 10);
45
222
 
46
- test('GetHistoricalPrices', async () => {
47
- const resp = await client.getHistoricalPrices(
48
- ["TUPRS", "SASA"],
49
- Region.Tr,
50
- [HistoricalPricePeriod.OneDay, HistoricalPricePeriod.OneWeek, HistoricalPricePeriod.OneMonth]
51
- );
52
- expect(resp).not.toBeEmpty();
53
-
54
- for (const price of resp) {
55
- expect(price).not.toBeEmpty();
56
- }
57
- });
223
+ expect(resp).not.toBeEmpty();
224
+ expect(resp.length).toBeLessThanOrEqual(10);
225
+ });
226
+ });
58
227
 
59
- test('GetCustomHistoricalPrices', async () => {
60
- let resp = await client.getCustomHistoricalPrices(
61
- "TUPRS",
62
- Region.Tr,
63
- "2024-01-01",
64
- "2024-03-01",
65
- HistoricalPriceInterval.OneDay,
66
- false
67
- );
68
- expect(resp).not.toBeEmpty();
69
-
70
- for (const price of resp) {
71
- expect(price).not.toBeEmpty();
72
- }
73
-
74
- resp = await client.getCustomHistoricalPrices(
75
- "SASA",
76
- Region.Tr,
77
- "2024-01-01 10:00:00",
78
- "2024-01-05 10:00:00",
79
- HistoricalPriceInterval.OneHour,
80
- true
81
- );
82
- expect(resp).not.toBeEmpty();
83
-
84
- for (const price of resp) {
85
- expect(price).not.toBeEmpty();
86
- }
87
- });
228
+ describe("getStockDetailById", () => {
229
+ test("should return stock detail by ID", async () => {
230
+ const resp = await client.getStockDetailById(
231
+ "61dd0d6f0ec2114146342fd0",
232
+ Locale.Tr
233
+ );
234
+
235
+ expect(resp).toBeDefined();
236
+ expect(typeof resp.id).toBe("string");
237
+ expect(typeof resp.assetClass).toBe("string");
238
+ expect(typeof resp.description).toBe("string");
239
+ expect(typeof resp.shortDescription).toBe("string");
240
+ expect(typeof resp.region).toBe("string");
241
+ expect(typeof resp.localized_description).toBe("object");
242
+ expect(typeof resp.localizedShortDescription).toBe("object");
243
+
244
+ if (resp.markets) {
245
+ expect(Array.isArray(resp.markets)).toBe(true);
246
+ }
247
+ });
248
+ });
249
+
250
+ describe("getStockDetailBySymbol", () => {
251
+ test("should return stock detail by symbol", async () => {
252
+ const resp = await client.getStockDetailBySymbol(
253
+ "TUPRS",
254
+ AssetClass.Equity,
255
+ Region.Tr,
256
+ Locale.Tr
257
+ );
258
+
259
+ expect(resp).toBeDefined();
260
+ expect(resp.symbol).toBe("TUPRS");
261
+ expect(typeof resp.assetClass).toBe("string");
262
+ expect(typeof resp.description).toBe("string");
263
+ expect(typeof resp.region).toBe("string");
264
+ });
265
+ });
266
+
267
+ describe("getHistoricalPrices", () => {
268
+ test("should return historical prices for multiple symbols", async () => {
269
+ const resp = await client.getHistoricalPrices(
270
+ ["TUPRS", "SASA"],
271
+ Region.Tr,
272
+ [
273
+ HistoricalPricePeriod.OneDay,
274
+ HistoricalPricePeriod.OneWeek,
275
+ HistoricalPricePeriod.OneMonth,
276
+ ]
277
+ );
278
+
279
+ expect(resp).not.toBeEmpty();
280
+
281
+ const firstPriceGraph = resp[0];
282
+ expect(typeof firstPriceGraph.symbol).toBe("string");
283
+ expect(Array.isArray(firstPriceGraph["1D"])).toBe(true);
284
+ expect(Array.isArray(firstPriceGraph["1W"])).toBe(true);
285
+ expect(Array.isArray(firstPriceGraph["1M"])).toBe(true);
286
+
287
+ if (firstPriceGraph["1D"].length > 0) {
288
+ const firstDataPoint = firstPriceGraph["1D"][0];
289
+ expect(typeof firstDataPoint.d).toBe("number");
290
+ expect(typeof firstDataPoint.c).toBe("number");
291
+ expect(typeof firstDataPoint.h).toBe("number");
292
+ expect(typeof firstDataPoint.l).toBe("number");
293
+ expect(typeof firstDataPoint.o).toBe("number");
294
+ }
295
+ });
296
+ });
297
+
298
+ describe("getCustomHistoricalPrices", () => {
299
+ test("should return custom historical prices", async () => {
300
+ const resp = await client.getCustomHistoricalPrices(
301
+ "TUPRS",
302
+ Region.Tr,
303
+ "2024-01-01",
304
+ "2024-03-01",
305
+ HistoricalPriceInterval.OneDay,
306
+ false
307
+ );
308
+
309
+ expect(resp).not.toBeEmpty();
310
+
311
+ const firstDataPoint = resp[0];
312
+ expect(typeof firstDataPoint.d).toBe("number");
313
+ expect(typeof firstDataPoint.c).toBe("number");
314
+ expect(typeof firstDataPoint.h).toBe("number");
315
+ expect(typeof firstDataPoint.l).toBe("number");
316
+ expect(typeof firstDataPoint.o).toBe("number");
317
+ });
318
+
319
+ test("should handle detailed historical prices", async () => {
320
+ const resp = await client.getCustomHistoricalPrices(
321
+ "SASA",
322
+ Region.Tr,
323
+ "2024-01-01 10:00:00",
324
+ "2024-01-05 10:00:00",
325
+ HistoricalPriceInterval.OneHour,
326
+ true
327
+ );
328
+
329
+ expect(resp).not.toBeEmpty();
330
+ });
331
+ });
332
+
333
+ describe("getStockRestrictions", () => {
334
+ test("should return stock restrictions for specific symbol", async () => {
335
+ const resp = await client.getStockRestrictions("TUPRS", Region.Tr);
336
+
337
+ if (resp && resp.length > 0) {
338
+ const firstRestriction = resp[0];
339
+ expect(typeof firstRestriction.id).toBe("number");
340
+ expect(typeof firstRestriction.title).toBe("string");
341
+ expect(typeof firstRestriction.description).toBe("string");
342
+ expect(typeof firstRestriction.startDate).toBe("string");
343
+ expect(typeof firstRestriction.endDate).toBe("string");
344
+
345
+ if (firstRestriction.symbol) {
346
+ expect(typeof firstRestriction.symbol).toBe("string");
347
+ }
348
+ if (firstRestriction.market) {
349
+ expect(typeof firstRestriction.market).toBe("string");
350
+ }
351
+ }
352
+ });
353
+ });
354
+
355
+ describe("getAllStockRestrictions", () => {
356
+ test("should return all stock restrictions for region", async () => {
357
+ const resp = await client.getAllStockRestrictions(Region.Tr);
88
358
 
89
- test('GetStockRestrictions', async () => {
90
- await client.getStockRestrictions("TUPRS", Region.Tr);
359
+ expect(Array.isArray(resp)).toBe(true);
360
+
361
+ if (resp.length > 0) {
362
+ const firstRestriction = resp[0];
363
+ expect(typeof firstRestriction.id).toBe("number");
364
+ expect(typeof firstRestriction.title).toBe("string");
365
+ expect(typeof firstRestriction.description).toBe("string");
366
+ expect(typeof firstRestriction.startDate).toBe("string");
367
+ expect(typeof firstRestriction.endDate).toBe("string");
368
+ }
369
+ });
370
+ });
371
+
372
+ describe("getTickRules", () => {
373
+ test("should return tick rules for symbol", async () => {
374
+ const resp = await client.getTickRules("TUPRS", Region.Tr);
375
+
376
+ expect(resp).toBeDefined();
377
+ expect(typeof resp.basePrice).toBe("number");
378
+ expect(typeof resp.additionalPrice).toBe("number");
379
+ expect(typeof resp.lowerPriceLimit).toBe("number");
380
+ expect(typeof resp.upperPriceLimit).toBe("number");
381
+
382
+ if (resp.rules !== null) {
383
+ expect(Array.isArray(resp.rules)).toBe(true);
384
+ }
385
+ });
386
+ });
387
+
388
+ describe("getEarningsTranscripts", () => {
389
+ test("should return earnings transcript list", async () => {
390
+ const resp = await client.getEarningsTranscripts("TUPRS", Region.Tr);
391
+
392
+ expect(Array.isArray(resp)).toBe(true);
393
+
394
+ if (resp.length > 0) {
395
+ const firstTranscript = resp[0];
396
+ expect(typeof firstTranscript.symbol).toBe("string");
397
+ expect(typeof firstTranscript.year).toBe("number");
398
+ expect(typeof firstTranscript.quarter).toBe("number");
399
+ expect(typeof firstTranscript.date).toBe("string");
400
+ expect(typeof firstTranscript.fiscal_year).toBe("number");
401
+ }
402
+ });
403
+ });
404
+
405
+ describe("getEarningsTranscript", () => {
406
+ test("should return earnings transcript detail", async () => {
407
+ const resp = await client.getEarningsTranscript("TUPRS", 2023, 4);
408
+
409
+ expect(resp).toBeDefined();
410
+ expect(typeof resp.symbol).toBe("string");
411
+ expect(typeof resp.year).toBe("number");
412
+ expect(typeof resp.quarter).toBe("number");
413
+ expect(typeof resp.date).toBe("string");
414
+ expect(typeof resp.content).toBe("string");
415
+ expect(typeof resp.has_summary).toBe("boolean");
416
+
417
+ if (resp.summary) {
418
+ expect(typeof resp.summary).toBe("string");
419
+ }
420
+ });
421
+ });
422
+
423
+ describe("getStockStateAll", () => {
424
+ test("should return paginated stock states", async () => {
425
+ const resp = await client.getStockStateAll(0, 10, Region.Tr);
426
+
427
+ expect(resp).toBeDefined();
428
+ expect(Array.isArray(resp.items)).toBe(true);
429
+ expect(typeof resp.recordCount).toBe("number");
430
+
431
+ if (resp.items.length > 0) {
432
+ const firstState = resp.items[0];
433
+ expect(typeof firstState.id).toBe("number");
434
+ expect(typeof firstState.state).toBe("string");
435
+ expect(typeof firstState.lastTimestamp).toBe("string");
436
+ }
437
+ });
438
+ });
439
+
440
+ describe("getStockState", () => {
441
+ test("should return single stock state", async () => {
442
+ const resp = await client.getStockState("TUPRS");
443
+
444
+ expect(resp).toBeDefined();
445
+ expect(typeof resp.id).toBe("number");
446
+ expect(typeof resp.state).toBe("string");
447
+ expect(typeof resp.lastTimestamp).toBe("string");
448
+
449
+ if (resp.stockSymbol) {
450
+ expect(typeof resp.stockSymbol).toBe("string");
451
+ }
452
+ if (resp.marketSymbol) {
453
+ expect(typeof resp.marketSymbol).toBe("string");
454
+ }
455
+ });
456
+ });
457
+
458
+ describe("getStateAll", () => {
459
+ test("should return paginated market states", async () => {
460
+ const resp = await client.getStateAll(0, 10, Region.Tr);
461
+
462
+ expect(resp).toBeDefined();
463
+ expect(Array.isArray(resp.items)).toBe(true);
464
+ expect(typeof resp.recordCount).toBe("number");
465
+
466
+ if (resp.items.length > 0) {
467
+ const firstState = resp.items[0];
468
+ expect(typeof firstState.id).toBe("number");
469
+ expect(typeof firstState.state).toBe("string");
470
+ expect(typeof firstState.lastTimestamp).toBe("string");
471
+ }
472
+ });
473
+ });
474
+
475
+ describe("getState", () => {
476
+ test("should return single market state", async () => {
477
+ const resp = await client.getState("XIST");
478
+
479
+ expect(resp).toBeDefined();
480
+ expect(typeof resp.id).toBe("number");
481
+ expect(typeof resp.state).toBe("string");
482
+ expect(typeof resp.lastTimestamp).toBe("string");
483
+
484
+ if (resp.marketSymbol) {
485
+ expect(typeof resp.marketSymbol).toBe("string");
486
+ }
487
+ });
488
+ });
91
489
  });
92
490
 
93
- test('GetTickRules', async () => {
94
- const resp = await client.getTickRules("TUPRS", Region.Tr);
95
- expect(resp).not.toBeEmpty();
491
+ describe("Mock Tests", () => {
492
+ beforeEach(() => {
493
+ jest.clearAllMocks();
494
+ });
495
+
496
+ describe("getAllStocks", () => {
497
+ test("should handle getAllStocks response correctly with mock data", async () => {
498
+ jest.spyOn(client, 'getAllStocks').mockResolvedValue(mockStocksResponse);
499
+
500
+ const resp = await client.getAllStocks(Region.Tr);
501
+
502
+ expect(resp).toHaveLength(2);
503
+
504
+ const firstStock = resp[0];
505
+ expect(firstStock.id).toBe("61dd0d6f0ec2114146342fd0");
506
+ expect(firstStock.assetType).toBe(AssetType.Stock);
507
+ expect(firstStock.name).toBe("Tüpraş");
508
+ expect(firstStock.symbol).toBe("TUPRS");
509
+ expect(firstStock.sectorId).toBe("sector123");
510
+ expect(firstStock.industryId).toBe("industry456");
511
+ expect(firstStock.updatedDate).toBe("2024-03-14T10:00:00Z");
512
+ expect(firstStock.dailyChange).toBe(2.5);
513
+ expect(firstStock.active).toBe(true);
514
+
515
+ const secondStock = resp[1];
516
+ expect(secondStock.id).toBe("61dd0d6f0ec2114146342fd1");
517
+ expect(secondStock.symbol).toBe("GARAN");
518
+ expect(secondStock.dailyChange).toBe(-1.2);
519
+
520
+ expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr);
521
+ });
522
+
523
+ test("should handle pagination correctly with mock data", async () => {
524
+ jest.spyOn(client, 'getAllStocks').mockResolvedValue([mockStocksResponse[0]]);
525
+
526
+ const resp = await client.getAllStocks(Region.Tr, 1, 0);
527
+
528
+ expect(resp).toHaveLength(1);
529
+ expect(resp[0].symbol).toBe("TUPRS");
530
+
531
+ expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr, 1, 0);
532
+ });
533
+
534
+ test("should handle API errors correctly", async () => {
535
+ jest.spyOn(client, 'getAllStocks').mockRejectedValue(new Error("API Error"));
536
+
537
+ await expect(client.getAllStocks(Region.Tr)).rejects.toThrow("API Error");
538
+ });
539
+ });
540
+
541
+ describe("getStockDetailById", () => {
542
+ test("should return stock detail by ID with mock data", async () => {
543
+ jest.spyOn(client, 'getStockDetailById').mockResolvedValue(mockStockDetailResponse);
544
+
545
+ const resp = await client.getStockDetailById("61dd0d6f0ec2114146342fd0", Locale.Tr);
546
+
547
+ expect(resp).toBeDefined();
548
+ expect(resp.id).toBe("61dd0d6f0ec2114146342fd0");
549
+ expect(resp.assetType).toBe(AssetType.Stock);
550
+ expect(resp.assetClass).toBe(AssetClass.Equity);
551
+ expect(resp.description).toBe("Türkiye'nin en büyük rafineri şirketi");
552
+ expect(resp.shortDescription).toBe("Rafineri şirketi");
553
+ expect(resp.region).toBe(Region.Tr);
554
+ expect(resp.localized_description).toEqual({
555
+ tr: "Türkiye'nin en büyük rafineri şirketi",
556
+ en: "Turkey's largest refinery company"
557
+ });
558
+ expect(resp.localizedShortDescription).toEqual({
559
+ tr: "Rafineri şirketi",
560
+ en: "Refinery company"
561
+ });
562
+ expect(resp.markets).toEqual([Market.Yildiz]);
563
+
564
+ expect(client.getStockDetailById).toHaveBeenCalledWith("61dd0d6f0ec2114146342fd0", Locale.Tr);
565
+ });
566
+
567
+ test("should handle API errors for stock detail", async () => {
568
+ jest.spyOn(client, 'getStockDetailById').mockRejectedValue(new Error("Stock not found"));
569
+
570
+ await expect(client.getStockDetailById("invalid_id", Locale.Tr))
571
+ .rejects.toThrow("Stock not found");
572
+ });
573
+ });
574
+
575
+ describe("getHistoricalPrices", () => {
576
+ test("should return historical prices for multiple symbols with mock data", async () => {
577
+ jest.spyOn(client, 'getHistoricalPrices').mockResolvedValue(mockHistoricalPricesResponse);
578
+
579
+ const symbols = ["TUPRS"];
580
+ const periods = [
581
+ HistoricalPricePeriod.OneDay,
582
+ HistoricalPricePeriod.OneWeek,
583
+ HistoricalPricePeriod.OneMonth
584
+ ];
585
+
586
+ const resp = await client.getHistoricalPrices(symbols, Region.Tr, periods);
587
+
588
+ expect(resp).toHaveLength(1);
589
+
590
+ const firstPriceGraph = resp[0];
591
+ expect(firstPriceGraph.symbol).toBe("TUPRS");
592
+
593
+ expect(firstPriceGraph["1D"]).toHaveLength(2);
594
+ const firstDayPoint = firstPriceGraph["1D"][0];
595
+ expect(firstDayPoint.d).toBe(1710374400000);
596
+ expect(firstDayPoint.c).toBe(425.5);
597
+ expect(firstDayPoint.h).toBe(428.0);
598
+ expect(firstDayPoint.l).toBe(422.0);
599
+ expect(firstDayPoint.o).toBe(423.0);
600
+ expect(firstPriceGraph["1W"]).toHaveLength(2);
601
+ expect(firstPriceGraph["1M"]).toHaveLength(2);
602
+
603
+ expect(client.getHistoricalPrices).toHaveBeenCalledWith(
604
+ symbols,
605
+ Region.Tr,
606
+ periods
607
+ );
608
+ });
609
+
610
+ test("should handle API errors for historical prices", async () => {
611
+ jest.spyOn(client, 'getHistoricalPrices').mockRejectedValue(new Error("Failed to fetch historical prices"));
612
+
613
+ await expect(client.getHistoricalPrices(
614
+ ["TUPRS"],
615
+ Region.Tr,
616
+ [HistoricalPricePeriod.OneDay]
617
+ )).rejects.toThrow("Failed to fetch historical prices");
618
+ });
619
+ });
620
+
621
+ describe("getStockRestrictions", () => {
622
+ test("should return stock restrictions with mock data", async () => {
623
+ jest.spyOn(client, 'getStockRestrictions').mockResolvedValue(mockStockRestrictionsResponse);
624
+
625
+ const resp = await client.getStockRestrictions("TUPRS", Region.Tr);
626
+
627
+ expect(resp).toHaveLength(2);
628
+
629
+ const firstRestriction = resp[0];
630
+ expect(firstRestriction.id).toBe(1);
631
+ expect(firstRestriction.title).toBe("Bedelli Sermaye Artırımı");
632
+ expect(firstRestriction.description).toBe("Şirket bedelli sermaye artırımı yapacaktır");
633
+ expect(firstRestriction.symbol).toBe("TUPRS");
634
+ expect(firstRestriction.startDate).toBe("2024-03-15T00:00:00Z");
635
+ expect(firstRestriction.endDate).toBe("2024-03-20T00:00:00Z");
636
+ expect(firstRestriction.market).toBe(Market.Yildiz);
637
+
638
+ expect(client.getStockRestrictions).toHaveBeenCalledWith("TUPRS", Region.Tr);
639
+ });
640
+
641
+ test("should handle API errors for stock restrictions", async () => {
642
+ jest.spyOn(client, 'getStockRestrictions').mockRejectedValue(new Error("Failed to fetch restrictions"));
643
+
644
+ await expect(client.getStockRestrictions("TUPRS", Region.Tr))
645
+ .rejects.toThrow("Failed to fetch restrictions");
646
+ });
647
+ });
648
+
649
+ describe("getTickRules", () => {
650
+ test("should return tick rules with mock data", async () => {
651
+ jest.spyOn(client, 'getTickRules').mockResolvedValue(mockTickRulesResponse);
652
+
653
+ const resp = await client.getTickRules("TUPRS", Region.Tr);
654
+
655
+ expect(resp.basePrice).toBe(425.5);
656
+ expect(resp.additionalPrice).toBe(0.1);
657
+ expect(resp.lowerPriceLimit).toBe(382.95);
658
+ expect(resp.upperPriceLimit).toBe(468.05);
659
+ expect(resp.rules).toHaveLength(3);
660
+
661
+ const firstRule = resp.rules![0];
662
+ expect(firstRule.priceFrom).toBe(0);
663
+ expect(firstRule.priceTo).toBe(20);
664
+ expect(firstRule.tickSize).toBe(0.01);
665
+
666
+ expect(client.getTickRules).toHaveBeenCalledWith("TUPRS", Region.Tr);
667
+ });
668
+
669
+ test("should handle API errors for tick rules", async () => {
670
+ jest.spyOn(client, 'getTickRules').mockRejectedValue(new Error("Failed to fetch tick rules"));
671
+
672
+ await expect(client.getTickRules("TUPRS", Region.Tr))
673
+ .rejects.toThrow("Failed to fetch tick rules");
674
+ });
675
+ });
676
+
677
+ describe("getEarningsTranscripts", () => {
678
+ test("should return earnings transcript list with mock data", async () => {
679
+ jest.spyOn(client, 'getEarningsTranscripts').mockResolvedValue(mockEarningsTranscriptList);
680
+
681
+ const resp = await client.getEarningsTranscripts("TUPRS", Region.Tr);
682
+
683
+ expect(resp).toHaveLength(2);
684
+
685
+ const firstTranscript = resp[0];
686
+ expect(firstTranscript.symbol).toBe("TUPRS");
687
+ expect(firstTranscript.year).toBe(2024);
688
+ expect(firstTranscript.quarter).toBe(1);
689
+ expect(firstTranscript.date).toBe("2024-05-15");
690
+ expect(firstTranscript.fiscal_year).toBe(2024);
691
+
692
+ const secondTranscript = resp[1];
693
+ expect(secondTranscript.year).toBe(2023);
694
+ expect(secondTranscript.quarter).toBe(4);
695
+
696
+ expect(client.getEarningsTranscripts).toHaveBeenCalledWith("TUPRS", Region.Tr);
697
+ });
698
+
699
+ test("should handle API errors for earnings transcripts", async () => {
700
+ jest.spyOn(client, 'getEarningsTranscripts').mockRejectedValue(new Error("Transcripts not found"));
701
+
702
+ await expect(client.getEarningsTranscripts("INVALID", Region.Tr))
703
+ .rejects.toThrow("Transcripts not found");
704
+ });
705
+ });
706
+
707
+ describe("getEarningsTranscript", () => {
708
+ test("should return earnings transcript detail with mock data", async () => {
709
+ jest.spyOn(client, 'getEarningsTranscript').mockResolvedValue(mockEarningsTranscriptDetail);
710
+
711
+ const resp = await client.getEarningsTranscript("TUPRS", 2024, 1);
712
+
713
+ expect(resp.symbol).toBe("TUPRS");
714
+ expect(resp.year).toBe(2024);
715
+ expect(resp.quarter).toBe(1);
716
+ expect(resp.date).toBe("2024-05-15");
717
+ expect(resp.content).toBe("Q1 2024 earnings call transcript content...");
718
+ expect(resp.summary).toBe("Strong Q1 performance with 15% revenue growth");
719
+ expect(resp.has_summary).toBe(true);
720
+
721
+ expect(client.getEarningsTranscript).toHaveBeenCalledWith("TUPRS", 2024, 1);
722
+ });
723
+
724
+ test("should handle API errors for earnings transcript detail", async () => {
725
+ jest.spyOn(client, 'getEarningsTranscript').mockRejectedValue(new Error("Transcript not found"));
726
+
727
+ await expect(client.getEarningsTranscript("TUPRS", 2020, 1))
728
+ .rejects.toThrow("Transcript not found");
729
+ });
730
+ });
731
+
732
+ describe("getStockStateAll", () => {
733
+ test("should return paginated stock states with mock data", async () => {
734
+ jest.spyOn(client, 'getStockStateAll').mockResolvedValue(mockPaginatedMarketStates);
735
+
736
+ const resp = await client.getStockStateAll(0, 10, Region.Tr);
737
+
738
+ expect(resp.items).toHaveLength(2);
739
+ expect(resp.recordCount).toBe(2);
740
+
741
+ const firstState = resp.items[0];
742
+ expect(firstState.id).toBe(1);
743
+ expect(firstState.marketSymbol).toBe("XIST");
744
+ expect(firstState.state).toBe("OPEN");
745
+ expect(firstState.stockSymbol).toBe("TUPRS");
746
+
747
+ expect(client.getStockStateAll).toHaveBeenCalledWith(0, 10, Region.Tr);
748
+ });
749
+
750
+ test("should handle API errors for stock state all", async () => {
751
+ jest.spyOn(client, 'getStockStateAll').mockRejectedValue(new Error("Failed to fetch stock states"));
752
+
753
+ await expect(client.getStockStateAll(0, 10, Region.Tr))
754
+ .rejects.toThrow("Failed to fetch stock states");
755
+ });
756
+ });
757
+
758
+ describe("getStockState", () => {
759
+ test("should return single stock state with mock data", async () => {
760
+ jest.spyOn(client, 'getStockState').mockResolvedValue(mockSingleMarketState);
761
+
762
+ const resp = await client.getStockState("TUPRS");
763
+
764
+ expect(resp.id).toBe(1);
765
+ expect(resp.marketSymbol).toBe("XIST");
766
+ expect(resp.state).toBe("OPEN");
767
+ expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
768
+ expect(resp.stockSymbol).toBe("TUPRS");
769
+
770
+ expect(client.getStockState).toHaveBeenCalledWith("TUPRS");
771
+ });
772
+
773
+ test("should handle API errors for single stock state", async () => {
774
+ jest.spyOn(client, 'getStockState').mockRejectedValue(new Error("Stock state not found"));
775
+
776
+ await expect(client.getStockState("INVALID"))
777
+ .rejects.toThrow("Stock state not found");
778
+ });
779
+ });
780
+
781
+ describe("getStateAll", () => {
782
+ test("should return paginated market states with mock data", async () => {
783
+ jest.spyOn(client, 'getStateAll').mockResolvedValue(mockPaginatedMarketStates);
784
+
785
+ const resp = await client.getStateAll(0, 10, Region.Tr);
786
+
787
+ expect(resp.items).toHaveLength(2);
788
+ expect(resp.recordCount).toBe(2);
789
+
790
+ const firstState = resp.items[0];
791
+ expect(firstState.state).toBe("OPEN");
792
+ expect(firstState.lastTimestamp).toBe("2024-03-14T10:00:00Z");
793
+
794
+ expect(client.getStateAll).toHaveBeenCalledWith(0, 10, Region.Tr);
795
+ });
796
+
797
+ test("should handle API errors for state all", async () => {
798
+ jest.spyOn(client, 'getStateAll').mockRejectedValue(new Error("Failed to fetch states"));
799
+
800
+ await expect(client.getStateAll(0, 10, Region.Tr))
801
+ .rejects.toThrow("Failed to fetch states");
802
+ });
803
+ });
804
+
805
+ describe("getState", () => {
806
+ test("should return single market state with mock data", async () => {
807
+ jest.spyOn(client, 'getState').mockResolvedValue(mockSingleMarketState);
808
+
809
+ const resp = await client.getState("XIST");
810
+
811
+ expect(resp.id).toBe(1);
812
+ expect(resp.marketSymbol).toBe("XIST");
813
+ expect(resp.state).toBe("OPEN");
814
+ expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
815
+
816
+ expect(client.getState).toHaveBeenCalledWith("XIST");
817
+ });
818
+
819
+ test("should handle API errors for single state", async () => {
820
+ jest.spyOn(client, 'getState').mockRejectedValue(new Error("Market state not found"));
821
+
822
+ await expect(client.getState("INVALID"))
823
+ .rejects.toThrow("Market state not found");
824
+ });
825
+ });
96
826
  });
97
827
  });