UNPKG

laplace-api

Version:

Client library for Laplace API for the US stock market and BIST (Istanbul stock market) fundamental financial data.

303 lines (256 loc) 9.54 kB
import { Logger } from "winston"; import { LaplaceConfiguration } from "../utilities/configuration"; import { SearchClient, SearchType } from "../client/search"; import "./client_test_suite"; import { Region, Locale } from "../client/collections"; const mockStockSearchResponse = { stocks: [ { id: "61dd0d6f0ec2114146342fd0", name: "Tüpraş", title: "Türkiye Petrol Rafinerileri A.Ş.", region: Region.Tr, assetType: "stock", type: "equity" } ], industries: [], sectors: [], collections: [] }; const mockIndustrySearchResponse = { stocks: [], industries: [ { id: "ind123", title: "Hava Yolları Taşımacılığı", region: [Region.Tr], assetClass: "equity", imageUrl: "https://example.com/image.jpg", avatarUrl: "https://example.com/avatar.jpg" } ], sectors: [], collections: [] }; const mockAllTypesSearchResponse = { stocks: [ { id: "61dd0d6f0ec2114146342fd1", name: "Abbott", title: "Abbott Laboratories", region: Region.Us, assetType: "stock", type: "equity" } ], industries: [ { id: "ind456", title: "Abrasive Manufacturing", region: [Region.Us], assetClass: "equity", imageUrl: "https://example.com/image.jpg", avatarUrl: "https://example.com/avatar.jpg" } ], sectors: [ { id: "sec789", title: "Aerospace & Defense", region: [Region.Us], assetClass: "equity", imageUrl: "https://example.com/sector.jpg", avatarUrl: "https://example.com/sector-avatar.jpg" } ], collections: [ { id: "col123", title: "Artificial Intelligence", region: [Region.Us], assetClass: "equity", imageUrl: "https://example.com/collection.jpg", avatarUrl: "https://example.com/collection-avatar.jpg" } ] }; describe("Search", () => { let client: SearchClient; beforeAll(() => { const config = (global as any).testSuite.config as LaplaceConfiguration; const logger: Logger = { info: jest.fn(), error: jest.fn(), warn: jest.fn(), debug: jest.fn(), } as unknown as Logger; client = new SearchClient(config, logger); }); describe("Integration Tests", () => { test("SearchStock", async () => { const resp = await client.search("TUPRS", [SearchType.Stock], Locale.Tr, Region.Tr); expect(resp.stocks).not.toBeEmpty(); const firstResult = resp.stocks[0]; expect(typeof firstResult.id).toBe("string"); expect(typeof firstResult.name).toBe("string"); expect(typeof firstResult.title).toBe("string"); expect(typeof firstResult.region).toBe("string"); expect(typeof firstResult.assetType).toBe("string"); expect(typeof firstResult.type).toBe("string"); }); test("SearchIndustry", async () => { const resp = await client.search("Hava", [SearchType.Industry], Locale.Tr, Region.Tr); expect(resp.industries).not.toBeEmpty(); const firstResult = resp.industries[0]; expect(typeof firstResult.id).toBe("string"); expect(typeof firstResult.title).toBe("string"); expect(Array.isArray(firstResult.region)).toBe(true); expect(firstResult.region.length).toBeGreaterThan(0); firstResult.region.forEach((r: string) => expect(typeof r).toBe("string")); expect(typeof firstResult.assetClass).toBe("string"); expect(typeof firstResult.imageUrl).toBe("string"); expect(typeof firstResult.avatarUrl).toBe("string"); }); test("SearchAllTypes", async () => { const resp = await client.search( "Ab", [SearchType.Stock, SearchType.Industry, SearchType.Sector, SearchType.Collection], Locale.Tr, Region.Us ); const hasResults = (resp.stocks && resp.stocks.length > 0) || (resp.industries && resp.industries.length > 0) || (resp.sectors && resp.sectors.length > 0) || (resp.collections && resp.collections.length > 0); expect(hasResults).toBe(true); }); }); describe("Mock Tests (Data Injection)", () => { let client: SearchClient; let cli: { request: jest.Mock }; beforeEach(() => { cli = { request: jest.fn() }; const config = (global as any).testSuite.config as LaplaceConfiguration; const logger: Logger = { info: jest.fn(), error: jest.fn(), warn: jest.fn(), debug: jest.fn(), } as unknown as Logger; client = new SearchClient(config, logger, cli as any); }); function expectSearchCall(expected: { filter: string; types: SearchType[]; locale: Locale; region?: Region; page?: number; size?: number; }) { expect(cli.request).toHaveBeenCalledTimes(1); const call = cli.request.mock.calls[0][0]; expect(call.method).toBe("GET"); expect(call.url).toBe("/api/v1/search"); const expectedParams: any = { filter: expected.filter, types: expected.types.join(","), locale: expected.locale, }; if (expected.region != null) expectedParams.region = expected.region; if (expected.page != null) expectedParams.page = expected.page; if (expected.size != null) expectedParams.size = expected.size; expect(call.params).toEqual(expectedParams); } test("SearchStock: calls correct endpoint/params and matches raw response", async () => { cli.request.mockResolvedValueOnce({ data: mockStockSearchResponse }); const resp = await client.search("TUPRS", [SearchType.Stock], Locale.Tr, Region.Tr); expectSearchCall({ filter: "TUPRS", types: [SearchType.Stock], locale: Locale.Tr, region: Region.Tr, }); expect(resp.stocks).toHaveLength(1); const first = resp.stocks[0]; expect(first.id).toBe(mockStockSearchResponse.stocks[0].id); expect(first.name).toBe(mockStockSearchResponse.stocks[0].name); expect(first.title).toBe(mockStockSearchResponse.stocks[0].title); expect(first.region).toBe(mockStockSearchResponse.stocks[0].region); expect(first.assetType).toBe(mockStockSearchResponse.stocks[0].assetType); expect(first.type).toBe(mockStockSearchResponse.stocks[0].type); expect(resp.industries).toHaveLength(0); expect(resp.sectors).toHaveLength(0); expect(resp.collections).toHaveLength(0); }); test("SearchIndustry: calls correct endpoint/params and matches raw response", async () => { cli.request.mockResolvedValueOnce({ data: mockIndustrySearchResponse }); const resp = await client.search("Hava", [SearchType.Industry], Locale.Tr, Region.Tr); expectSearchCall({ filter: "Hava", types: [SearchType.Industry], locale: Locale.Tr, region: Region.Tr, }); expect(resp.industries).toHaveLength(1); const first = resp.industries[0]; expect(first.id).toBe(mockIndustrySearchResponse.industries[0].id); expect(first.title).toBe(mockIndustrySearchResponse.industries[0].title); expect(first.region).toEqual(mockIndustrySearchResponse.industries[0].region); expect(first.assetClass).toBe(mockIndustrySearchResponse.industries[0].assetClass); expect(first.imageUrl).toBe(mockIndustrySearchResponse.industries[0].imageUrl); expect(first.avatarUrl).toBe(mockIndustrySearchResponse.industries[0].avatarUrl); expect(resp.stocks).toHaveLength(0); expect(resp.sectors).toHaveLength(0); expect(resp.collections).toHaveLength(0); }); test("SearchAllTypes: calls correct endpoint/params and matches raw response", async () => { cli.request.mockResolvedValueOnce({ data: mockAllTypesSearchResponse }); const resp = await client.search( "Ab", [SearchType.Stock, SearchType.Industry, SearchType.Sector, SearchType.Collection], Locale.Tr, Region.Us ); expectSearchCall({ filter: "Ab", types: [SearchType.Stock, SearchType.Industry, SearchType.Sector, SearchType.Collection], locale: Locale.Tr, region: Region.Us, }); expect(resp.stocks).toHaveLength(1); expect(resp.industries).toHaveLength(1); expect(resp.sectors).toHaveLength(1); expect(resp.collections).toHaveLength(1); }); test("does not send optional params when undefined", async () => { cli.request.mockResolvedValueOnce({ data: mockStockSearchResponse }); await client.search("TUPRS", [SearchType.Stock], Locale.Tr); expectSearchCall({ filter: "TUPRS", types: [SearchType.Stock], locale: Locale.Tr, }); }); test("bubbles up request error", async () => { cli.request.mockRejectedValueOnce(new Error("Failed to search")); await expect(client.search("TUPRS", [SearchType.Stock], Locale.Tr, Region.Tr)).rejects.toThrow( "Failed to search" ); expect(cli.request).toHaveBeenCalledTimes(1); }); test("page=0 / size=0 should still be sent (guards against falsy spread bug)", async () => { cli.request.mockResolvedValueOnce({ data: mockStockSearchResponse }); await client.search("TUPRS", [SearchType.Stock], Locale.Tr, Region.Tr, 0, 10); expectSearchCall({ filter: "TUPRS", types: [SearchType.Stock], locale: Locale.Tr, region: Region.Tr, page: 0, size: 10, }); }); }); });