laplace-api 4.7.0 → 5.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.
@@ -4,6 +4,7 @@ import {
4
4
  StockClient,
5
5
  HistoricalPricePeriod,
6
6
  HistoricalPriceInterval,
7
+ ChartImagePeriod,
7
8
  AssetClass,
8
9
  Stock,
9
10
  AssetType,
@@ -17,7 +18,7 @@ import "./client_test_suite";
17
18
  import { Region, Locale } from "../client/collections";
18
19
  import { PaginatedResponse } from "../client/capital_increase";
19
20
 
20
- const mockStocksResponse: Stock[] = [
21
+ const mockStocksResponse = [
21
22
  {
22
23
  id: "61dd0d6f0ec2114146342fd0",
23
24
  assetType: AssetType.Stock,
@@ -26,18 +27,6 @@ const mockStocksResponse: Stock[] = [
26
27
  sectorId: "sector123",
27
28
  industryId: "industry456",
28
29
  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
30
  active: true
42
31
  }
43
32
  ];
@@ -99,15 +88,6 @@ const mockStockRestrictionsResponse = [
99
88
  startDate: "2024-03-15T00:00:00Z",
100
89
  endDate: "2024-03-20T00:00:00Z",
101
90
  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
91
  }
112
92
  ];
113
93
 
@@ -180,8 +160,6 @@ const mockSingleMarketState: MarketState = {
180
160
  stockSymbol: "TUPRS"
181
161
  };
182
162
 
183
- const mockChartImageBlob = new Blob(['mock chart image data'], { type: 'image/png' });
184
-
185
163
  describe("Stocks Client", () => {
186
164
  let client: StockClient;
187
165
 
@@ -260,9 +238,13 @@ describe("Stocks Client", () => {
260
238
 
261
239
  expect(resp).toBeDefined();
262
240
  expect(resp.symbol).toBe("TUPRS");
241
+ expect(typeof resp.id).toBe("string");
263
242
  expect(typeof resp.assetClass).toBe("string");
264
243
  expect(typeof resp.description).toBe("string");
244
+ expect(typeof resp.shortDescription).toBe("string");
265
245
  expect(typeof resp.region).toBe("string");
246
+ expect(typeof resp.localized_description).toBe("object");
247
+ expect(typeof resp.localizedShortDescription).toBe("object");
266
248
  });
267
249
  });
268
250
 
@@ -329,6 +311,18 @@ describe("Stocks Client", () => {
329
311
  );
330
312
 
331
313
  expect(resp).not.toBeEmpty();
314
+ const firstDataPoint = resp[0];
315
+ expect(typeof firstDataPoint.d).toBe("number");
316
+ expect(typeof firstDataPoint.c).toBe("number");
317
+ expect(typeof firstDataPoint.h).toBe("number");
318
+ expect(typeof firstDataPoint.l).toBe("number");
319
+ expect(typeof firstDataPoint.o).toBe("number");
320
+ expect(typeof firstDataPoint.uc).toBe("number");
321
+ expect(typeof firstDataPoint.uh).toBe("number");
322
+ expect(typeof firstDataPoint.ul).toBe("number");
323
+ expect(typeof firstDataPoint.uo).toBe("number");
324
+ expect(typeof firstDataPoint.uv).toBe("number");
325
+ expect(typeof firstDataPoint.v).toBe("number");
332
326
  });
333
327
  });
334
328
 
