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,13 +1,148 @@
1
- import { Logger } from 'winston';
2
- import { LaplaceConfiguration } from '../utilities/configuration';
3
- import { CollectionClient, Region, Locale } from '../client/collections';
4
- import './client_test_suite';
1
+ import { Logger } from "winston";
2
+ import { LaplaceConfiguration } from "../utilities/configuration";
3
+ import { CollectionClient, Locale, Region, Collection, CollectionDetail, CollectionType, CollectionPriceGraph } from "../client/collections";
4
+ import "./client_test_suite";
5
+ import { validateCollection, validateCollectionDetail } from "./helpers";
6
+ import { Stock, AssetType, PriceDataPoint, HistoricalPricePeriod } from "../client/stocks";
5
7
 
6
- describe('Collections', () => {
8
+ const mockStocks: Stock[] = [
9
+ {
10
+ id: "stock1",
11
+ name: "Tüpraş",
12
+ symbol: "TUPRS",
13
+ assetType: AssetType.Stock,
14
+ sectorId: "sector1",
15
+ industryId: "industry1",
16
+ updatedDate: "2024-03-14T10:00:00Z",
17
+ active: true
18
+ },
19
+ {
20
+ id: "stock2",
21
+ name: "Garanti Bankası",
22
+ symbol: "GARAN",
23
+ assetType: AssetType.Stock,
24
+ sectorId: "sector2",
25
+ industryId: "industry2",
26
+ updatedDate: "2024-03-14T10:00:00Z",
27
+ active: true
28
+ }
29
+ ];
30
+
31
+ const mockIndustries: Collection[] = [
32
+ {
33
+ id: "industry1",
34
+ title: "Bankacılık",
35
+ description: "Türkiye'nin önde gelen bankaları",
36
+ region: [Region.Tr],
37
+ assetClass: "equity",
38
+ imageUrl: "https://example.com/banking.jpg",
39
+ avatarUrl: "https://example.com/banking-avatar.jpg",
40
+ numStocks: 10
41
+ },
42
+ {
43
+ id: "industry2",
44
+ title: "Enerji",
45
+ description: "Enerji sektörü şirketleri",
46
+ region: [Region.Tr],
47
+ assetClass: "equity",
48
+ imageUrl: "https://example.com/energy.jpg",
49
+ avatarUrl: "https://example.com/energy-avatar.jpg",
50
+ numStocks: 8
51
+ }
52
+ ];
53
+
54
+ const mockSectors: Collection[] = [
55
+ {
56
+ id: "sector1",
57
+ title: "Finans",
58
+ description: "Finans sektörü şirketleri",
59
+ region: [Region.Tr],
60
+ assetClass: "equity",
61
+ imageUrl: "https://example.com/finance.jpg",
62
+ avatarUrl: "https://example.com/finance-avatar.jpg",
63
+ numStocks: 25
64
+ }
65
+ ];
66
+
67
+ const mockThemes: Collection[] = [
68
+ {
69
+ id: "theme1",
70
+ title: "Sürdürülebilir Enerji",
71
+ description: "Yenilenebilir enerji şirketleri",
72
+ region: [Region.Tr],
73
+ assetClass: "equity",
74
+ imageUrl: "https://example.com/sustainable.jpg",
75
+ avatarUrl: "https://example.com/sustainable-avatar.jpg",
76
+ numStocks: 15
77
+ }
78
+ ];
79
+
80
+ const mockCollections: Collection[] = [
81
+ {
82
+ id: "collection1",
83
+ title: "Borsa İstanbul 30",
84
+ description: "BIST-30 endeksindeki şirketler",
85
+ region: [Region.Tr],
86
+ assetClass: "equity",
87
+ imageUrl: "https://example.com/bist30.jpg",
88
+ avatarUrl: "https://example.com/bist30-avatar.jpg",
89
+ numStocks: 30
90
+ }
91
+ ];
92
+
93
+ const mockPriceDataPoints: PriceDataPoint[] = [
94
+ {
95
+ d: 1710403200000,
96
+ o: 100.5,
97
+ h: 105.2,
98
+ l: 99.8,
99
+ c: 103.7
100
+ },
101
+ {
102
+ d: 1710489600000,
103
+ o: 103.7,
104
+ h: 107.1,
105
+ l: 102.3,
106
+ c: 106.4
107
+ },
108
+ {
109
+ d: 1710576000000,
110
+ o: 106.4,
111
+ h: 108.9,
112
+ l: 105.1,
113
+ c: 107.8
114
+ }
115
+ ];
116
+
117
+ const mockCollectionPriceGraph: CollectionPriceGraph = {
118
+ previous_close: 98.5,
119
+ graph: mockPriceDataPoints
120
+ };
121
+
122
+ const mockIndustryDetail: CollectionDetail = {
123
+ ...mockIndustries[0],
124
+ stocks: mockStocks
125
+ };
126
+
127
+ const mockSectorDetail: CollectionDetail = {
128
+ ...mockSectors[0],
129
+ stocks: mockStocks
130
+ };
131
+
132
+ const mockThemeDetail: CollectionDetail = {
133
+ ...mockThemes[0],
134
+ stocks: mockStocks
135
+ };
136
+
137
+ const mockCollectionDetail: CollectionDetail = {
138
+ ...mockCollections[0],
139
+ stocks: mockStocks
140
+ };
141
+
142
+ describe("Collections", () => {
7
143
  let client: CollectionClient;
8
144
 
9
145
  beforeAll(() => {
10
- // Assuming global.testSuite is set up as in the previous example
11
146
  const config = (global as any).testSuite.config as LaplaceConfiguration;
12
147
  const logger: Logger = {
13
148
  info: jest.fn(),
@@ -19,18 +154,326 @@ describe('Collections', () => {
19
154
  client = new CollectionClient(config, logger);
20
155
  });
21
156
 
22
- test('GetAllIndustries', async () => {
23
- const resp = await client.getAllIndustries(Region.Tr, Locale.Tr);
24
- expect(resp).not.toBeEmpty();
25
- });
157
+ describe("Integration Tests", () => {
158
+ test("GetAllIndustries", async () => {
159
+ const resp = await client.getAllIndustries(Region.Tr, Locale.Tr);
160
+ expect(resp).not.toBeEmpty();
161
+
162
+ const firstIndustry = resp[0];
163
+ validateCollection(firstIndustry);
164
+ });
165
+
166
+ test("GetAllSectors", async () => {
167
+ const resp = await client.getAllSectors(Region.Tr, Locale.Tr);
168
+ expect(resp).not.toBeEmpty();
169
+
170
+ const firstSector = resp[0];
171
+ validateCollection(firstSector);
172
+ });
173
+
174
+ test("GetIndustryDetails", async () => {
175
+ const resp = await client.getIndustryDetail(
176
+ "65533e441fa5c7b58afa0944",
177
+ Region.Tr,
178
+ Locale.Tr
179
+ );
180
+ expect(resp).not.toBeEmpty();
181
+ validateCollectionDetail(resp);
182
+ });
183
+
184
+ test("GetSectorDetails", async () => {
185
+ const resp = await client.getSectorDetail(
186
+ "65533e047844ee7afe9941b9",
187
+ Region.Tr,
188
+ Locale.Tr
189
+ );
190
+ expect(resp).not.toBeEmpty();
191
+ validateCollectionDetail(resp);
192
+ });
193
+
194
+ test("GetAllThemes", async () => {
195
+ const resp = await client.getAllThemes(Region.Tr, Locale.Tr);
196
+ expect(resp).not.toBeEmpty();
197
+
198
+ const firstTheme = resp[0];
199
+ validateCollection(firstTheme);
200
+ });
201
+
202
+ test("GetThemeDetails", async () => {
203
+ const resp = await client.getThemeDetail(
204
+ "6256b0647d0bb100123effa7",
205
+ Region.Tr,
206
+ Locale.Tr
207
+ );
208
+ expect(resp).not.toBeEmpty();
209
+ validateCollectionDetail(resp);
210
+ });
211
+
212
+ test("GetAllCollections", async () => {
213
+ const resp = await client.getAllCollections(Region.Tr, Locale.Tr);
214
+ expect(resp).not.toBeEmpty();
26
215
 
27
- test('GetIndustryDetails', async () => {
28
- const resp = await client.getIndustryDetail("65533e441fa5c7b58afa0944", Region.Tr, Locale.Tr);
29
- expect(resp).not.toBeEmpty();
216
+ const firstCollection = resp[0];
217
+ validateCollection(firstCollection);
218
+ });
219
+
220
+ test("GetCollectionDetails", async () => {
221
+ const resp = await client.getThemeDetail(
222
+ "620f455a0187ade00bb0d55f",
223
+ Region.Tr,
224
+ Locale.Tr
225
+ );
226
+ expect(resp).not.toBeEmpty();
227
+ validateCollectionDetail(resp);
228
+ });
229
+
230
+ test("GetAggregateGraph", async () => {
231
+ const resp = await client.getAggregateGraph(
232
+ HistoricalPricePeriod.OneYear,
233
+ "65533e047844ee7afe9941b9",
234
+ "65533e441fa5c7b58afa0944",
235
+ "",
236
+ Region.Tr
237
+ );
238
+
239
+ expect(resp).not.toBeNull();
240
+ expect(resp.previous_close).toBeDefined();
241
+ expect(resp.graph).toBeDefined();
242
+ expect(resp.graph).toBeInstanceOf(Array);
243
+
244
+ if (resp.graph.length > 0) {
245
+ const firstDataPoint = resp.graph[0];
246
+ expect(firstDataPoint.d).toBeDefined();
247
+ expect(firstDataPoint.o).toBeDefined();
248
+ expect(firstDataPoint.h).toBeDefined();
249
+ expect(firstDataPoint.l).toBeDefined();
250
+ expect(firstDataPoint.c).toBeDefined();
251
+ expect(typeof firstDataPoint.d).toBe('number');
252
+ expect(typeof firstDataPoint.o).toBe('number');
253
+ expect(typeof firstDataPoint.h).toBe('number');
254
+ expect(typeof firstDataPoint.l).toBe('number');
255
+ expect(typeof firstDataPoint.c).toBe('number');
256
+ }
257
+ });
30
258
  });
31
259
 
32
- test('GetSectorDetails', async () => {
33
- const resp = await client.getSectorDetail("65533e047844ee7afe9941b9", Region.Tr, Locale.Tr);
34
- expect(resp).not.toBeEmpty();
260
+ describe("Mock Tests", () => {
261
+ beforeEach(() => {
262
+ jest.clearAllMocks();
263
+ });
264
+
265
+ describe("Industries", () => {
266
+ test("should get all industries", async () => {
267
+ jest.spyOn(client, 'getAllIndustries').mockResolvedValue(mockIndustries);
268
+
269
+ const resp = await client.getAllIndustries(Region.Tr, Locale.Tr);
270
+
271
+ expect(resp).toHaveLength(2);
272
+ expect(resp[0].title).toBe("Bankacılık");
273
+ expect(resp[1].title).toBe("Enerji");
274
+ expect(resp[0].numStocks).toBe(10);
275
+ expect(resp[1].numStocks).toBe(8);
276
+
277
+ expect(client.getAllIndustries).toHaveBeenCalledWith(Region.Tr, Locale.Tr);
278
+ });
279
+
280
+ test("should get industry details", async () => {
281
+ jest.spyOn(client, 'getIndustryDetail').mockResolvedValue(mockIndustryDetail);
282
+
283
+ const resp = await client.getIndustryDetail("industry1", Region.Tr, Locale.Tr);
284
+
285
+ expect(resp.id).toBe("industry1");
286
+ expect(resp.title).toBe("Bankacılık");
287
+ expect(resp.stocks).toHaveLength(2);
288
+ expect(resp.stocks[0].symbol).toBe("TUPRS");
289
+ expect(resp.stocks[1].symbol).toBe("GARAN");
290
+
291
+ expect(client.getIndustryDetail).toHaveBeenCalledWith("industry1", Region.Tr, Locale.Tr);
292
+ });
293
+ });
294
+
295
+ describe("Sectors", () => {
296
+ test("should get all sectors", async () => {
297
+ jest.spyOn(client, 'getAllSectors').mockResolvedValue(mockSectors);
298
+
299
+ const resp = await client.getAllSectors(Region.Tr, Locale.Tr);
300
+
301
+ expect(resp).toHaveLength(1);
302
+ expect(resp[0].title).toBe("Finans");
303
+ expect(resp[0].numStocks).toBe(25);
304
+
305
+ expect(client.getAllSectors).toHaveBeenCalledWith(Region.Tr, Locale.Tr);
306
+ });
307
+
308
+ test("should get sector details", async () => {
309
+ jest.spyOn(client, 'getSectorDetail').mockResolvedValue(mockSectorDetail);
310
+
311
+ const resp = await client.getSectorDetail("sector1", Region.Tr, Locale.Tr);
312
+
313
+ expect(resp.id).toBe("sector1");
314
+ expect(resp.title).toBe("Finans");
315
+ expect(resp.stocks).toHaveLength(2);
316
+ expect(resp.stocks[0].symbol).toBe("TUPRS");
317
+ expect(resp.stocks[1].symbol).toBe("GARAN");
318
+
319
+ expect(client.getSectorDetail).toHaveBeenCalledWith("sector1", Region.Tr, Locale.Tr);
320
+ });
321
+ });
322
+
323
+ describe("Themes", () => {
324
+ test("should get all themes", async () => {
325
+ jest.spyOn(client, 'getAllThemes').mockResolvedValue(mockThemes);
326
+
327
+ const resp = await client.getAllThemes(Region.Tr, Locale.Tr);
328
+
329
+ expect(resp).toHaveLength(1);
330
+ expect(resp[0].title).toBe("Sürdürülebilir Enerji");
331
+ expect(resp[0].numStocks).toBe(15);
332
+
333
+ expect(client.getAllThemes).toHaveBeenCalledWith(Region.Tr, Locale.Tr);
334
+ });
335
+
336
+ test("should get theme details", async () => {
337
+ jest.spyOn(client, 'getThemeDetail').mockResolvedValue(mockThemeDetail);
338
+
339
+ const resp = await client.getThemeDetail("theme1", Region.Tr, Locale.Tr);
340
+
341
+ expect(resp.id).toBe("theme1");
342
+ expect(resp.title).toBe("Sürdürülebilir Enerji");
343
+ expect(resp.stocks).toHaveLength(2);
344
+ expect(resp.stocks[0].symbol).toBe("TUPRS");
345
+ expect(resp.stocks[1].symbol).toBe("GARAN");
346
+
347
+ expect(client.getThemeDetail).toHaveBeenCalledWith("theme1", Region.Tr, Locale.Tr);
348
+ });
349
+ });
350
+
351
+ describe("Collections", () => {
352
+ test("should get all collections", async () => {
353
+ jest.spyOn(client, 'getAllCollections').mockResolvedValue(mockCollections);
354
+
355
+ const resp = await client.getAllCollections(Region.Tr, Locale.Tr);
356
+
357
+ expect(resp).toHaveLength(1);
358
+ expect(resp[0].title).toBe("Borsa İstanbul 30");
359
+ expect(resp[0].numStocks).toBe(30);
360
+
361
+ expect(client.getAllCollections).toHaveBeenCalledWith(Region.Tr, Locale.Tr);
362
+ });
363
+
364
+ test("should get collection details", async () => {
365
+ jest.spyOn(client, 'getCollectionDetail').mockResolvedValue(mockCollectionDetail);
366
+
367
+ const resp = await client.getCollectionDetail("collection1", Region.Tr, Locale.Tr);
368
+
369
+ expect(resp.id).toBe("collection1");
370
+ expect(resp.title).toBe("Borsa İstanbul 30");
371
+ expect(resp.stocks).toHaveLength(2);
372
+ expect(resp.stocks[0].symbol).toBe("TUPRS");
373
+ expect(resp.stocks[1].symbol).toBe("GARAN");
374
+
375
+ expect(client.getCollectionDetail).toHaveBeenCalledWith("collection1", Region.Tr, Locale.Tr);
376
+ });
377
+ });
378
+
379
+ describe("Aggregate Graph", () => {
380
+ test("should get aggregate graph for sector", async () => {
381
+ jest.spyOn(client, 'getAggregateGraph').mockResolvedValue(mockCollectionPriceGraph);
382
+
383
+ const resp = await client.getAggregateGraph(HistoricalPricePeriod.OneMonth, "sector1", "", "", Region.Tr);
384
+
385
+ expect(resp.previous_close).toBe(98.5);
386
+ expect(resp.graph).toHaveLength(3);
387
+ expect(resp.graph[0].o).toBe(100.5);
388
+ expect(resp.graph[0].h).toBe(105.2);
389
+ expect(resp.graph[0].l).toBe(99.8);
390
+ expect(resp.graph[0].c).toBe(103.7);
391
+ expect(resp.graph[2].c).toBe(107.8);
392
+
393
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.OneMonth, "sector1", "", "", Region.Tr);
394
+ });
395
+
396
+ test("should get aggregate graph for industry", async () => {
397
+ jest.spyOn(client, 'getAggregateGraph').mockResolvedValue(mockCollectionPriceGraph);
398
+
399
+ const resp = await client.getAggregateGraph(HistoricalPricePeriod.ThreeMonth, "", "industry1", "", Region.Tr);
400
+
401
+ expect(resp.previous_close).toBe(98.5);
402
+ expect(resp.graph).toHaveLength(3);
403
+ expect(resp.graph[1].o).toBe(103.7);
404
+ expect(resp.graph[1].h).toBe(107.1);
405
+ expect(resp.graph[1].l).toBe(102.3);
406
+ expect(resp.graph[1].c).toBe(106.4);
407
+
408
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.ThreeMonth, "", "industry1", "", Region.Tr);
409
+ });
410
+
411
+ test("should get aggregate graph for collection", async () => {
412
+ jest.spyOn(client, 'getAggregateGraph').mockResolvedValue(mockCollectionPriceGraph);
413
+
414
+ const resp = await client.getAggregateGraph(HistoricalPricePeriod.OneWeek, "", "", "collection1", Region.Tr);
415
+
416
+ expect(resp.previous_close).toBe(98.5);
417
+ expect(resp.graph).toHaveLength(3);
418
+ expect(resp.graph[0].d).toBe(1710403200000);
419
+ expect(resp.graph[1].d).toBe(1710489600000);
420
+ expect(resp.graph[2].d).toBe(1710576000000);
421
+
422
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.OneWeek, "", "", "collection1", Region.Tr);
423
+ });
424
+
425
+ test("should get aggregate graph for different periods", async () => {
426
+ jest.spyOn(client, 'getAggregateGraph').mockResolvedValue(mockCollectionPriceGraph);
427
+
428
+ const resp1D = await client.getAggregateGraph(HistoricalPricePeriod.OneDay, "sector1", "", "", Region.Tr);
429
+ expect(resp1D.previous_close).toBe(98.5);
430
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.OneDay, "sector1", "", "", Region.Tr);
431
+
432
+ const resp1Y = await client.getAggregateGraph(HistoricalPricePeriod.OneYear, "", "industry1", "", Region.Tr);
433
+ expect(resp1Y.previous_close).toBe(98.5);
434
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.OneYear, "", "industry1", "", Region.Tr);
435
+
436
+ const resp5Y = await client.getAggregateGraph(HistoricalPricePeriod.FiveYear, "", "", "collection1", Region.Tr);
437
+ expect(resp5Y.previous_close).toBe(98.5);
438
+ expect(client.getAggregateGraph).toHaveBeenCalledWith(HistoricalPricePeriod.FiveYear, "", "", "collection1", Region.Tr);
439
+ });
440
+ });
441
+
442
+ describe("Error Handling", () => {
443
+ test("should handle invalid industry ID", async () => {
444
+ jest.spyOn(client, 'getIndustryDetail').mockRejectedValue(new Error("Industry not found"));
445
+
446
+ await expect(client.getIndustryDetail("invalid-id", Region.Tr, Locale.Tr))
447
+ .rejects.toThrow("Industry not found");
448
+ });
449
+
450
+ test("should handle invalid sector ID", async () => {
451
+ jest.spyOn(client, 'getSectorDetail').mockRejectedValue(new Error("Sector not found"));
452
+
453
+ await expect(client.getSectorDetail("invalid-id", Region.Tr, Locale.Tr))
454
+ .rejects.toThrow("Sector not found");
455
+ });
456
+
457
+ test("should handle invalid theme ID", async () => {
458
+ jest.spyOn(client, 'getThemeDetail').mockRejectedValue(new Error("Theme not found"));
459
+
460
+ await expect(client.getThemeDetail("invalid-id", Region.Tr, Locale.Tr))
461
+ .rejects.toThrow("Theme not found");
462
+ });
463
+
464
+ test("should handle invalid collection ID", async () => {
465
+ jest.spyOn(client, 'getCollectionDetail').mockRejectedValue(new Error("Collection not found"));
466
+
467
+ await expect(client.getCollectionDetail("invalid-id", Region.Tr, Locale.Tr))
468
+ .rejects.toThrow("Collection not found");
469
+ });
470
+
471
+ test("should handle invalid aggregate graph request", async () => {
472
+ jest.spyOn(client, 'getAggregateGraph').mockRejectedValue(new Error("Invalid parameters"));
473
+
474
+ await expect(client.getAggregateGraph("invalid-period" as HistoricalPricePeriod, "invalid-sector", "", "", Region.Tr))
475
+ .rejects.toThrow("Invalid parameters");
476
+ });
477
+ });
35
478
  });
36
- });
479
+ });