laplace-api 4.8.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.
@@ -9,65 +9,63 @@ import {
9
9
  import { Stock, StockClient } from "../client/stocks";
10
10
  import "./client_test_suite";
11
11
  import { validateCollection } from "./helpers";
12
- import { Locale, Region, SortBy, Collection, CollectionDetail } from "../client/collections";
13
- import { AssetType } from "../client/stocks";
12
+ import { Locale, Region, SortBy, CollectionType } from "../client/collections";
14
13
 
15
- const mockStocks: Stock[] = [
14
+ const mockCustomThemes = [
16
15
  {
17
- id: "stock1",
18
- name: "Tüpraş",
19
- symbol: "TUPRS",
20
- assetType: AssetType.Stock,
21
- sectorId: "sector1",
22
- industryId: "industry1",
23
- updatedDate: "2024-03-14T10:00:00Z",
24
- active: true
25
- },
26
- {
27
- id: "stock2",
28
- name: "Garanti Bankası",
29
- symbol: "GARAN",
30
- assetType: AssetType.Stock,
31
- sectorId: "sector2",
32
- industryId: "industry2",
33
- updatedDate: "2024-03-14T10:00:00Z",
34
- active: true
35
- },
36
- {
37
- id: "stock3",
38
- name: "Türk Hava Yolları",
39
- symbol: "THYAO",
40
- assetType: AssetType.Stock,
41
- sectorId: "sector3",
42
- industryId: "industry3",
43
- updatedDate: "2024-03-14T10:00:00Z",
44
- active: true
16
+ "id": "6888e18a6c84bcba9dc69ef7",
17
+ "title": "Test Custom Theme",
18
+ "region": [
19
+ "tr"
20
+ ],
21
+ "imageUrl": "Test Custom Theme Image URL",
22
+ "avatarUrl": "Test Custom Theme Avatar Image",
23
+ "numStocks": 2,
24
+ "assetClass": "equity",
25
+ "description": "Test Custom Theme Description",
26
+ "image": "Test Custom Theme Image",
27
+ "order": 0,
28
+ "status": "active"
45
29
  }
46
30
  ];
47
31
 
48
- const mockCustomThemes: Collection[] = [
49
- {
50
- id: "theme1",
51
- title: "Enerji Şirketleri",
52
- description: "Türkiye'nin önde gelen enerji şirketleri",
53
- region: [Region.Tr],
54
- imageUrl: "https://example.com/energy.jpg",
55
- avatarUrl: "https://example.com/energy-avatar.jpg",
56
- numStocks: 5,
57
- status: CollectionStatus.Active
58
- }
59
- ];
60
-
61
- const mockCustomThemeDetail: CollectionDetail = {
62
- id: "theme1",
63
- title: "Enerji Şirketleri",
64
- description: "Türkiye'nin önde gelen enerji şirketleri",
65
- region: [Region.Tr],
66
- imageUrl: "https://example.com/energy.jpg",
67
- avatarUrl: "https://example.com/energy-avatar.jpg",
68
- numStocks: 2,
69
- status: CollectionStatus.Active,
70
- stocks: [mockStocks[0], mockStocks[1]]
32
+ const mockCustomThemeDetail = {
33
+ "id": "6888e18a6c84bcba9dc69ef7",
34
+ "title": "Test Custom Theme",
35
+ "region": [
36
+ "tr"
37
+ ],
38
+ "imageUrl": "Test Custom Theme Image URL",
39
+ "avatarUrl": "Test Custom Theme Avatar Image",
40
+ "numStocks": 2,
41
+ "assetClass": "equity",
42
+ "description": "Test Custom Theme Description",
43
+ "image": "Test Custom Theme Image",
44
+ "order": 0,
45
+ "status": "active",
46
+ "stocks": [
47
+ {
48
+ "id": "648ab66e38daf3102a5a7401",
49
+ "assetType": "stock",
50
+ "name": "A1 Capital Yatırım Menkul Değerler",
51
+ "symbol": "A1CAP",
52
+ "sectorId": "65533e047844ee7afe9941bc",
53
+ "industryId": "65533e441fa5c7b58afa0955",
54
+ "updatedDate": "2025-04-01T00:00:00.533Z",
55
+ "active": true
56
+ },
57
+ {
58
+ "id": "61dd0da80ec21141463430cf",
59
+ "assetType": "stock",
60
+ "name": "A1 Yenilenebilir Enerji",
61
+ "symbol": "A1YEN",
62
+ "sectorId": "65533e047844ee7afe9941c2",
63
+ "industryId": "65533e441fa5c7b58afa0985",
64
+ "updatedDate": "2025-07-28T09:06:04.286Z",
65
+ "active": true
66
+ }
67
+ ],
68
+ "locale": "tr"
71
69
  };
72
70
 
73
71
  describe("CustomTheme", () => {
@@ -153,124 +151,232 @@ describe("CustomTheme", () => {
153
151
  });
154
152
 
155
153
  describe("Mock Tests", () => {
154
+ const locale = Locale.Tr;
155
+
156
+ let client: CustomThemeClient;
157
+ let cli: { request: jest.Mock };
158
+
156
159
  beforeEach(() => {
157
- jest.clearAllMocks();
160
+ cli = { request: jest.fn() };
161
+
162
+ const config = (global as any).testSuite.config as LaplaceConfiguration;
163
+ const logger: Logger = {
164
+ info: jest.fn(),
165
+ error: jest.fn(),
166
+ warn: jest.fn(),
167
+ debug: jest.fn(),
168
+ } as unknown as Logger;
169
+
170
+ client = new CustomThemeClient(config, logger, cli as any);
158
171
  });
159
-
172
+
160
173
  describe("getAllCustomThemes", () => {
161
- test("should return custom themes list with mock data", async () => {
162
- jest.spyOn(client, 'getAllCustomThemes').mockResolvedValue(mockCustomThemes);
163
-
164
- const resp = await client.getAllCustomThemes(Locale.Tr);
165
-
174
+ test("should call correct endpoint/params and return list (check all fields)", async () => {
175
+ cli.request.mockResolvedValueOnce({ data: mockCustomThemes });
176
+
177
+ const resp = await client.getAllCustomThemes(locale);
178
+
179
+ expect(cli.request).toHaveBeenCalledTimes(1);
180
+ const call = cli.request.mock.calls[0][0];
181
+ expect(call.method).toBe("GET");
182
+ expect(call.url).toBe(`/api/v1/${CollectionType.CustomTheme}`);
183
+ expect(call.params).toEqual({ locale });
184
+
185
+ expect(Array.isArray(resp)).toBe(true);
166
186
  expect(resp).toHaveLength(1);
167
-
187
+
168
188
  const theme = resp[0];
169
- expect(theme.id).toBe("theme1");
170
- expect(theme.title).toBe("Enerji Şirketleri");
171
- expect(theme.description).toBe("Türkiye'nin önde gelen enerji şirketleri");
172
- expect(theme.region).toEqual([Region.Tr]);
173
- expect(theme.imageUrl).toBe("https://example.com/energy.jpg");
174
- expect(theme.avatarUrl).toBe("https://example.com/energy-avatar.jpg");
175
- expect(theme.numStocks).toBe(5);
176
- expect(theme.status).toBe(CollectionStatus.Active);
177
-
178
- expect(client.getAllCustomThemes).toHaveBeenCalledWith(Locale.Tr);
189
+
190
+ expect(theme.id).toBe("6888e18a6c84bcba9dc69ef7");
191
+ expect(theme.title).toBe("Test Custom Theme");
192
+ expect(theme.region).toEqual(["tr"]);
193
+ expect(theme.imageUrl).toBe("Test Custom Theme Image URL");
194
+ expect(theme.avatarUrl).toBe("Test Custom Theme Avatar Image");
195
+ expect(theme.numStocks).toBe(2);
196
+ expect(theme.assetClass).toBe("equity");
197
+ expect(theme.description).toBe("Test Custom Theme Description");
198
+ expect(theme.image).toBe("Test Custom Theme Image");
199
+ expect(theme.order).toBe(0);
200
+ expect(theme.status).toBe("active");
179
201
  });
180
202
  });
181
-
203
+
182
204
  describe("getCustomThemeDetail", () => {
183
- test("should return custom theme detail with mock data", async () => {
184
- jest.spyOn(client, 'getCustomThemeDetail').mockResolvedValue(mockCustomThemeDetail);
185
-
186
- const resp = await client.getCustomThemeDetail("theme1", Locale.Tr, null);
187
-
188
- expect(resp.id).toBe("theme1");
189
- expect(resp.title).toBe("Enerji Şirketleri");
190
- expect(resp.description).toBe("Türkiye'nin önde gelen enerji şirketleri");
191
- expect(resp.region).toEqual([Region.Tr]);
192
- expect(resp.imageUrl).toBe("https://example.com/energy.jpg");
193
- expect(resp.avatarUrl).toBe("https://example.com/energy-avatar.jpg");
205
+ test("should call correct endpoint/params and return detail (check all fields)", async () => {
206
+ cli.request.mockResolvedValueOnce({ data: mockCustomThemeDetail });
207
+
208
+ const resp = await client.getCustomThemeDetail(
209
+ "6888e18a6c84bcba9dc69ef7",
210
+ locale,
211
+ null
212
+ );
213
+
214
+ expect(cli.request).toHaveBeenCalledTimes(1);
215
+ const call = cli.request.mock.calls[0][0];
216
+ expect(call.method).toBe("GET");
217
+ expect(call.url).toBe(
218
+ `/api/v1/${CollectionType.CustomTheme}/6888e18a6c84bcba9dc69ef7`
219
+ );
220
+ expect(call.params).toEqual({ locale });
221
+
222
+ expect(resp.id).toBe("6888e18a6c84bcba9dc69ef7");
223
+ expect(resp.title).toBe("Test Custom Theme");
224
+ expect(resp.region).toEqual(["tr"]);
225
+ expect(resp.imageUrl).toBe("Test Custom Theme Image URL");
226
+ expect(resp.avatarUrl).toBe("Test Custom Theme Avatar Image");
194
227
  expect(resp.numStocks).toBe(2);
195
- expect(resp.status).toBe(CollectionStatus.Active);
228
+ expect(resp.assetClass).toBe("equity");
229
+ expect(resp.description).toBe("Test Custom Theme Description");
230
+ expect(resp.image).toBe("Test Custom Theme Image");
231
+ expect(resp.order).toBe(0);
232
+ expect(resp.status).toBe("active");
233
+ expect(resp.locale).toBe("tr");
234
+
235
+ expect(Array.isArray(resp.stocks)).toBe(true);
196
236
  expect(resp.stocks).toHaveLength(2);
197
- expect(resp.stocks[0].symbol).toBe("TUPRS");
198
- expect(resp.stocks[1].symbol).toBe("GARAN");
199
-
200
- expect(client.getCustomThemeDetail).toHaveBeenCalledWith("theme1", Locale.Tr, null);
237
+
238
+ const s0 = resp.stocks[0];
239
+ expect(s0.id).toBe("648ab66e38daf3102a5a7401");
240
+ expect(s0.assetType).toBe("stock");
241
+ expect(s0.name).toBe("A1 Capital Yatırım Menkul Değerler");
242
+ expect(s0.symbol).toBe("A1CAP");
243
+ expect(s0.sectorId).toBe("65533e047844ee7afe9941bc");
244
+ expect(s0.industryId).toBe("65533e441fa5c7b58afa0955");
245
+ expect(s0.updatedDate).toBe("2025-04-01T00:00:00.533Z");
246
+ expect(s0.active).toBe(true);
247
+
248
+ const s1 = resp.stocks[1];
249
+ expect(s1.id).toBe("61dd0da80ec21141463430cf");
250
+ expect(s1.assetType).toBe("stock");
251
+ expect(s1.name).toBe("A1 Yenilenebilir Enerji");
252
+ expect(s1.symbol).toBe("A1YEN");
253
+ expect(s1.sectorId).toBe("65533e047844ee7afe9941c2");
254
+ expect(s1.industryId).toBe("65533e441fa5c7b58afa0985");
255
+ expect(s1.updatedDate).toBe("2025-07-28T09:06:04.286Z");
256
+ expect(s1.active).toBe(true);
201
257
  });
202
-
203
- test("should handle sort by price change", async () => {
204
- jest.spyOn(client, 'getCustomThemeDetail').mockResolvedValue(mockCustomThemeDetail);
205
-
206
- await client.getCustomThemeDetail("theme1", Locale.Tr, SortBy.PriceChange);
207
-
208
- expect(client.getCustomThemeDetail).toHaveBeenCalledWith("theme1", Locale.Tr, SortBy.PriceChange);
258
+
259
+ test("should include sortBy when provided", async () => {
260
+ cli.request.mockResolvedValueOnce({ data: mockCustomThemeDetail });
261
+
262
+ await client.getCustomThemeDetail(
263
+ "6888e18a6c84bcba9dc69ef7",
264
+ locale,
265
+ SortBy.PriceChange
266
+ );
267
+
268
+ expect(cli.request).toHaveBeenCalledTimes(1);
269
+ const call = cli.request.mock.calls[0][0];
270
+
271
+ expect(call.method).toBe("GET");
272
+ expect(call.url).toBe(
273
+ `/api/v1/${CollectionType.CustomTheme}/6888e18a6c84bcba9dc69ef7`
274
+ );
275
+ expect(call.params).toEqual({ locale, sortBy: SortBy.PriceChange });
209
276
  });
210
277
  });
211
-
212
278
  describe("createCustomTheme", () => {
213
- test("should create custom theme with mock data", async () => {
279
+ test("should call correct endpoint/body and return id", async () => {
214
280
  const createParams: CreateCustomThemeParams = {
215
- title: {
216
- [Locale.Tr]: "Yeni Tema",
217
- [Locale.En]: "New Theme"
218
- },
219
- description: {
220
- [Locale.Tr]: "Tema açıklaması",
221
- [Locale.En]: "Theme description"
222
- },
281
+ title: { [Locale.Tr]: "Test Custom Theme" },
282
+ description: { [Locale.Tr]: "Test Custom Theme Description" },
223
283
  region: [Region.Tr],
224
- image_url: "https://example.com/new-theme.jpg",
225
- avatar_url: "https://example.com/new-theme-avatar.jpg",
226
- stocks: [mockStocks[0].id, mockStocks[1].id],
227
- status: CollectionStatus.Active
284
+ image_url: "Test Custom Theme Image URL",
285
+ image: "Test Custom Theme Image",
286
+ avatar_url: "Test Custom Theme Avatar Image",
287
+ stocks: [
288
+ "648ab66e38daf3102a5a7401",
289
+ "61dd0da80ec21141463430cf",
290
+ ],
291
+ order: 0,
292
+ status: CollectionStatus.Active,
293
+ meta_data: { foo: "bar" },
228
294
  };
229
-
230
- jest.spyOn(client, 'createCustomTheme').mockResolvedValue("new-theme-id");
231
-
232
- const resp = await client.createCustomTheme(createParams);
233
-
234
- expect(resp).toBe("new-theme-id");
235
-
236
- expect(client.createCustomTheme).toHaveBeenCalledWith(createParams);
295
+
296
+ cli.request.mockResolvedValueOnce({ data: { id: "6888e18a6c84bcba9dc69ef7" } });
297
+
298
+ const id = await client.createCustomTheme(createParams);
299
+
300
+ expect(cli.request).toHaveBeenCalledTimes(1);
301
+ const call = cli.request.mock.calls[0][0];
302
+
303
+ expect(call.method).toBe("POST");
304
+ expect(call.url).toBe("/api/v1/custom-theme");
305
+ expect(call.data).toEqual(createParams);
306
+
307
+ expect(id).toBe("6888e18a6c84bcba9dc69ef7");
308
+ });
309
+
310
+ test("should bubble up request error", async () => {
311
+ const createParams: CreateCustomThemeParams = {
312
+ title: { [Locale.Tr]: "Test Custom Theme" },
313
+ stocks: ["648ab66e38daf3102a5a7401"],
314
+ status: CollectionStatus.Active,
315
+ };
316
+
317
+ cli.request.mockRejectedValueOnce(new Error("Validation error"));
318
+
319
+ await expect(client.createCustomTheme(createParams)).rejects.toThrow("Validation error");
237
320
  });
238
321
  });
239
-
322
+
240
323
  describe("updateCustomTheme", () => {
241
- test("should update custom theme with mock data", async () => {
324
+ test("should call correct endpoint/body (stockIds) and resolve", async () => {
242
325
  const updateParams: UpdateCustomThemeParams = {
243
- title: {
244
- [Locale.Tr]: "Güncellenmiş Tema",
245
- [Locale.En]: "Updated Theme"
246
- },
247
- stockIds: [mockStocks[0].id, mockStocks[2].id]
326
+ title: { [Locale.Tr]: "Test Custom Theme Title Updated" },
327
+ description: { [Locale.Tr]: "Test Custom Theme Description Updated" },
328
+ image_url: "Test Custom Theme Image URL Updated",
329
+ image: "Test Custom Theme Image Updated",
330
+ avatar_url: "Test Custom Theme Avatar Image Updated",
331
+ stockIds: [
332
+ "648ab66e38daf3102a5a7401",
333
+ "61dd0da80ec21141463430cf",
334
+ ],
335
+ status: CollectionStatus.Inactive,
336
+ meta_data: { hello: "world" },
248
337
  };
249
-
250
- jest.spyOn(client, 'updateCustomTheme').mockResolvedValue(undefined);
251
-
252
- await client.updateCustomTheme("theme1", updateParams);
253
-
254
- expect(client.updateCustomTheme).toHaveBeenCalledWith("theme1", updateParams);
338
+
339
+ cli.request.mockResolvedValueOnce({ data: undefined });
340
+
341
+ await client.updateCustomTheme("6888e18a6c84bcba9dc69ef7", updateParams);
342
+
343
+ expect(cli.request).toHaveBeenCalledTimes(1);
344
+ const call = cli.request.mock.calls[0][0];
345
+
346
+ expect(call.method).toBe("PATCH");
347
+ expect(call.url).toBe("/api/v1/custom-theme/6888e18a6c84bcba9dc69ef7");
348
+ expect(call.data).toEqual(updateParams);
349
+ });
350
+
351
+ test("should bubble up request error", async () => {
352
+ cli.request.mockRejectedValueOnce(new Error("Theme not found"));
353
+
354
+ await expect(
355
+ client.updateCustomTheme("invalid-theme", { status: CollectionStatus.Active })
356
+ ).rejects.toThrow("Theme not found");
255
357
  });
256
358
  });
257
-
359
+
258
360
  describe("deleteCustomTheme", () => {
259
- test("should delete custom theme", async () => {
260
- jest.spyOn(client, 'deleteCustomTheme').mockResolvedValue(undefined);
261
-
262
- await client.deleteCustomTheme("theme1");
263
-
264
- expect(client.deleteCustomTheme).toHaveBeenCalledWith("theme1");
361
+ test("should call correct endpoint and resolve", async () => {
362
+ cli.request.mockResolvedValueOnce({ data: undefined });
363
+
364
+ await client.deleteCustomTheme("6888e18a6c84bcba9dc69ef7");
365
+
366
+ expect(cli.request).toHaveBeenCalledTimes(1);
367
+ const call = cli.request.mock.calls[0][0];
368
+
369
+ expect(call.method).toBe("DELETE");
370
+ expect(call.url).toBe("/api/v1/custom-theme/6888e18a6c84bcba9dc69ef7");
265
371
  });
266
-
267
- test("should handle delete error", async () => {
268
- jest.spyOn(client, 'deleteCustomTheme').mockRejectedValue(new Error("Theme not found"));
269
-
270
- await expect(client.deleteCustomTheme("invalid-theme"))
271
- .rejects.toThrow("Theme not found");
372
+
373
+ test("should bubble up request error", async () => {
374
+ cli.request.mockRejectedValueOnce(new Error("Theme not found"));
375
+
376
+ await expect(client.deleteCustomTheme("invalid-theme")).rejects.toThrow("Theme not found");
272
377
  });
273
378
  });
379
+
274
380
  });
275
381
  });
276
382