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.
- package/.github/workflows/publish.yml +37 -0
- package/.github/workflows/test.yml +25 -0
- package/README.md +461 -2
- package/package.json +1 -1
- package/src/client/broker.ts +79 -99
- package/src/client/capital_increase.ts +17 -22
- package/src/client/collections.ts +61 -40
- package/src/client/financial_fundamentals.ts +40 -35
- package/src/client/financial_ratios.ts +168 -128
- package/src/client/funds.ts +139 -0
- package/src/client/key-insights.ts +17 -0
- package/src/client/live-price-web-socket.ts +84 -11
- package/src/client/live-price.ts +210 -58
- package/src/client/politician.ts +75 -0
- package/src/client/stocks.ts +85 -2
- package/src/test/broker.test.ts +581 -170
- package/src/test/capital_increase.test.ts +266 -15
- package/src/test/collections.test.ts +460 -17
- package/src/test/custom_theme.test.ts +256 -65
- package/src/test/financial_fundamentals.test.ts +301 -45
- package/src/test/financial_ratios.test.ts +376 -75
- package/src/test/funds.test.ts +317 -0
- package/src/test/helpers.ts +58 -0
- package/src/test/key-insight.test.ts +110 -0
- package/src/test/live-price.test.ts +427 -67
- package/src/test/politician.test.ts +253 -0
- package/src/test/readme.test.ts +483 -0
- package/src/test/search.test.ts +308 -23
- package/src/test/stocks.test.ts +800 -70
- package/src/utilities/configuration.ts +23 -10
- package/src/utilities/test.env +2 -2
package/src/test/search.test.ts
CHANGED
|
@@ -1,15 +1,89 @@
|
|
|
1
|
-
import { Logger } from
|
|
2
|
-
import { LaplaceConfiguration } from
|
|
3
|
-
import { SearchClient, SearchType } from
|
|
4
|
-
import
|
|
5
|
-
import
|
|
1
|
+
import { Logger } from "winston";
|
|
2
|
+
import { LaplaceConfiguration } from "../utilities/configuration";
|
|
3
|
+
import { SearchClient, SearchType } from "../client/search";
|
|
4
|
+
import "./client_test_suite";
|
|
5
|
+
import { Region, Locale } from "../client/collections";
|
|
6
6
|
|
|
7
|
+
const mockStockSearchResponse = {
|
|
8
|
+
stocks: [
|
|
9
|
+
{
|
|
10
|
+
id: "61dd0d6f0ec2114146342fd0",
|
|
11
|
+
name: "Tüpraş",
|
|
12
|
+
title: "Türkiye Petrol Rafinerileri A.Ş.",
|
|
13
|
+
region: Region.Tr,
|
|
14
|
+
assetType: "stock",
|
|
15
|
+
type: "equity"
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
industries: [],
|
|
19
|
+
sectors: [],
|
|
20
|
+
collections: []
|
|
21
|
+
};
|
|
7
22
|
|
|
8
|
-
|
|
23
|
+
const mockIndustrySearchResponse = {
|
|
24
|
+
stocks: [],
|
|
25
|
+
industries: [
|
|
26
|
+
{
|
|
27
|
+
id: "ind123",
|
|
28
|
+
title: "Hava Yolları Taşımacılığı",
|
|
29
|
+
region: [Region.Tr],
|
|
30
|
+
assetClass: "equity",
|
|
31
|
+
imageUrl: "https://example.com/image.jpg",
|
|
32
|
+
avatarUrl: "https://example.com/avatar.jpg"
|
|
33
|
+
}
|
|
34
|
+
],
|
|
35
|
+
sectors: [],
|
|
36
|
+
collections: []
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const mockAllTypesSearchResponse = {
|
|
40
|
+
stocks: [
|
|
41
|
+
{
|
|
42
|
+
id: "61dd0d6f0ec2114146342fd1",
|
|
43
|
+
name: "Abbott",
|
|
44
|
+
title: "Abbott Laboratories",
|
|
45
|
+
region: Region.Us,
|
|
46
|
+
assetType: "stock",
|
|
47
|
+
type: "equity"
|
|
48
|
+
}
|
|
49
|
+
],
|
|
50
|
+
industries: [
|
|
51
|
+
{
|
|
52
|
+
id: "ind456",
|
|
53
|
+
title: "Abrasive Manufacturing",
|
|
54
|
+
region: [Region.Us],
|
|
55
|
+
assetClass: "equity",
|
|
56
|
+
imageUrl: "https://example.com/image.jpg",
|
|
57
|
+
avatarUrl: "https://example.com/avatar.jpg"
|
|
58
|
+
}
|
|
59
|
+
],
|
|
60
|
+
sectors: [
|
|
61
|
+
{
|
|
62
|
+
id: "sec789",
|
|
63
|
+
title: "Aerospace & Defense",
|
|
64
|
+
region: [Region.Us],
|
|
65
|
+
assetClass: "equity",
|
|
66
|
+
imageUrl: "https://example.com/sector.jpg",
|
|
67
|
+
avatarUrl: "https://example.com/sector-avatar.jpg"
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
collections: [
|
|
71
|
+
{
|
|
72
|
+
id: "col123",
|
|
73
|
+
title: "Artificial Intelligence",
|
|
74
|
+
description: "AI focused companies",
|
|
75
|
+
region: [Region.Us],
|
|
76
|
+
assetClass: "equity",
|
|
77
|
+
imageUrl: "https://example.com/collection.jpg",
|
|
78
|
+
avatarUrl: "https://example.com/collection-avatar.jpg"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
describe("Search", () => {
|
|
9
84
|
let client: SearchClient;
|
|
10
85
|
|
|
11
86
|
beforeAll(() => {
|
|
12
|
-
// Assuming global.testSuite is set up as in the previous example
|
|
13
87
|
const config = (global as any).testSuite.config as LaplaceConfiguration;
|
|
14
88
|
const logger: Logger = {
|
|
15
89
|
info: jest.fn(),
|
|
@@ -21,23 +95,234 @@ describe('Search', () => {
|
|
|
21
95
|
client = new SearchClient(config, logger);
|
|
22
96
|
});
|
|
23
97
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
98
|
+
describe("Integration Tests", () => {
|
|
99
|
+
test("SearchStock", async () => {
|
|
100
|
+
const resp = await client.search(
|
|
101
|
+
"TUPRS",
|
|
102
|
+
[SearchType.Stock],
|
|
103
|
+
Region.Tr,
|
|
104
|
+
Locale.Tr
|
|
105
|
+
);
|
|
106
|
+
expect(resp.stocks).not.toBeEmpty();
|
|
107
|
+
|
|
108
|
+
const firstResult = resp.stocks[0];
|
|
109
|
+
expect(typeof firstResult.id).toBe("string");
|
|
110
|
+
expect(typeof firstResult.name).toBe("string");
|
|
111
|
+
expect(typeof firstResult.title).toBe("string");
|
|
112
|
+
expect(typeof firstResult.region).toBe("string");
|
|
113
|
+
expect(typeof firstResult.assetType).toBe("string");
|
|
114
|
+
expect(typeof firstResult.type).toBe("string");
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
test("SearchIndustry", async () => {
|
|
118
|
+
const resp = await client.search(
|
|
119
|
+
"Hava",
|
|
120
|
+
[SearchType.Industry],
|
|
121
|
+
Region.Tr,
|
|
122
|
+
Locale.Tr
|
|
123
|
+
);
|
|
124
|
+
expect(resp.industries).not.toBeEmpty();
|
|
125
|
+
|
|
126
|
+
const firstResult = resp.industries[0];
|
|
127
|
+
expect(typeof firstResult.id).toBe("string");
|
|
128
|
+
expect(typeof firstResult.title).toBe("string");
|
|
129
|
+
expect(Array.isArray(firstResult.region)).toBe(true);
|
|
130
|
+
expect(firstResult.region.length).toBeGreaterThan(0);
|
|
131
|
+
firstResult.region.forEach((region) => {
|
|
132
|
+
expect(typeof region).toBe("string");
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
expect(typeof firstResult.assetClass).toBe("string");
|
|
136
|
+
expect(typeof firstResult.imageUrl).toBe("string");
|
|
137
|
+
expect(typeof firstResult.avatarUrl).toBe("string");
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
test("SearchAllTypes", async () => {
|
|
141
|
+
const resp = await client.search(
|
|
142
|
+
"Ab",
|
|
143
|
+
[
|
|
144
|
+
SearchType.Stock,
|
|
145
|
+
SearchType.Industry,
|
|
146
|
+
SearchType.Sector,
|
|
147
|
+
SearchType.Collection,
|
|
148
|
+
],
|
|
149
|
+
Region.Us,
|
|
150
|
+
Locale.Tr
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
expect(typeof resp).toBe("object");
|
|
154
|
+
expect(resp).not.toBeNull();
|
|
28
155
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
156
|
+
const hasResults =
|
|
157
|
+
(resp.stocks && resp.stocks.length > 0) ||
|
|
158
|
+
(resp.industries && resp.industries.length > 0) ||
|
|
159
|
+
(resp.sectors && resp.sectors.length > 0) ||
|
|
160
|
+
(resp.collections && resp.collections.length > 0);
|
|
161
|
+
|
|
162
|
+
expect(hasResults).toBe(true);
|
|
163
|
+
|
|
164
|
+
if (resp.stocks) expect(Array.isArray(resp.stocks)).toBe(true);
|
|
165
|
+
if (resp.industries) expect(Array.isArray(resp.industries)).toBe(true);
|
|
166
|
+
if (resp.sectors) expect(Array.isArray(resp.sectors)).toBe(true);
|
|
167
|
+
if (resp.collections) expect(Array.isArray(resp.collections)).toBe(true);
|
|
168
|
+
});
|
|
32
169
|
});
|
|
33
170
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
171
|
+
describe("Mock Tests", () => {
|
|
172
|
+
beforeEach(() => {
|
|
173
|
+
jest.clearAllMocks();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
describe("SearchStock", () => {
|
|
177
|
+
test("should return stock search results with mock data", async () => {
|
|
178
|
+
jest.spyOn(client, 'search').mockResolvedValue(mockStockSearchResponse);
|
|
179
|
+
|
|
180
|
+
const resp = await client.search(
|
|
181
|
+
"TUPRS",
|
|
182
|
+
[SearchType.Stock],
|
|
183
|
+
Region.Tr,
|
|
184
|
+
Locale.Tr
|
|
185
|
+
);
|
|
186
|
+
|
|
187
|
+
expect(resp.stocks).toHaveLength(1);
|
|
188
|
+
|
|
189
|
+
const firstResult = resp.stocks[0];
|
|
190
|
+
expect(firstResult.id).toBe("61dd0d6f0ec2114146342fd0");
|
|
191
|
+
expect(firstResult.name).toBe("Tüpraş");
|
|
192
|
+
expect(firstResult.title).toBe("Türkiye Petrol Rafinerileri A.Ş.");
|
|
193
|
+
expect(firstResult.region).toBe(Region.Tr);
|
|
194
|
+
expect(firstResult.assetType).toBe("stock");
|
|
195
|
+
expect(firstResult.type).toBe("equity");
|
|
196
|
+
|
|
197
|
+
expect(resp.industries).toHaveLength(0);
|
|
198
|
+
expect(resp.sectors).toHaveLength(0);
|
|
199
|
+
expect(resp.collections).toHaveLength(0);
|
|
200
|
+
|
|
201
|
+
expect(client.search).toHaveBeenCalledWith(
|
|
202
|
+
"TUPRS",
|
|
203
|
+
[SearchType.Stock],
|
|
204
|
+
Region.Tr,
|
|
205
|
+
Locale.Tr
|
|
206
|
+
);
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("should handle API errors for stock search", async () => {
|
|
210
|
+
jest.spyOn(client, 'search').mockRejectedValue(new Error("Failed to search stocks"));
|
|
211
|
+
|
|
212
|
+
await expect(client.search(
|
|
213
|
+
"TUPRS",
|
|
214
|
+
[SearchType.Stock],
|
|
215
|
+
Region.Tr,
|
|
216
|
+
Locale.Tr
|
|
217
|
+
)).rejects.toThrow("Failed to search stocks");
|
|
218
|
+
});
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
describe("SearchIndustry", () => {
|
|
222
|
+
test("should return industry search results with mock data", async () => {
|
|
223
|
+
jest.spyOn(client, 'search').mockResolvedValue(mockIndustrySearchResponse);
|
|
224
|
+
|
|
225
|
+
const resp = await client.search(
|
|
226
|
+
"Hava",
|
|
227
|
+
[SearchType.Industry],
|
|
228
|
+
Region.Tr,
|
|
229
|
+
Locale.Tr
|
|
230
|
+
);
|
|
231
|
+
|
|
232
|
+
expect(resp.industries).toHaveLength(1);
|
|
233
|
+
|
|
234
|
+
const firstResult = resp.industries[0];
|
|
235
|
+
expect(firstResult.id).toBe("ind123");
|
|
236
|
+
expect(firstResult.title).toBe("Hava Yolları Taşımacılığı");
|
|
237
|
+
expect(firstResult.region).toEqual([Region.Tr]);
|
|
238
|
+
expect(firstResult.assetClass).toBe("equity");
|
|
239
|
+
expect(firstResult.imageUrl).toBe("https://example.com/image.jpg");
|
|
240
|
+
expect(firstResult.avatarUrl).toBe("https://example.com/avatar.jpg");
|
|
241
|
+
|
|
242
|
+
expect(resp.stocks).toHaveLength(0);
|
|
243
|
+
expect(resp.sectors).toHaveLength(0);
|
|
244
|
+
expect(resp.collections).toHaveLength(0);
|
|
245
|
+
|
|
246
|
+
expect(client.search).toHaveBeenCalledWith(
|
|
247
|
+
"Hava",
|
|
248
|
+
[SearchType.Industry],
|
|
249
|
+
Region.Tr,
|
|
250
|
+
Locale.Tr
|
|
251
|
+
);
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
test("should handle API errors for industry search", async () => {
|
|
255
|
+
jest.spyOn(client, 'search').mockRejectedValue(new Error("Failed to search industries"));
|
|
256
|
+
|
|
257
|
+
await expect(client.search(
|
|
258
|
+
"Hava",
|
|
259
|
+
[SearchType.Industry],
|
|
260
|
+
Region.Tr,
|
|
261
|
+
Locale.Tr
|
|
262
|
+
)).rejects.toThrow("Failed to search industries");
|
|
263
|
+
});
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
describe("SearchAllTypes", () => {
|
|
267
|
+
test("should return all types search results with mock data", async () => {
|
|
268
|
+
jest.spyOn(client, 'search').mockResolvedValue(mockAllTypesSearchResponse);
|
|
269
|
+
|
|
270
|
+
const resp = await client.search(
|
|
271
|
+
"Ab",
|
|
272
|
+
[
|
|
273
|
+
SearchType.Stock,
|
|
274
|
+
SearchType.Industry,
|
|
275
|
+
SearchType.Sector,
|
|
276
|
+
SearchType.Collection,
|
|
277
|
+
],
|
|
278
|
+
Region.Us,
|
|
279
|
+
Locale.Tr
|
|
280
|
+
);
|
|
281
|
+
|
|
282
|
+
expect(resp.stocks).toHaveLength(1);
|
|
283
|
+
expect(resp.stocks[0].name).toBe("Abbott");
|
|
284
|
+
expect(resp.stocks[0].region).toBe(Region.Us);
|
|
285
|
+
|
|
286
|
+
expect(resp.industries).toHaveLength(1);
|
|
287
|
+
expect(resp.industries[0].title).toBe("Abrasive Manufacturing");
|
|
288
|
+
expect(resp.industries[0].region).toEqual([Region.Us]);
|
|
289
|
+
|
|
290
|
+
expect(resp.sectors).toHaveLength(1);
|
|
291
|
+
expect(resp.sectors[0].title).toBe("Aerospace & Defense");
|
|
292
|
+
expect(resp.sectors[0].region).toEqual([Region.Us]);
|
|
293
|
+
|
|
294
|
+
expect(resp.collections).toHaveLength(1);
|
|
295
|
+
expect(resp.collections[0].title).toBe("Artificial Intelligence");
|
|
296
|
+
expect(resp.collections[0].region).toEqual([Region.Us]);
|
|
297
|
+
|
|
298
|
+
expect(client.search).toHaveBeenCalledWith(
|
|
299
|
+
"Ab",
|
|
300
|
+
[
|
|
301
|
+
SearchType.Stock,
|
|
302
|
+
SearchType.Industry,
|
|
303
|
+
SearchType.Sector,
|
|
304
|
+
SearchType.Collection,
|
|
305
|
+
],
|
|
306
|
+
Region.Us,
|
|
307
|
+
Locale.Tr
|
|
308
|
+
);
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
test("should handle API errors for all types search", async () => {
|
|
312
|
+
jest.spyOn(client, 'search').mockRejectedValue(new Error("Failed to search all types"));
|
|
313
|
+
|
|
314
|
+
await expect(client.search(
|
|
315
|
+
"Ab",
|
|
316
|
+
[
|
|
317
|
+
SearchType.Stock,
|
|
318
|
+
SearchType.Industry,
|
|
319
|
+
SearchType.Sector,
|
|
320
|
+
SearchType.Collection,
|
|
321
|
+
],
|
|
322
|
+
Region.Us,
|
|
323
|
+
Locale.Tr
|
|
324
|
+
)).rejects.toThrow("Failed to search all types");
|
|
325
|
+
});
|
|
326
|
+
});
|
|
42
327
|
});
|
|
43
|
-
});
|
|
328
|
+
});
|