@@ -356,7 +350,7 @@ describe("Stocks Client", () => {
356
350
 
357
351
  describe("getAllStockRestrictions", () => {
358
352
  test("should return all stock restrictions for region", async () => {
359
- const resp = await client.getAllStockRestrictions(Region.Tr);
353
+ const resp = await client.getAllStockRestrictions();
360
354
 
361
355
  expect(Array.isArray(resp)).toBe(true);
362
356
 
@@ -383,6 +377,13 @@ describe("Stocks Client", () => {
383
377
 
384
378
  if (resp.rules !== null) {
385
379
  expect(Array.isArray(resp.rules)).toBe(true);
380
+ if (resp.rules.length > 0) {
381
+ const firstRule = resp.rules[0]
382
+ expect(firstRule).toBeDefined();
383
+ expect(typeof firstRule.priceFrom).toBe("number");
384
+ expect(typeof firstRule.priceTo).toBe("number");
385
+ expect(typeof firstRule.tickSize).toBe("number");
386
+ }
386
387
  }
387
388
  });
388
389
  });
@@ -488,7 +489,6 @@ describe("Stocks Client", () => {
488
489
  }
489
490
  });
490
491
  });
491
-
492
492
  describe("getStockChartImage", () => {
493
493
  test("should return chart image blob", async () => {
494
494
  const resp = await client.getStockChartImage({
@@ -498,377 +498,313 @@ describe("Stocks Client", () => {
498
498
  expect(resp).toBeDefined();
499
499
  expect(resp).toBeInstanceOf(Blob);
500
500
  expect(resp.size).toBeGreaterThan(0);
501
- }, 10000);
501
+ }, 30000);
502
502
  });
503
503
  });
504
504
 
505
- describe("Mock Tests", () => {
505
+ describe("Mock Tests (Data Injection)", () => {
506
+ let client: StockClient;
507
+ let cli: { request: jest.Mock };
508
+
506
509
  beforeEach(() => {
507
- jest.clearAllMocks();
510
+ cli = { request: jest.fn() };
511
+
512
+ const config = (global as any).testSuite.config as LaplaceConfiguration;
513
+ const logger: Logger = {
514
+ info: jest.fn(),
515
+ error: jest.fn(),
516
+ warn: jest.fn(),
517
+ debug: jest.fn(),
518
+ } as unknown as Logger;
519
+
520
+ client = new StockClient(config, logger, cli as any);
508
521
  });
509
-
510
- describe("getAllStocks", () => {
511
- test("should handle getAllStocks response correctly with mock data", async () => {
512
- jest.spyOn(client, 'getAllStocks').mockResolvedValue(mockStocksResponse);
513
-
514
- const resp = await client.getAllStocks(Region.Tr);
515
-
516
- expect(resp).toHaveLength(2);
517
-
518
- const firstStock = resp[0];
519
- expect(firstStock.id).toBe("61dd0d6f0ec2114146342fd0");
520
- expect(firstStock.assetType).toBe(AssetType.Stock);
521
- expect(firstStock.name).toBe("Tüpraş");
522
- expect(firstStock.symbol).toBe("TUPRS");
523
- expect(firstStock.sectorId).toBe("sector123");
524
- expect(firstStock.industryId).toBe("industry456");
525
- expect(firstStock.updatedDate).toBe("2024-03-14T10:00:00Z");
526
- expect(firstStock.dailyChange).toBe(2.5);
527
- expect(firstStock.active).toBe(true);
528
-
529
- const secondStock = resp[1];
530
- expect(secondStock.id).toBe("61dd0d6f0ec2114146342fd1");
531
- expect(secondStock.symbol).toBe("GARAN");
532
- expect(secondStock.dailyChange).toBe(-1.2);
533
-
534
- expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr);
535
- });
536
-
537
- test("should handle pagination correctly with mock data", async () => {
538
- jest.spyOn(client, 'getAllStocks').mockResolvedValue([mockStocksResponse[0]]);
539
-
540
- const resp = await client.getAllStocks(Region.Tr, 1, 0);
541
-
542
- expect(resp).toHaveLength(1);
543
- expect(resp[0].symbol).toBe("TUPRS");
544
-
545
- expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr, 1, 0);
546
- });
547
-
548
- test("should handle API errors correctly", async () => {
549
- jest.spyOn(client, 'getAllStocks').mockRejectedValue(new Error("API Error"));
550
-
551
- await expect(client.getAllStocks(Region.Tr)).rejects.toThrow("API Error");
552
- });
522
+
523
+ test("getAllStocks: calls correct endpoint/params and matches raw response", async () => {
524
+ cli.request.mockResolvedValueOnce({ data: mockStocksResponse });
525
+
526
+ const resp = await client.getAllStocks(Region.Tr);
527
+
528
+ expect(cli.request).toHaveBeenCalledTimes(1);
529
+ const call = cli.request.mock.calls[0][0];
530
+
531
+ expect(call.method).toBe("GET");
532
+ expect(call.url).toBe("/api/v2/stock/all");
533
+ expect(call.params).toEqual({ region: Region.Tr });
534
+
535
+ // raw match
536
+ expect(resp).toEqual(mockStocksResponse);
553
537
  });
554
-
555
- describe("getStockDetailById", () => {
556
- test("should return stock detail by ID with mock data", async () => {
557
- jest.spyOn(client, 'getStockDetailById').mockResolvedValue(mockStockDetailResponse);
558
-
559
- const resp = await client.getStockDetailById("61dd0d6f0ec2114146342fd0", Locale.Tr);
560
-
561
- expect(resp).toBeDefined();
562
- expect(resp.id).toBe("61dd0d6f0ec2114146342fd0");
563
- expect(resp.assetType).toBe(AssetType.Stock);
564
- expect(resp.assetClass).toBe(AssetClass.Equity);
565
- expect(resp.description).toBe("Türkiye'nin en büyük rafineri şirketi");
566
- expect(resp.shortDescription).toBe("Rafineri şirketi");
567
- expect(resp.region).toBe(Region.Tr);
568
- expect(resp.localized_description).toEqual({
569
- tr: "Türkiye'nin en büyük rafineri şirketi",
570
- en: "Turkey's largest refinery company"
571
- });
572
- expect(resp.localizedShortDescription).toEqual({
573
- tr: "Rafineri şirketi",
574
- en: "Refinery company"
575
- });
576
- expect(resp.markets).toEqual([Market.Yildiz]);
577
-
578
- expect(client.getStockDetailById).toHaveBeenCalledWith("61dd0d6f0ec2114146342fd0", Locale.Tr);
579
- });
580
-
581
- test("should handle API errors for stock detail", async () => {
582
- jest.spyOn(client, 'getStockDetailById').mockRejectedValue(new Error("Stock not found"));
583
-
584
- await expect(client.getStockDetailById("invalid_id", Locale.Tr))
585
- .rejects.toThrow("Stock not found");
586
- });
538
+
539
+ test("getAllStocks: includes page/pageSize when provided (including 0)", async () => {
540
+ cli.request.mockResolvedValueOnce({ data: mockStocksResponse });
541
+
542
+ await client.getAllStocks(Region.Tr, 0, 0);
543
+
544
+ const call = cli.request.mock.calls[0][0];
545
+ expect(call.params).toEqual({ region: Region.Tr, page: 0, pageSize: 0 });
587
546
  });
588
-
589
- describe("getHistoricalPrices", () => {
590
- test("should return historical prices for multiple symbols with mock data", async () => {
591
- jest.spyOn(client, 'getHistoricalPrices').mockResolvedValue(mockHistoricalPricesResponse);
592
-
593
- const symbols = ["TUPRS"];
594
- const periods = [
595
- HistoricalPricePeriod.OneDay,
596
- HistoricalPricePeriod.OneWeek,
597
- HistoricalPricePeriod.OneMonth
598
- ];
599
-
600
- const resp = await client.getHistoricalPrices(symbols, Region.Tr, periods);
601
-
602
- expect(resp).toHaveLength(1);
603
-
604
- const firstPriceGraph = resp[0];
605
- expect(firstPriceGraph.symbol).toBe("TUPRS");
606
-
607
- expect(firstPriceGraph["1D"]).toHaveLength(2);
608
- const firstDayPoint = firstPriceGraph["1D"][0];
609
- expect(firstDayPoint.d).toBe(1710374400000);
610
- expect(firstDayPoint.c).toBe(425.5);
611
- expect(firstDayPoint.h).toBe(428.0);
612
- expect(firstDayPoint.l).toBe(422.0);
613
- expect(firstDayPoint.o).toBe(423.0);
614
- expect(firstPriceGraph["1W"]).toHaveLength(2);
615
- expect(firstPriceGraph["1M"]).toHaveLength(2);
616
-
617
- expect(client.getHistoricalPrices).toHaveBeenCalledWith(
618
- symbols,
619
- Region.Tr,
620
- periods
621
- );
622
- });
623
-
624
- test("should handle API errors for historical prices", async () => {
625
- jest.spyOn(client, 'getHistoricalPrices').mockRejectedValue(new Error("Failed to fetch historical prices"));
626
-
627
- await expect(client.getHistoricalPrices(
628
- ["TUPRS"],
629
- Region.Tr,
630
- [HistoricalPricePeriod.OneDay]
631
- )).rejects.toThrow("Failed to fetch historical prices");
632
- });
547
+
548
+ test("getStockDetailById: calls correct endpoint/params and matches raw response", async () => {
549
+ cli.request.mockResolvedValueOnce({ data: mockStockDetailResponse });
550
+
551
+ const resp = await client.getStockDetailById("61dd0d6f0ec2114146342fd0", Locale.Tr);
552
+
553
+ const call = cli.request.mock.calls[0][0];
554
+ expect(call.method).toBe("GET");
555
+ expect(call.url).toBe("/api/v1/stock/61dd0d6f0ec2114146342fd0");
556
+ expect(call.params).toEqual({ locale: Locale.Tr });
557
+
558
+ expect(resp).toEqual(mockStockDetailResponse);
633
559
  });
634
-
635
- describe("getStockRestrictions", () => {
636
- test("should return stock restrictions with mock data", async () => {
637
- jest.spyOn(client, 'getStockRestrictions').mockResolvedValue(mockStockRestrictionsResponse);
638
-
639
- const resp = await client.getStockRestrictions("TUPRS", Region.Tr);
640
-
641
- expect(resp).toHaveLength(2);
642
-
643
- const firstRestriction = resp[0];
644
- expect(firstRestriction.id).toBe(1);
645
- expect(firstRestriction.title).toBe("Bedelli Sermaye Artırımı");
646
- expect(firstRestriction.description).toBe("Şirket bedelli sermaye artırımı yapacaktır");
647
- expect(firstRestriction.symbol).toBe("TUPRS");
648
- expect(firstRestriction.startDate).toBe("2024-03-15T00:00:00Z");
649
- expect(firstRestriction.endDate).toBe("2024-03-20T00:00:00Z");
650
- expect(firstRestriction.market).toBe(Market.Yildiz);
651
-
652
- expect(client.getStockRestrictions).toHaveBeenCalledWith("TUPRS", Region.Tr);
653
- });
654
-
655
- test("should handle API errors for stock restrictions", async () => {
656
- jest.spyOn(client, 'getStockRestrictions').mockRejectedValue(new Error("Failed to fetch restrictions"));
657
-
658
- await expect(client.getStockRestrictions("TUPRS", Region.Tr))
659
- .rejects.toThrow("Failed to fetch restrictions");
660
- });
560
+
561
+ test("getStockDetailBySymbol: calls correct endpoint/params and matches raw response", async () => {
562
+ cli.request.mockResolvedValueOnce({ data: mockStockDetailResponse });
563
+
564
+ const resp = await client.getStockDetailBySymbol("TUPRS", AssetClass.Equity, Region.Tr, Locale.Tr);
565
+
566
+ const call = cli.request.mock.calls[0][0];
567
+ expect(call.method).toBe("GET");
568
+ expect(call.url).toBe("/api/v1/stock/detail");
569
+ expect(call.params).toEqual({
570
+ symbol: "TUPRS",
571
+ asset_class: AssetClass.Equity,
572
+ region: Region.Tr,
573
+ locale: Locale.Tr,
574
+ });
575
+
576
+ expect(resp).toEqual(mockStockDetailResponse);
661
577
  });
662
-
663
- describe("getTickRules", () => {
664
- test("should return tick rules with mock data", async () => {
665
- jest.spyOn(client, 'getTickRules').mockResolvedValue(mockTickRulesResponse);
666
-
667
- const resp = await client.getTickRules("TUPRS", Region.Tr);
668
-
669
- expect(resp.basePrice).toBe(425.5);
670
- expect(resp.additionalPrice).toBe(0.1);
671
- expect(resp.lowerPriceLimit).toBe(382.95);
672
- expect(resp.upperPriceLimit).toBe(468.05);
673
- expect(resp.rules).toHaveLength(3);
674
-
675
- const firstRule = resp.rules![0];
676
- expect(firstRule.priceFrom).toBe(0);
677
- expect(firstRule.priceTo).toBe(20);
678
- expect(firstRule.tickSize).toBe(0.01);
679
-
680
- expect(client.getTickRules).toHaveBeenCalledWith("TUPRS", Region.Tr);
681
- });
682
-
683
- test("should handle API errors for tick rules", async () => {
684
- jest.spyOn(client, 'getTickRules').mockRejectedValue(new Error("Failed to fetch tick rules"));
685
-
686
- await expect(client.getTickRules("TUPRS", Region.Tr))
687
- .rejects.toThrow("Failed to fetch tick rules");
688
- });
578
+
579
+ test("getHistoricalPrices: calls correct endpoint/params and matches raw response", async () => {
580
+ cli.request.mockResolvedValueOnce({ data: mockHistoricalPricesResponse });
581
+
582
+ const resp = await client.getHistoricalPrices(
583
+ ["TUPRS"],
584
+ Region.Tr,
585
+ [HistoricalPricePeriod.OneDay, HistoricalPricePeriod.OneWeek, HistoricalPricePeriod.OneMonth]
586
+ );
587
+
588
+ const call = cli.request.mock.calls[0][0];
589
+ expect(call.method).toBe("GET");
590
+ expect(call.url).toBe("/api/v1/stock/price");
591
+ expect(call.params).toEqual({
592
+ symbols: "TUPRS",
593
+ region: Region.Tr,
594
+ keys: "1D,1W,1M",
595
+ });
596
+
597
+ expect(resp).toEqual(mockHistoricalPricesResponse);
689
598
  });
690
-
691
- describe("getEarningsTranscripts", () => {
692
- test("should return earnings transcript list with mock data", async () => {
693
- jest.spyOn(client, 'getEarningsTranscripts').mockResolvedValue(mockEarningsTranscriptList);
694
-
695
- const resp = await client.getEarningsTranscripts("AAPL", Region.Us);
696
-
697
- expect(resp).toHaveLength(2);
698
-
699
- const firstTranscript = resp[0];
700
- expect(firstTranscript.symbol).toBe("AAPL");
701
- expect(firstTranscript.year).toBe(2024);
702
- expect(firstTranscript.quarter).toBe(1);
703
- expect(firstTranscript.date).toBe("2024-05-15");
704
- expect(firstTranscript.fiscal_year).toBe(2024);
705
-
706
- const secondTranscript = resp[1];
707
- expect(secondTranscript.year).toBe(2023);
708
- expect(secondTranscript.quarter).toBe(4);
709
-
710
- expect(client.getEarningsTranscripts).toHaveBeenCalledWith(
711
- "AAPL",
712
- Region.Us
713
- );
714
- });
715
-
716
- test("should handle API errors for earnings transcripts", async () => {
717
- jest.spyOn(client, 'getEarningsTranscripts').mockRejectedValue(new Error("Transcripts not found"));
718
-
719
- await expect(
720
- client.getEarningsTranscripts("INVALID", Region.Us)
721
- ).rejects.toThrow("Transcripts not found");
722
- });
599
+
600
+ test("getCustomHistoricalPrices: calls correct endpoint/params and matches raw response", async () => {
601
+ const mockCustom = [{ d: 1, o: 1, h: 1, l: 1, c: 1 }];
602
+ cli.request.mockResolvedValueOnce({ data: mockCustom });
603
+
604
+ const resp = await client.getCustomHistoricalPrices(
605
+ "TUPRS",
606
+ Region.Tr,
607
+ "2024-01-01",
608
+ "2024-03-01",
609
+ HistoricalPriceInterval.OneDay,
610
+ false,
611
+ 10
612
+ );
613
+
614
+ const call = cli.request.mock.calls[0][0];
615
+ expect(call.method).toBe("GET");
616
+ expect(call.url).toBe("/api/v1/stock/price/interval");
617
+ expect(call.params).toEqual({
618
+ stock: "TUPRS",
619
+ region: Region.Tr,
620
+ fromDate: "2024-01-01",
621
+ toDate: "2024-03-01",
622
+ interval: HistoricalPriceInterval.OneDay,
623
+ detail: false,
624
+ numIntervals: 10,
625
+ });
626
+
627
+ expect(resp).toEqual(mockCustom);
723
628
  });
724
-
725
- describe("getEarningsTranscript", () => {
726
- test("should return earnings transcript detail with mock data", async () => {
727
- jest.spyOn(client, 'getEarningsTranscript').mockResolvedValue(mockEarningsTranscriptDetail);
728
-
729
- const resp = await client.getEarningsTranscript("AAPL", 2024, 1);
730
-
731
- expect(resp.symbol).toBe("AAPL");
732
- expect(resp.year).toBe(2024);
733
- expect(resp.quarter).toBe(1);
734
- expect(resp.date).toBe("2024-05-15");
735
- expect(resp.content).toBe("Q1 2024 earnings call transcript content...");
736
- expect(resp.summary).toBe("Strong Q1 performance with 15% revenue growth");
737
- expect(resp.has_summary).toBe(true);
738
-
739
- expect(client.getEarningsTranscript).toHaveBeenCalledWith(
740
- "AAPL",
741
- 2024,
742
- 1
743
- );
744
- });
745
-
746
- test("should handle API errors for earnings transcript detail", async () => {
747
- jest.spyOn(client, 'getEarningsTranscript').mockRejectedValue(new Error("Transcript not found"));
748
-
749
- await expect(
750
- client.getEarningsTranscript("AAPL", 2020, 1)
751
- ).rejects.toThrow("Transcript not found");
752
- });
629
+
630
+ test("getStockRestrictions: calls correct endpoint/params and matches raw response", async () => {
631
+ cli.request.mockResolvedValueOnce({ data: mockStockRestrictionsResponse });
632
+
633
+ const resp = await client.getStockRestrictions("TUPRS", Region.Tr);
634
+
635
+ const call = cli.request.mock.calls[0][0];
636
+ expect(call.method).toBe("GET");
637
+ expect(call.url).toBe("/api/v1/stock/restrictions");
638
+ expect(call.params).toEqual({ symbol: "TUPRS", region: Region.Tr });
639
+
640
+ expect(resp).toEqual(mockStockRestrictionsResponse);
753
641
  });
754
-
755
- describe("getStockStateAll", () => {
756
- test("should return paginated stock states with mock data", async () => {
757
- jest.spyOn(client, 'getStockStateAll').mockResolvedValue(mockPaginatedMarketStates);
758
-
759
- const resp = await client.getStockStateAll(0, 10, Region.Tr);
760
-
761
- expect(resp.items).toHaveLength(2);
762
- expect(resp.recordCount).toBe(2);
763
-
764
- const firstState = resp.items[0];
765
- expect(firstState.id).toBe(1);
766
- expect(firstState.marketSymbol).toBe("BIST");
767
- expect(firstState.state).toBe("OPEN");
768
- expect(firstState.stockSymbol).toBe("TUPRS");
769
-
770
- expect(client.getStockStateAll).toHaveBeenCalledWith(0, 10, Region.Tr);
771
- });
772
-
773
- test("should handle API errors for stock state all", async () => {
774
- jest.spyOn(client, 'getStockStateAll').mockRejectedValue(new Error("Failed to fetch stock states"));
775
-
776
- await expect(client.getStockStateAll(0, 10, Region.Tr))
777
- .rejects.toThrow("Failed to fetch stock states");
778
- });
642
+
643
+ test("getAllStockRestrictions: calls correct endpoint and matches raw response", async () => {
644
+ cli.request.mockResolvedValueOnce({ data: mockStockRestrictionsResponse });
645
+
646
+ const resp = await client.getAllStockRestrictions();
647
+
648
+ const call = cli.request.mock.calls[0][0];
649
+ expect(call.method).toBe("GET");
650
+ expect(call.url).toBe("/api/v1/stock/restrictions/all");
651
+ expect(call.params).toBeUndefined();
652
+
653
+ expect(resp).toEqual(mockStockRestrictionsResponse);
654
+ });
655
+
656
+ test("getTickRules: calls correct endpoint/params and matches raw response", async () => {
657
+ cli.request.mockResolvedValueOnce({ data: mockTickRulesResponse });
658
+
659
+ const resp = await client.getTickRules("TUPRS", Region.Tr);
660
+
661
+ const call = cli.request.mock.calls[0][0];
662
+ expect(call.method).toBe("GET");
663
+ expect(call.url).toBe("/api/v1/stock/rules");
664
+ expect(call.params).toEqual({ symbol: "TUPRS", region: Region.Tr });
665
+
666
+ expect(resp).toEqual(mockTickRulesResponse);
667
+ });
668
+
669
+ test("getEarningsTranscripts: calls correct endpoint/params and matches raw response", async () => {
670
+ cli.request.mockResolvedValueOnce({ data: mockEarningsTranscriptList });
671
+
672
+ const resp = await client.getEarningsTranscripts("AAPL", Region.Us);
673
+
674
+ const call = cli.request.mock.calls[0][0];
675
+ expect(call.method).toBe("GET");
676
+ expect(call.url).toBe("/api/v1/earnings/transcripts");
677
+ expect(call.params).toEqual({ symbol: "AAPL", region: Region.Us });
678
+
679
+ expect(resp).toEqual(mockEarningsTranscriptList);
680
+ });
681
+
682
+ test("getEarningsTranscript: calls correct endpoint/params and matches raw response", async () => {
683
+ cli.request.mockResolvedValueOnce({ data: mockEarningsTranscriptDetail });
684
+
685
+ const resp = await client.getEarningsTranscript("AAPL", 2024, 1);
686
+
687
+ const call = cli.request.mock.calls[0][0];
688
+ expect(call.method).toBe("GET");
689
+ expect(call.url).toBe("/api/v1/earnings/transcript");
690
+ expect(call.params).toEqual({ symbol: "AAPL", year: 2024, quarter: 1 });
691
+
692
+ expect(resp).toEqual(mockEarningsTranscriptDetail);
693
+ });
694
+
695
+ test("getStockStateAll: calls correct endpoint/params and matches raw response", async () => {
696
+ cli.request.mockResolvedValueOnce({ data: mockPaginatedMarketStates });
697
+
698
+ const resp = await client.getStockStateAll(0, 10, Region.Tr);
699
+
700
+ const call = cli.request.mock.calls[0][0];
701
+ expect(call.method).toBe("GET");
702
+ expect(call.url).toBe("/api/v1/state/stock/all");
703
+ expect(call.params).toEqual({ page: 0, size: 10, region: Region.Tr });
704
+
705
+ expect(resp).toEqual(mockPaginatedMarketStates);
706
+ });
707
+
708
+ test("getStockState: calls correct endpoint and matches raw response", async () => {
709
+ cli.request.mockResolvedValueOnce({ data: mockSingleMarketState });
710
+
711
+ const resp = await client.getStockState("TUPRS");
712
+
713
+ const call = cli.request.mock.calls[0][0];
714
+ expect(call.method).toBe("GET");
715
+ expect(call.url).toBe("/api/v1/state/stock/TUPRS");
716
+ expect(call.params).toBeUndefined();
717
+
718
+ expect(resp).toEqual(mockSingleMarketState);
719
+ });
720
+
721
+ test("getStateAll: calls correct endpoint/params and matches raw response", async () => {
722
+ cli.request.mockResolvedValueOnce({ data: mockPaginatedMarketStates });
723
+
724
+ const resp = await client.getStateAll(0, 10, Region.Tr);
725
+
726
+ const call = cli.request.mock.calls[0][0];
727
+ expect(call.method).toBe("GET");
728
+ expect(call.url).toBe("/api/v1/state/all");
729
+ expect(call.params).toEqual({ page: 0, size: 10, region: Region.Tr });
730
+
731
+ expect(resp).toEqual(mockPaginatedMarketStates);
732
+ });
733
+
734
+ test("getState: calls correct endpoint and matches raw response", async () => {
735
+ cli.request.mockResolvedValueOnce({ data: mockSingleMarketState });
736
+
737
+ const resp = await client.getState("BIST");
738
+
739
+ const call = cli.request.mock.calls[0][0];
740
+ expect(call.method).toBe("GET");
741
+ expect(call.url).toBe("/api/v1/state/BIST");
742
+ expect(call.params).toBeUndefined();
743
+
744
+ expect(resp).toEqual(mockSingleMarketState);
745
+ });
746
+
747
+ test("bubbles up request error", async () => {
748
+ cli.request.mockRejectedValueOnce(new Error("API Error"));
749
+
750
+ await expect(client.getAllStocks(Region.Tr)).rejects.toThrow("API Error");
751
+ expect(cli.request).toHaveBeenCalledTimes(1);
779
752
  });
780
753
 
781
- describe("getStockState", () => {
782
- test("should return single stock state with mock data", async () => {
783
- jest.spyOn(client, 'getStockState').mockResolvedValue(mockSingleMarketState);
784
-
785
- const resp = await client.getStockState("TUPRS");
786
-
787
- expect(resp.id).toBe(1);
788
- expect(resp.marketSymbol).toBe("BIST");
789
- expect(resp.state).toBe("OPEN");
790
- expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
791
- expect(resp.stockSymbol).toBe("TUPRS");
792
-
793
- expect(client.getStockState).toHaveBeenCalledWith("TUPRS");
794
- });
795
-
796
- test("should handle API errors for single stock state", async () => {
797
- jest.spyOn(client, 'getStockState').mockRejectedValue(new Error("Stock state not found"));
754
+ test("getStockChartImage: calls correct endpoint/params and returns Blob", async () => {
755
+ const mockArrayBuffer = new ArrayBuffer(8);
756
+ cli.request.mockResolvedValueOnce({ data: mockArrayBuffer });
798
757
 
799
- await expect(client.getStockState("INVALID"))
800
- .rejects.toThrow("Stock state not found");
758
+ const resp = await client.getStockChartImage({
759
+ symbol: "TUPRS",
760
+ region: Region.Tr,
801
761
  });
802
- });
803
762
 
804
- describe("getStateAll", () => {
805
- test("should return paginated market states with mock data", async () => {
806
- jest.spyOn(client, 'getStateAll').mockResolvedValue(mockPaginatedMarketStates);
763
+ expect(cli.request).toHaveBeenCalledTimes(1);
764
+ const call = cli.request.mock.calls[0][0];
807
765
 
808
- const resp = await client.getStateAll(0, 10, Region.Tr);
766
+ expect(call.method).toBe("GET");
767
+ expect(call.url).toBe("/api/v1/stock/chart");
768
+ expect(call.params).toEqual({ symbol: "TUPRS", region: Region.Tr });
769
+ expect(call.responseType).toBe("arraybuffer");
809
770
 
810
- expect(resp.items).toHaveLength(2);
811
- expect(resp.recordCount).toBe(2);
771
+ expect(resp).toBeInstanceOf(Blob);
772
+ expect(resp.type).toBe("image/png");
773
+ });
812
774
 
813
- const firstState = resp.items[0];
814
- expect(firstState.state).toBe("OPEN");
815
- expect(firstState.lastTimestamp).toBe("2024-03-14T10:00:00Z");
775
+ test("getStockChartImage: includes optional params when provided", async () => {
776
+ const mockArrayBuffer = new ArrayBuffer(8);
777
+ cli.request.mockResolvedValueOnce({ data: mockArrayBuffer });
816
778
 
817
- expect(client.getStateAll).toHaveBeenCalledWith(0, 10, Region.Tr);
779
+ await client.getStockChartImage({
780
+ symbol: "TUPRS",
781
+ region: Region.Tr,
782
+ period: ChartImagePeriod.OneMonth,
783
+ resolution: HistoricalPriceInterval.OneDay,
784
+ indicators: ["RSI", "MACD"],
785
+ chartType: 1,
818
786
  });
819
787
 
820
- test("should handle API errors for state all", async () => {
821
- jest.spyOn(client, 'getStateAll').mockRejectedValue(new Error("Failed to fetch states"));
822
-
823
- await expect(client.getStateAll(0, 10, Region.Tr))
824
- .rejects.toThrow("Failed to fetch states");
788
+ const call = cli.request.mock.calls[0][0];
789
+ expect(call.params).toEqual({
790
+ symbol: "TUPRS",
791
+ region: Region.Tr,
792
+ period: ChartImagePeriod.OneMonth,
793
+ resolution: HistoricalPriceInterval.OneDay,
794
+ indicators: ["RSI", "MACD"],
795
+ chartType: 1,
825
796
  });
826
797
  });
827
798
 
828
- describe("getState", () => {
829
- test("should return single market state with mock data", async () => {
830
- jest.spyOn(client, 'getState').mockResolvedValue(mockSingleMarketState);
831
-
832
- const resp = await client.getState("BIST");
833
-
834
- expect(resp.id).toBe(1);
835
- expect(resp.marketSymbol).toBe("BIST");
836
- expect(resp.state).toBe("OPEN");
837
- expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z");
838
-
839
- expect(client.getState).toHaveBeenCalledWith("BIST");
840
- });
799
+ test("getStockChartImage: bubbles up request error", async () => {
800
+ cli.request.mockRejectedValueOnce(new Error("Failed to generate chart"));
841
801
 
842
- test("should handle API errors for single state", async () => {
843
- jest.spyOn(client, 'getState').mockRejectedValue(new Error("Market state not found"));
802
+ await expect(client.getStockChartImage({
803
+ symbol: "INVALID",
804
+ region: Region.Tr,
805
+ })).rejects.toThrow("Failed to generate chart");
844
806
 
845
- await expect(client.getState("INVALID"))
846
- .rejects.toThrow("Market state not found");
847
- });
848
- });
849
-
850
- describe("getStockChartImage", () => {
851
- test("should return chart image with mock data", async () => {
852
- jest.spyOn(client, 'getStockChartImage').mockResolvedValue(mockChartImageBlob);
853
-
854
- const resp = await client.getStockChartImage({
855
- symbol: "TUPRS",
856
- region: Region.Tr,
857
- });
858
-
859
- expect(resp).toBeDefined();
860
- expect(resp).toBeInstanceOf(Blob);
861
- expect(resp.type).toBe('image/png');
862
- });
863
-
864
- test("should handle API errors for chart image", async () => {
865
- jest.spyOn(client, 'getStockChartImage').mockRejectedValue(new Error("Failed to generate chart"));
866
-
867
- await expect(client.getStockChartImage({
868
- symbol: "INVALID",
869
- region: Region.Tr
870
- })).rejects.toThrow("Failed to generate chart");
871
- });
807
+ expect(cli.request).toHaveBeenCalledTimes(1);
872
808
  });
873
- });
809
+ });
874
810
  });