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/funds.test.ts
CHANGED
|
@@ -5,87 +5,73 @@ import {
|
|
|
5
5
|
FundsClient,
|
|
6
6
|
FundType,
|
|
7
7
|
HistoricalFundPricePeriod,
|
|
8
|
-
Fund,
|
|
9
|
-
FundStats,
|
|
10
|
-
FundDistribution,
|
|
11
|
-
FundAssetCategory,
|
|
12
|
-
FundHistoricalPrice,
|
|
13
|
-
FundContentType
|
|
14
8
|
} from "../client/funds";
|
|
15
9
|
import { Region } from "../client/collections";
|
|
16
|
-
import { AssetType } from "../client/stocks";
|
|
17
10
|
|
|
18
|
-
const mockFundsResponse
|
|
11
|
+
const mockFundsResponse= [
|
|
19
12
|
{
|
|
20
|
-
assetType:
|
|
21
|
-
name: "
|
|
22
|
-
symbol: "
|
|
23
|
-
active: true,
|
|
24
|
-
managementFee:
|
|
25
|
-
riskLevel:
|
|
26
|
-
fundType:
|
|
27
|
-
ownerSymbol: "
|
|
28
|
-
},
|
|
29
|
-
{
|
|
30
|
-
assetType: AssetType.Stock,
|
|
31
|
-
name: "İş Portföy BIST 30 Endeksi Hisse Senedi Fonu",
|
|
32
|
-
symbol: "TI3",
|
|
33
|
-
active: true,
|
|
34
|
-
managementFee: 0.0035,
|
|
35
|
-
riskLevel: 6,
|
|
36
|
-
fundType: FundType.STOCK_UMBRELLA_FUND,
|
|
37
|
-
ownerSymbol: "IYP"
|
|
13
|
+
"assetType": "fund",
|
|
14
|
+
"name": "NEO PORTFÖY KATILIM HİSSE SENEDİ FONU (HİSSE SENEDİ YOĞUN FON)",
|
|
15
|
+
"symbol": "NKM",
|
|
16
|
+
"active": true,
|
|
17
|
+
"managementFee": 2.8,
|
|
18
|
+
"riskLevel": 0,
|
|
19
|
+
"fundType": "STOCK_UMBRELLA_FUND",
|
|
20
|
+
"ownerSymbol": "VVP"
|
|
38
21
|
}
|
|
39
22
|
];
|
|
40
23
|
|
|
41
|
-
const mockFundStatsResponse
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
yearlyReturn:
|
|
47
|
-
|
|
48
|
-
fiveYearReturn:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
24
|
+
const mockFundStatsResponse = {
|
|
25
|
+
"monthlyReturn": -2.3367,
|
|
26
|
+
"threeMonthReturn": 3.8059,
|
|
27
|
+
"sixMonthReturn": 12.3031,
|
|
28
|
+
"ytdReturn": -0.8037,
|
|
29
|
+
"yearlyReturn": 31.9956,
|
|
30
|
+
"threeYearReturn": 281.8466,
|
|
31
|
+
"fiveYearReturn": 867.6593,
|
|
32
|
+
"yearMomentum": 0,
|
|
33
|
+
"yearBeta": 0.000068,
|
|
34
|
+
"yearStdev": 0.077
|
|
52
35
|
};
|
|
53
36
|
|
|
54
|
-
const mockFundDistributionResponse
|
|
55
|
-
categories: [
|
|
37
|
+
const mockFundDistributionResponse = {
|
|
38
|
+
"categories": [
|
|
56
39
|
{
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
40
|
+
"assets": [
|
|
41
|
+
{
|
|
42
|
+
"type": "BIST_STOCK",
|
|
43
|
+
"symbol": "ASELS",
|
|
44
|
+
"wholePercentage": 30,
|
|
45
|
+
"categoryPercentage": 60
|
|
46
|
+
},
|
|
60
47
|
{
|
|
61
|
-
type:
|
|
62
|
-
symbol: "
|
|
63
|
-
wholePercentage:
|
|
64
|
-
categoryPercentage:
|
|
48
|
+
"type": "OTHER_STOCK",
|
|
49
|
+
"symbol": "NVDA",
|
|
50
|
+
"wholePercentage": 20,
|
|
51
|
+
"categoryPercentage": 40
|
|
65
52
|
}
|
|
66
|
-
]
|
|
53
|
+
],
|
|
54
|
+
"category": "EQUITY",
|
|
55
|
+
"percentage": 50
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
"category": "GOVERNMENT_BOND",
|
|
59
|
+
"percentage": 30
|
|
67
60
|
},
|
|
68
61
|
{
|
|
69
|
-
category:
|
|
70
|
-
percentage:
|
|
62
|
+
"category": "CURRENCY",
|
|
63
|
+
"percentage": 20
|
|
71
64
|
}
|
|
72
65
|
]
|
|
73
66
|
};
|
|
74
67
|
|
|
75
|
-
const mockHistoricalPricesResponse
|
|
76
|
-
{
|
|
77
|
-
price: 15.25,
|
|
78
|
-
aum: 1250000000,
|
|
79
|
-
date: "2024-03-14T10:00:00Z",
|
|
80
|
-
shareCount: 82000000,
|
|
81
|
-
investorCount: 25000
|
|
82
|
-
},
|
|
68
|
+
const mockHistoricalPricesResponse = [
|
|
83
69
|
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
70
|
+
"date": "2026-02-20T00:00:00Z",
|
|
71
|
+
"price": 1.004711,
|
|
72
|
+
"aum": 5242278660.64,
|
|
73
|
+
"investorCount": 48900,
|
|
74
|
+
"shareCount": 5217695760
|
|
89
75
|
}
|
|
90
76
|
];
|
|
91
77
|
|
|
@@ -119,6 +105,7 @@ describe("Funds Client", () => {
|
|
|
119
105
|
expect(typeof fund.assetType).toBe("string");
|
|
120
106
|
expect(typeof fund.managementFee).toBe("number");
|
|
121
107
|
expect(typeof fund.riskLevel).toBe("number");
|
|
108
|
+
expect(typeof fund.active).toBe("boolean");
|
|
122
109
|
expect(typeof fund.ownerSymbol).toBe("string");
|
|
123
110
|
expect(Object.values(FundType)).toContain(fund.fundType);
|
|
124
111
|
});
|
|
@@ -191,127 +178,209 @@ describe("Funds Client", () => {
|
|
|
191
178
|
});
|
|
192
179
|
|
|
193
180
|
describe("Mock Tests", () => {
|
|
181
|
+
let client: FundsClient;
|
|
182
|
+
let cli: { request: jest.Mock };
|
|
183
|
+
|
|
194
184
|
beforeEach(() => {
|
|
195
|
-
jest.
|
|
185
|
+
cli = { request: jest.fn() };
|
|
186
|
+
|
|
187
|
+
const config = (global as any).testSuite.config as LaplaceConfiguration;
|
|
188
|
+
const logger: Logger = {
|
|
189
|
+
info: jest.fn(),
|
|
190
|
+
error: jest.fn(),
|
|
191
|
+
warn: jest.fn(),
|
|
192
|
+
debug: jest.fn(),
|
|
193
|
+
} as unknown as Logger;
|
|
194
|
+
|
|
195
|
+
client = new FundsClient(config, logger, cli as any);
|
|
196
196
|
});
|
|
197
|
-
|
|
197
|
+
|
|
198
198
|
describe("getFunds", () => {
|
|
199
|
-
test("
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const resp = await client.getFunds(Region.Tr,
|
|
203
|
-
|
|
204
|
-
expect(
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
expect(
|
|
208
|
-
expect(
|
|
209
|
-
expect(
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
199
|
+
test("calls correct endpoint/params (without page) and matches raw response", async () => {
|
|
200
|
+
cli.request.mockResolvedValueOnce({ data: mockFundsResponse });
|
|
201
|
+
|
|
202
|
+
const resp = await client.getFunds(Region.Tr, 10);
|
|
203
|
+
|
|
204
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
205
|
+
const call = cli.request.mock.calls[0][0];
|
|
206
|
+
|
|
207
|
+
expect(call.method).toBe("GET");
|
|
208
|
+
expect(call.url).toBe("/api/v1/fund");
|
|
209
|
+
expect(call.params).toEqual({
|
|
210
|
+
region: Region.Tr,
|
|
211
|
+
pageSize: 10,
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
expect(resp).toHaveLength(1);
|
|
215
|
+
|
|
216
|
+
const f = resp[0];
|
|
217
|
+
expect(f.assetType).toBe("fund");
|
|
218
|
+
expect(f.name).toBe(
|
|
219
|
+
"NEO PORTFÖY KATILIM HİSSE SENEDİ FONU (HİSSE SENEDİ YOĞUN FON)"
|
|
220
|
+
);
|
|
221
|
+
expect(f.symbol).toBe("NKM");
|
|
222
|
+
expect(f.active).toBe(true);
|
|
223
|
+
expect(f.managementFee).toBe(2.8);
|
|
224
|
+
expect(f.riskLevel).toBe(0);
|
|
225
|
+
expect(f.fundType).toBe("STOCK_UMBRELLA_FUND");
|
|
226
|
+
expect(f.ownerSymbol).toBe("VVP");
|
|
216
227
|
});
|
|
217
|
-
|
|
218
|
-
test("
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const resp = await client.getFunds(Region.Tr,
|
|
222
|
-
|
|
228
|
+
|
|
229
|
+
test("calls correct endpoint/params (with page) and matches raw response", async () => {
|
|
230
|
+
cli.request.mockResolvedValueOnce({ data: mockFundsResponse });
|
|
231
|
+
|
|
232
|
+
const resp = await client.getFunds(Region.Tr, 10, 2);
|
|
233
|
+
|
|
234
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
235
|
+
const call = cli.request.mock.calls[0][0];
|
|
236
|
+
|
|
237
|
+
expect(call.method).toBe("GET");
|
|
238
|
+
expect(call.url).toBe("/api/v1/fund");
|
|
239
|
+
expect(call.params).toEqual({
|
|
240
|
+
region: Region.Tr,
|
|
241
|
+
pageSize: 10,
|
|
242
|
+
page: 2,
|
|
243
|
+
});
|
|
244
|
+
|
|
223
245
|
expect(resp).toHaveLength(1);
|
|
224
|
-
expect(resp[0].symbol).toBe("
|
|
225
|
-
|
|
226
|
-
|
|
246
|
+
expect(resp[0].symbol).toBe("NKM");
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
test("bubbles up request error", async () => {
|
|
250
|
+
cli.request.mockRejectedValueOnce(new Error("Bad request"));
|
|
251
|
+
|
|
252
|
+
await expect(client.getFunds(Region.Tr, 10)).rejects.toThrow("Bad request");
|
|
227
253
|
});
|
|
228
254
|
});
|
|
229
|
-
|
|
255
|
+
|
|
230
256
|
describe("getFundStats", () => {
|
|
231
|
-
test("
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const resp = await client.getFundStats("
|
|
235
|
-
|
|
236
|
-
expect(
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
expect(
|
|
240
|
-
expect(
|
|
241
|
-
expect(
|
|
242
|
-
|
|
243
|
-
expect(resp.
|
|
244
|
-
expect(resp.
|
|
245
|
-
expect(resp.
|
|
246
|
-
|
|
247
|
-
expect(
|
|
257
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
258
|
+
cli.request.mockResolvedValueOnce({ data: mockFundStatsResponse });
|
|
259
|
+
|
|
260
|
+
const resp = await client.getFundStats("NKM", Region.Tr);
|
|
261
|
+
|
|
262
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
263
|
+
const call = cli.request.mock.calls[0][0];
|
|
264
|
+
|
|
265
|
+
expect(call.method).toBe("GET");
|
|
266
|
+
expect(call.url).toBe("/api/v1/fund/stats");
|
|
267
|
+
expect(call.params).toEqual({ symbol: "NKM", region: Region.Tr });
|
|
268
|
+
|
|
269
|
+
expect(resp.monthlyReturn).toBe(-2.3367);
|
|
270
|
+
expect(resp.threeMonthReturn).toBe(3.8059);
|
|
271
|
+
expect(resp.sixMonthReturn).toBe(12.3031);
|
|
272
|
+
expect(resp.ytdReturn).toBe(-0.8037);
|
|
273
|
+
expect(resp.yearlyReturn).toBe(31.9956);
|
|
274
|
+
expect(resp.threeYearReturn).toBe(281.8466);
|
|
275
|
+
expect(resp.fiveYearReturn).toBe(867.6593);
|
|
276
|
+
expect(resp.yearMomentum).toBe(0);
|
|
277
|
+
expect(resp.yearBeta).toBe(0.000068);
|
|
278
|
+
expect(resp.yearStdev).toBe(0.077);
|
|
248
279
|
});
|
|
249
|
-
|
|
250
|
-
test("
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
await expect(client.getFundStats("
|
|
254
|
-
|
|
280
|
+
|
|
281
|
+
test("bubbles up request error", async () => {
|
|
282
|
+
cli.request.mockRejectedValueOnce(new Error("Fund not found"));
|
|
283
|
+
|
|
284
|
+
await expect(client.getFundStats("INVALID", Region.Tr)).rejects.toThrow(
|
|
285
|
+
"Fund not found"
|
|
286
|
+
);
|
|
255
287
|
});
|
|
256
288
|
});
|
|
257
|
-
|
|
289
|
+
|
|
258
290
|
describe("getFundDistribution", () => {
|
|
259
|
-
test("
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
const resp = await client.getFundDistribution("
|
|
263
|
-
|
|
264
|
-
expect(
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
expect(
|
|
268
|
-
expect(
|
|
269
|
-
expect(
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
expect(
|
|
275
|
-
|
|
276
|
-
expect(
|
|
291
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
292
|
+
cli.request.mockResolvedValueOnce({ data: mockFundDistributionResponse });
|
|
293
|
+
|
|
294
|
+
const resp = await client.getFundDistribution("NKM", Region.Tr);
|
|
295
|
+
|
|
296
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
297
|
+
const call = cli.request.mock.calls[0][0];
|
|
298
|
+
|
|
299
|
+
expect(call.method).toBe("GET");
|
|
300
|
+
expect(call.url).toBe("/api/v1/fund/distribution");
|
|
301
|
+
expect(call.params).toEqual({ symbol: "NKM", region: Region.Tr });
|
|
302
|
+
|
|
303
|
+
expect(resp.categories).toHaveLength(3);
|
|
304
|
+
|
|
305
|
+
const c0 = resp.categories[0];
|
|
306
|
+
expect(c0.category).toBe("EQUITY");
|
|
307
|
+
expect(c0.percentage).toBe(50);
|
|
308
|
+
expect(Array.isArray(c0.assets)).toBe(true);
|
|
309
|
+
expect(c0.assets!).toHaveLength(2);
|
|
310
|
+
|
|
311
|
+
expect(c0.assets![0].type).toBe("BIST_STOCK");
|
|
312
|
+
expect(c0.assets![0].symbol).toBe("ASELS");
|
|
313
|
+
expect(c0.assets![0].wholePercentage).toBe(30);
|
|
314
|
+
expect(c0.assets![0].categoryPercentage).toBe(60);
|
|
315
|
+
|
|
316
|
+
expect(c0.assets![1].type).toBe("OTHER_STOCK");
|
|
317
|
+
expect(c0.assets![1].symbol).toBe("NVDA");
|
|
318
|
+
expect(c0.assets![1].wholePercentage).toBe(20);
|
|
319
|
+
expect(c0.assets![1].categoryPercentage).toBe(40);
|
|
320
|
+
|
|
321
|
+
const c1 = resp.categories[1];
|
|
322
|
+
expect(c1.category).toBe("GOVERNMENT_BOND");
|
|
323
|
+
expect(c1.percentage).toBe(30);
|
|
324
|
+
expect(c1.assets).toBeUndefined();
|
|
325
|
+
|
|
326
|
+
const c2 = resp.categories[2];
|
|
327
|
+
expect(c2.category).toBe("CURRENCY");
|
|
328
|
+
expect(c2.percentage).toBe(20);
|
|
329
|
+
expect(c2.assets).toBeUndefined();
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
test("bubbles up request error", async () => {
|
|
333
|
+
cli.request.mockRejectedValueOnce(new Error("Invalid symbol"));
|
|
334
|
+
|
|
335
|
+
await expect(client.getFundDistribution("INVALID", Region.Tr)).rejects.toThrow(
|
|
336
|
+
"Invalid symbol"
|
|
337
|
+
);
|
|
277
338
|
});
|
|
278
339
|
});
|
|
279
|
-
|
|
340
|
+
|
|
280
341
|
describe("getHistoricalFundPrices", () => {
|
|
281
|
-
test("
|
|
282
|
-
|
|
283
|
-
|
|
342
|
+
test("calls correct endpoint/params and matches raw response", async () => {
|
|
343
|
+
cli.request.mockResolvedValueOnce({ data: mockHistoricalPricesResponse });
|
|
344
|
+
|
|
284
345
|
const resp = await client.getHistoricalFundPrices(
|
|
285
|
-
"
|
|
286
|
-
Region.Tr,
|
|
287
|
-
HistoricalFundPricePeriod.OneMonth
|
|
288
|
-
);
|
|
289
|
-
|
|
290
|
-
expect(resp).toHaveLength(2);
|
|
291
|
-
|
|
292
|
-
const firstPrice = resp[0];
|
|
293
|
-
expect(firstPrice.price).toBe(15.25);
|
|
294
|
-
expect(firstPrice.aum).toBe(1250000000);
|
|
295
|
-
expect(firstPrice.date).toBe("2024-03-14T10:00:00Z");
|
|
296
|
-
expect(firstPrice.shareCount).toBe(82000000);
|
|
297
|
-
expect(firstPrice.investorCount).toBe(25000);
|
|
298
|
-
|
|
299
|
-
expect(client.getHistoricalFundPrices).toHaveBeenCalledWith(
|
|
300
|
-
"SPP",
|
|
346
|
+
"NKM",
|
|
301
347
|
Region.Tr,
|
|
302
348
|
HistoricalFundPricePeriod.OneMonth
|
|
303
349
|
);
|
|
350
|
+
|
|
351
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
352
|
+
const call = cli.request.mock.calls[0][0];
|
|
353
|
+
|
|
354
|
+
expect(call.method).toBe("GET");
|
|
355
|
+
expect(call.url).toBe("/api/v1/fund/price");
|
|
356
|
+
expect(call.params).toEqual({
|
|
357
|
+
symbol: "NKM",
|
|
358
|
+
region: Region.Tr,
|
|
359
|
+
period: HistoricalFundPricePeriod.OneMonth,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
expect(resp).toHaveLength(1);
|
|
363
|
+
|
|
364
|
+
const p = resp[0];
|
|
365
|
+
expect(p.date).toBe("2026-02-20T00:00:00Z");
|
|
366
|
+
expect(p.price).toBe(1.004711);
|
|
367
|
+
expect(p.aum).toBe(5242278660.64);
|
|
368
|
+
expect(p.investorCount).toBe(48900);
|
|
369
|
+
expect(p.shareCount).toBe(5217695760);
|
|
304
370
|
});
|
|
305
|
-
|
|
306
|
-
test("
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
await expect(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
371
|
+
|
|
372
|
+
test("bubbles up request error", async () => {
|
|
373
|
+
cli.request.mockRejectedValueOnce(new Error("Invalid period"));
|
|
374
|
+
|
|
375
|
+
await expect(
|
|
376
|
+
client.getHistoricalFundPrices(
|
|
377
|
+
"NKM",
|
|
378
|
+
Region.Tr,
|
|
379
|
+
"INVALID_PERIOD" as HistoricalFundPricePeriod
|
|
380
|
+
)
|
|
381
|
+
).rejects.toThrow("Invalid period");
|
|
314
382
|
});
|
|
315
383
|
});
|
|
316
384
|
});
|
|
385
|
+
|
|
317
386
|
});
|
package/src/test/helpers.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Collection, CollectionDetail } from "../client/collections";
|
|
2
|
+
import { Stock } from "../client/stocks";
|
|
2
3
|
|
|
3
4
|
export const validateCollection = (collection: Collection) => {
|
|
4
5
|
expect(typeof collection.id).toBe("string");
|
|
@@ -17,27 +18,19 @@ export const validateCollection = (collection: Collection) => {
|
|
|
17
18
|
expect(typeof region).toBe("string");
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
-
if (collection.
|
|
22
|
-
expect(typeof collection.
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
if (collection.image !== undefined) {
|
|
26
|
-
expect(typeof collection.image).toBe("string");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
if (collection.order !== undefined) {
|
|
30
|
-
expect(typeof collection.order).toBe("number");
|
|
21
|
+
|
|
22
|
+
if (collection.locale != null) {
|
|
23
|
+
expect(typeof collection.locale).toBe("string");
|
|
31
24
|
}
|
|
32
25
|
|
|
33
|
-
if (collection.
|
|
34
|
-
expect(typeof collection.
|
|
26
|
+
if (collection.assetClass != null) {
|
|
27
|
+
expect(typeof collection.assetClass).toBe("string");
|
|
35
28
|
}
|
|
36
29
|
|
|
37
|
-
if (collection.
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
if (collection.image != null) expect(typeof collection.image).toBe("string");
|
|
31
|
+
if (collection.order != null) expect(typeof collection.order).toBe("number");
|
|
32
|
+
if (collection.status != null) expect(typeof collection.status).toBe("string");
|
|
33
|
+
if (collection.metaData != null) expect(typeof collection.metaData).toBe("object");
|
|
41
34
|
};
|
|
42
35
|
|
|
43
36
|
export const validateCollectionDetail = (collectionDetail: CollectionDetail) => {
|
|
@@ -46,13 +39,16 @@ export const validateCollection = (collection: Collection) => {
|
|
|
46
39
|
expect(Array.isArray(collectionDetail.stocks)).toBe(true);
|
|
47
40
|
expect(collectionDetail.stocks.length).toBeGreaterThan(0);
|
|
48
41
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
expect(typeof
|
|
54
|
-
expect(typeof
|
|
55
|
-
expect(typeof
|
|
56
|
-
expect(typeof
|
|
57
|
-
expect(typeof
|
|
58
|
-
|
|
42
|
+
collectionDetail.stocks.forEach(validateStockLite);
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
function validateStockLite(s: Stock) {
|
|
46
|
+
expect(typeof s.id).toBe("string");
|
|
47
|
+
expect(typeof s.assetType).toBe("string");
|
|
48
|
+
expect(typeof s.name).toBe("string");
|
|
49
|
+
expect(typeof s.symbol).toBe("string");
|
|
50
|
+
expect(typeof s.sectorId).toBe("string");
|
|
51
|
+
expect(typeof s.industryId).toBe("string");
|
|
52
|
+
expect(typeof s.updatedDate).toBe("string");
|
|
53
|
+
expect(typeof s.active).toBe("boolean");
|
|
54
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Logger } from "winston";
|
|
2
2
|
import { LaplaceConfiguration } from "../utilities/configuration";
|
|
3
3
|
import "./client_test_suite";
|
|
4
|
-
import { KeyInsightClient
|
|
4
|
+
import { KeyInsightClient } from "../client/key-insights";
|
|
5
5
|
import { Region } from "../client/collections";
|
|
6
6
|
|
|
7
|
-
const mockTRKeyInsightResponse
|
|
7
|
+
const mockTRKeyInsightResponse = {
|
|
8
8
|
symbol: "TOASO",
|
|
9
9
|
insight: "Tofaş'ın net kârı, güçlü operasyonel performans ve yüksek ihracat gelirleri sayesinde geçen yılın aynı dönemine göre %85 artış gösterdi."
|
|
10
10
|
};
|
|
11
11
|
|
|
12
|
-
const mockUSKeyInsightResponse
|
|
12
|
+
const mockUSKeyInsightResponse = {
|
|
13
13
|
symbol: "AAPL",
|
|
14
14
|
insight: "Apple's revenue growth was driven by strong iPhone sales and continued expansion in services, with significant market share gains in emerging markets."
|
|
15
15
|
};
|
|
@@ -59,52 +59,87 @@ describe("Key Insight", () => {
|
|
|
59
59
|
});
|
|
60
60
|
|
|
61
61
|
describe("Mock Tests", () => {
|
|
62
|
+
let client: KeyInsightClient;
|
|
63
|
+
let cli: { request: jest.Mock };
|
|
64
|
+
|
|
62
65
|
beforeEach(() => {
|
|
63
|
-
jest.
|
|
66
|
+
cli = { request: jest.fn() };
|
|
67
|
+
|
|
68
|
+
const config = (global as any).testSuite.config as LaplaceConfiguration;
|
|
69
|
+
const logger: Logger = {
|
|
70
|
+
info: jest.fn(),
|
|
71
|
+
error: jest.fn(),
|
|
72
|
+
warn: jest.fn(),
|
|
73
|
+
debug: jest.fn(),
|
|
74
|
+
} as unknown as Logger;
|
|
75
|
+
|
|
76
|
+
client = new KeyInsightClient(config, logger, cli as any);
|
|
64
77
|
});
|
|
65
|
-
|
|
78
|
+
|
|
66
79
|
describe("getKeyInsights", () => {
|
|
67
|
-
test("
|
|
68
|
-
|
|
69
|
-
|
|
80
|
+
test("TR: calls correct endpoint/params and matches raw response", async () => {
|
|
81
|
+
cli.request.mockResolvedValueOnce({ data: mockTRKeyInsightResponse });
|
|
82
|
+
|
|
70
83
|
const resp = await client.getKeyInsights("TOASO", Region.Tr);
|
|
71
|
-
|
|
72
|
-
expect(
|
|
84
|
+
|
|
85
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
86
|
+
const call = cli.request.mock.calls[0][0];
|
|
87
|
+
|
|
88
|
+
expect(call.method).toBe("GET");
|
|
89
|
+
expect(call.url).toBe("/api/v1/key-insights");
|
|
90
|
+
expect(call.params).toEqual({
|
|
91
|
+
symbol: "TOASO",
|
|
92
|
+
region: Region.Tr,
|
|
93
|
+
});
|
|
94
|
+
|
|
73
95
|
expect(resp.symbol).toBe("TOASO");
|
|
74
96
|
expect(resp.insight).toBe(mockTRKeyInsightResponse.insight);
|
|
75
|
-
|
|
76
|
-
expect(client.getKeyInsights).toHaveBeenCalledWith("TOASO", Region.Tr);
|
|
77
97
|
});
|
|
78
|
-
|
|
79
|
-
test("
|
|
80
|
-
|
|
81
|
-
|
|
98
|
+
|
|
99
|
+
test("US: calls correct endpoint/params and matches raw response", async () => {
|
|
100
|
+
cli.request.mockResolvedValueOnce({ data: mockUSKeyInsightResponse });
|
|
101
|
+
|
|
82
102
|
const resp = await client.getKeyInsights("AAPL", Region.Us);
|
|
83
|
-
|
|
84
|
-
expect(
|
|
103
|
+
|
|
104
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
105
|
+
const call = cli.request.mock.calls[0][0];
|
|
106
|
+
|
|
107
|
+
expect(call.method).toBe("GET");
|
|
108
|
+
expect(call.url).toBe("/api/v1/key-insights");
|
|
109
|
+
expect(call.params).toEqual({
|
|
110
|
+
symbol: "AAPL",
|
|
111
|
+
region: Region.Us,
|
|
112
|
+
});
|
|
113
|
+
|
|
85
114
|
expect(resp.symbol).toBe("AAPL");
|
|
86
115
|
expect(resp.insight).toBe(mockUSKeyInsightResponse.insight);
|
|
87
|
-
|
|
88
|
-
expect(client.getKeyInsights).toHaveBeenCalledWith("AAPL", Region.Us);
|
|
89
116
|
});
|
|
90
|
-
|
|
91
|
-
test("
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
await expect(client.getKeyInsights("INVALID_SYMBOL", Region.Tr))
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
117
|
+
|
|
118
|
+
test("bubbles up request error", async () => {
|
|
119
|
+
cli.request.mockRejectedValueOnce(new Error("Symbol not found"));
|
|
120
|
+
|
|
121
|
+
await expect(client.getKeyInsights("INVALID_SYMBOL", Region.Tr)).rejects.toThrow(
|
|
122
|
+
"Symbol not found"
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
98
126
|
});
|
|
99
|
-
|
|
100
|
-
test("
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
await expect(client.getKeyInsights("", Region.Tr))
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
127
|
+
|
|
128
|
+
test("empty symbol: bubbles up request error", async () => {
|
|
129
|
+
cli.request.mockRejectedValueOnce(new Error("Symbol cannot be empty"));
|
|
130
|
+
|
|
131
|
+
await expect(client.getKeyInsights("", Region.Tr)).rejects.toThrow(
|
|
132
|
+
"Symbol cannot be empty"
|
|
133
|
+
);
|
|
134
|
+
|
|
135
|
+
expect(cli.request).toHaveBeenCalledTimes(1);
|
|
136
|
+
const call = cli.request.mock.calls[0][0];
|
|
137
|
+
|
|
138
|
+
expect(call.method).toBe("GET");
|
|
139
|
+
expect(call.url).toBe("/api/v1/key-insights");
|
|
140
|
+
expect(call.params).toEqual({ symbol: "", region: Region.Tr });
|
|
107
141
|
});
|
|
108
142
|
});
|
|
109
143
|
});
|
|
144
|
+
|
|
110
145
|
});
|