laplace-api 4.8.0 → 5.2.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.
- package/package.json +1 -1
- package/src/client/broker.ts +17 -17
- package/src/client/capital_increase.ts +9 -10
- package/src/client/client.ts +40 -40
- package/src/client/collections.ts +26 -14
- package/src/client/custom_theme.ts +15 -14
- package/src/client/financial_fundamentals.ts +29 -27
- package/src/client/financial_ratios.ts +29 -47
- package/src/client/funds.ts +10 -5
- package/src/client/key-insights.ts +1 -1
- package/src/client/live-price-web-socket.ts +3 -1
- package/src/client/live-price.ts +18 -44
- package/src/client/news.ts +106 -107
- package/src/client/search.ts +13 -9
- package/src/client/stocks.ts +42 -12
- package/src/test/broker.test.ts +580 -453
- package/src/test/capital_increase.test.ts +131 -82
- package/src/test/collections.test.ts +489 -268
- package/src/test/custom_theme.test.ts +250 -144
- package/src/test/financial_fundamentals.test.ts +171 -202
- package/src/test/financial_ratios.test.ts +222 -170
- package/src/test/funds.test.ts +231 -162
- package/src/test/helpers.ts +23 -27
- package/src/test/key-insight.test.ts +71 -36
- package/src/test/live-price.test.ts +135 -1
- package/src/test/news.test.ts +399 -169
- package/src/test/politician.test.ts +176 -187
- package/src/test/readme.test.ts +12 -13
- package/src/test/search.test.ts +144 -170
- package/src/test/stocks.test.ts +306 -370
- package/src/utilities/test.env +0 -2
package/src/test/stocks.test.ts
CHANGED
|
@@ -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
|
|
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(
|
|
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
|
-
},
|
|
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.
|
|
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
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
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
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
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
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
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
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
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
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
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
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
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
|
-
|
|
782
|
-
|
|
783
|
-
|
|
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
|
-
|
|
800
|
-
|
|
758
|
+
const resp = await client.getStockChartImage({
|
|
759
|
+
symbol: "TUPRS",
|
|
760
|
+
region: Region.Tr,
|
|
801
761
|
});
|
|
802
|
-
});
|
|
803
762
|
|
|
804
|
-
|
|
805
|
-
|
|
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
|
-
|
|
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
|
-
|
|
811
|
-
|
|
771
|
+
expect(resp).toBeInstanceOf(Blob);
|
|
772
|
+
expect(resp.type).toBe("image/png");
|
|
773
|
+
});
|
|
812
774
|
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
775
|
+
test("getStockChartImage: includes optional params when provided", async () => {
|
|
776
|
+
const mockArrayBuffer = new ArrayBuffer(8);
|
|
777
|
+
cli.request.mockResolvedValueOnce({ data: mockArrayBuffer });
|
|
816
778
|
|
|
817
|
-
|
|
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
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
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
|
-
|
|
829
|
-
|
|
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
|
-
|
|
843
|
-
|
|
802
|
+
await expect(client.getStockChartImage({
|
|
803
|
+
symbol: "INVALID",
|
|
804
|
+
region: Region.Tr,
|
|
805
|
+
})).rejects.toThrow("Failed to generate chart");
|
|
844
806
|
|
|
845
|
-
|
|
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
|
});
|