UNPKG

laplace-api

Version:

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

875 lines (725 loc) 29.9 kB
import { Logger } from "winston"; import { LaplaceConfiguration } from "../utilities/configuration"; import { StockClient, HistoricalPricePeriod, HistoricalPriceInterval, AssetClass, Stock, AssetType, Market, StockPriceGraph, MarketState, EarningsTranscriptWithSummary, EarningsTranscriptListItem } from "../client/stocks"; import "./client_test_suite"; import { Region, Locale } from "../client/collections"; import { PaginatedResponse } from "../client/capital_increase"; const mockStocksResponse: Stock[] = [ { id: "61dd0d6f0ec2114146342fd0", assetType: AssetType.Stock, name: "Tüpraş", symbol: "TUPRS", sectorId: "sector123", industryId: "industry456", updatedDate: "2024-03-14T10:00:00Z", dailyChange: 2.5, active: true }, { id: "61dd0d6f0ec2114146342fd1", assetType: AssetType.Stock, name: "Garanti Bankası", symbol: "GARAN", sectorId: "sector789", industryId: "industry101", updatedDate: "2024-03-14T10:00:00Z", dailyChange: -1.2, active: true } ]; const mockStockDetailResponse = { id: "61dd0d6f0ec2114146342fd0", assetType: AssetType.Stock, assetClass: AssetClass.Equity, name: "Tüpraş", symbol: "TUPRS", sectorId: "sector123", industryId: "industry456", updatedDate: "2024-03-14T10:00:00Z", dailyChange: 2.5, active: true, description: "Türkiye'nin en büyük rafineri şirketi", shortDescription: "Rafineri şirketi", region: Region.Tr, localized_description: { tr: "Türkiye'nin en büyük rafineri şirketi", en: "Turkey's largest refinery company" }, localizedShortDescription: { tr: "Rafineri şirketi", en: "Refinery company" }, markets: [Market.Yildiz] }; const mockHistoricalPricesResponse: StockPriceGraph[] = [ { symbol: "TUPRS", "1D": [ { d: 1710374400000, c: 425.5, h: 428.0, l: 422.0, o: 423.0 }, { d: 1710378000000, c: 426.8, h: 427.5, l: 425.0, o: 425.5 } ], "1W": [ { d: 1709856000000, c: 420.5, h: 422.0, l: 419.0, o: 419.5 }, { d: 1709942400000, c: 423.0, h: 424.5, l: 420.0, o: 420.5 } ], "1M": [ { d: 1707436800000, c: 415.0, h: 416.5, l: 414.0, o: 414.5 }, { d: 1707523200000, c: 417.2, h: 418.0, l: 415.0, o: 415.0 } ], "3M": [], "1Y": [], "2Y": [], "3Y": [], "5Y": [] } ]; const mockStockRestrictionsResponse = [ { id: 1, title: "Bedelli Sermaye Artırımı", description: "Şirket bedelli sermaye artırımı yapacaktır", symbol: "TUPRS", startDate: "2024-03-15T00:00:00Z", endDate: "2024-03-20T00:00:00Z", market: Market.Yildiz }, { id: 2, title: "Temettü Ödemesi", description: "Şirket temettü ödemesi yapacaktır", symbol: "TUPRS", startDate: "2024-04-01T00:00:00Z", endDate: "2024-04-01T00:00:00Z", market: Market.Yildiz } ]; const mockTickRulesResponse = { basePrice: 425.5, additionalPrice: 0.1, lowerPriceLimit: 382.95, upperPriceLimit: 468.05, rules: [ { priceFrom: 0, priceTo: 20, tickSize: 0.01 }, { priceFrom: 20, priceTo: 50, tickSize: 0.02 }, { priceFrom: 50, priceTo: 100, tickSize: 0.05 } ] }; const mockEarningsTranscriptList: EarningsTranscriptListItem[] = [ { symbol: "AAPL", year: 2024, quarter: 1, date: "2024-05-15", fiscal_year: 2024, }, { symbol: "AAPL", year: 2023, quarter: 4, date: "2024-02-20", fiscal_year: 2023 } ]; const mockEarningsTranscriptDetail: EarningsTranscriptWithSummary = { symbol: "AAPL", year: 2024, quarter: 1, date: "2024-05-15", content: "Q1 2024 earnings call transcript content...", summary: "Strong Q1 performance with 15% revenue growth", has_summary: true }; const mockMarketStates: MarketState[] = [ { id: 1, marketSymbol: "BIST", state: "OPEN", lastTimestamp: "2024-03-14T10:00:00Z", stockSymbol: "TUPRS" }, { id: 2, marketSymbol: "BIST", state: "CLOSED", lastTimestamp: "2024-03-14T18:00:00Z", stockSymbol: "GARAN" } ]; const mockPaginatedMarketStates: PaginatedResponse<MarketState> = { recordCount: 2, items: mockMarketStates }; const mockSingleMarketState: MarketState = { id: 1, marketSymbol: "BIST", state: "OPEN", lastTimestamp: "2024-03-14T10:00:00Z", stockSymbol: "TUPRS" }; const mockChartImageBlob = new Blob(['mock chart image data'], { type: 'image/png' }); describe("Stocks Client", () => { let client: StockClient; 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 StockClient(config, logger); }); describe("Integration Tests", () => { describe("getAllStocks", () => { test("should return stocks list for TR region", async () => { const resp = await client.getAllStocks(Region.Tr); expect(resp).not.toBeEmpty(); const firstStock = resp[0]; expect(typeof firstStock.id).toBe("string"); expect(typeof firstStock.assetType).toBe("string"); expect(typeof firstStock.name).toBe("string"); expect(typeof firstStock.symbol).toBe("string"); expect(typeof firstStock.sectorId).toBe("string"); expect(typeof firstStock.industryId).toBe("string"); expect(typeof firstStock.updatedDate).toBe("string"); expect(typeof firstStock.active).toBe("boolean"); if (firstStock.dailyChange !== undefined) { expect(typeof firstStock.dailyChange).toBe("number"); } }); test("should handle pagination correctly", async () => { const resp = await client.getAllStocks(Region.Tr, 10, 10); expect(resp).not.toBeEmpty(); expect(resp.length).toBeLessThanOrEqual(10); }); }); describe("getStockDetailById", () => { test("should return stock detail by ID", async () => { const resp = await client.getStockDetailById( "61dd0d6f0ec2114146342fd0", Locale.Tr ); expect(resp).toBeDefined(); expect(typeof resp.id).toBe("string"); expect(typeof resp.assetClass).toBe("string"); expect(typeof resp.description).toBe("string"); expect(typeof resp.shortDescription).toBe("string"); expect(typeof resp.region).toBe("string"); expect(typeof resp.localized_description).toBe("object"); expect(typeof resp.localizedShortDescription).toBe("object"); if (resp.markets) { expect(Array.isArray(resp.markets)).toBe(true); } }); }); describe("getStockDetailBySymbol", () => { test("should return stock detail by symbol", async () => { const resp = await client.getStockDetailBySymbol( "TUPRS", AssetClass.Equity, Region.Tr, Locale.Tr ); expect(resp).toBeDefined(); expect(resp.symbol).toBe("TUPRS"); expect(typeof resp.assetClass).toBe("string"); expect(typeof resp.description).toBe("string"); expect(typeof resp.region).toBe("string"); }); }); describe("getHistoricalPrices", () => { test("should return historical prices for multiple symbols", async () => { const resp = await client.getHistoricalPrices( ["TUPRS", "SASA"], Region.Tr, [ HistoricalPricePeriod.OneDay, HistoricalPricePeriod.OneWeek, HistoricalPricePeriod.OneMonth, ] ); expect(resp).not.toBeEmpty(); const firstPriceGraph = resp[0]; expect(typeof firstPriceGraph.symbol).toBe("string"); expect(Array.isArray(firstPriceGraph["1D"])).toBe(true); expect(Array.isArray(firstPriceGraph["1W"])).toBe(true); expect(Array.isArray(firstPriceGraph["1M"])).toBe(true); if (firstPriceGraph["1D"].length > 0) { const firstDataPoint = firstPriceGraph["1D"][0]; expect(typeof firstDataPoint.d).toBe("number"); expect(typeof firstDataPoint.c).toBe("number"); expect(typeof firstDataPoint.h).toBe("number"); expect(typeof firstDataPoint.l).toBe("number"); expect(typeof firstDataPoint.o).toBe("number"); } }); }); describe("getCustomHistoricalPrices", () => { test("should return custom historical prices", async () => { const resp = await client.getCustomHistoricalPrices( "TUPRS", Region.Tr, "2024-01-01", "2024-03-01", HistoricalPriceInterval.OneDay, false ); expect(resp).not.toBeEmpty(); const firstDataPoint = resp[0]; expect(typeof firstDataPoint.d).toBe("number"); expect(typeof firstDataPoint.c).toBe("number"); expect(typeof firstDataPoint.h).toBe("number"); expect(typeof firstDataPoint.l).toBe("number"); expect(typeof firstDataPoint.o).toBe("number"); }); test("should handle detailed historical prices", async () => { const resp = await client.getCustomHistoricalPrices( "SASA", Region.Tr, "2024-01-01 10:00:00", "2024-01-05 10:00:00", HistoricalPriceInterval.OneHour, true ); expect(resp).not.toBeEmpty(); }); }); describe("getStockRestrictions", () => { test("should return stock restrictions for specific symbol", async () => { const resp = await client.getStockRestrictions("TUPRS", Region.Tr); if (resp && resp.length > 0) { const firstRestriction = resp[0]; expect(typeof firstRestriction.id).toBe("number"); expect(typeof firstRestriction.title).toBe("string"); expect(typeof firstRestriction.description).toBe("string"); expect(typeof firstRestriction.startDate).toBe("string"); expect(typeof firstRestriction.endDate).toBe("string"); if (firstRestriction.symbol) { expect(typeof firstRestriction.symbol).toBe("string"); } if (firstRestriction.market) { expect(typeof firstRestriction.market).toBe("string"); } } }); }); describe("getAllStockRestrictions", () => { test("should return all stock restrictions for region", async () => { const resp = await client.getAllStockRestrictions(Region.Tr); expect(Array.isArray(resp)).toBe(true); if (resp.length > 0) { const firstRestriction = resp[0]; expect(typeof firstRestriction.id).toBe("number"); expect(typeof firstRestriction.title).toBe("string"); expect(typeof firstRestriction.description).toBe("string"); expect(typeof firstRestriction.startDate).toBe("string"); expect(typeof firstRestriction.endDate).toBe("string"); } }); }); describe("getTickRules", () => { test("should return tick rules for symbol", async () => { const resp = await client.getTickRules("TUPRS", Region.Tr); expect(resp).toBeDefined(); expect(typeof resp.basePrice).toBe("number"); expect(typeof resp.additionalPrice).toBe("number"); expect(typeof resp.lowerPriceLimit).toBe("number"); expect(typeof resp.upperPriceLimit).toBe("number"); if (resp.rules !== null) { expect(Array.isArray(resp.rules)).toBe(true); } }); }); describe("getEarningsTranscripts", () => { test("should return earnings transcript list", async () => { const resp = await client.getEarningsTranscripts("AAPL", Region.Us); expect(Array.isArray(resp)).toBe(true); if (resp.length > 0) { const firstTranscript = resp[0]; expect(typeof firstTranscript.symbol).toBe("string"); expect(typeof firstTranscript.year).toBe("number"); expect(typeof firstTranscript.quarter).toBe("number"); expect(typeof firstTranscript.date).toBe("string"); expect(typeof firstTranscript.fiscal_year).toBe("number"); } }); }); describe("getEarningsTranscript", () => { test("should return earnings transcript detail", async () => { const resp = await client.getEarningsTranscript("AAPL", 2023, 4); expect(resp).toBeDefined(); expect(typeof resp.symbol).toBe("string"); expect(typeof resp.year).toBe("number"); expect(typeof resp.quarter).toBe("number"); expect(typeof resp.date).toBe("string"); expect(typeof resp.content).toBe("string"); expect(typeof resp.has_summary).toBe("boolean"); if (resp.summary) { expect(typeof resp.summary).toBe("string"); } }); }); describe("getStockStateAll", () => { test("should return paginated stock states", async () => { const resp = await client.getStockStateAll(0, 10, Region.Tr); expect(resp).toBeDefined(); expect(Array.isArray(resp.items)).toBe(true); expect(typeof resp.recordCount).toBe("number"); if (resp.items.length > 0) { const firstState = resp.items[0]; expect(typeof firstState.id).toBe("number"); expect(typeof firstState.state).toBe("string"); expect(typeof firstState.lastTimestamp).toBe("string"); } }); }); describe("getStockState", () => { test("should return single stock state", async () => { const resp = await client.getStockState("TUPRS"); expect(resp).toBeDefined(); expect(typeof resp.id).toBe("number"); expect(typeof resp.state).toBe("string"); expect(typeof resp.lastTimestamp).toBe("string"); if (resp.stockSymbol) { expect(typeof resp.stockSymbol).toBe("string"); } if (resp.marketSymbol) { expect(typeof resp.marketSymbol).toBe("string"); } }); }); describe("getStateAll", () => { test("should return paginated market states", async () => { const resp = await client.getStateAll(0, 10, Region.Tr); expect(resp).toBeDefined(); expect(Array.isArray(resp.items)).toBe(true); expect(typeof resp.recordCount).toBe("number"); if (resp.items.length > 0) { const firstState = resp.items[0]; expect(typeof firstState.id).toBe("number"); expect(typeof firstState.state).toBe("string"); expect(typeof firstState.lastTimestamp).toBe("string"); } }); }); describe("getState", () => { test("should return single market state", async () => { const resp = await client.getState("BIST"); expect(resp).toBeDefined(); expect(typeof resp.id).toBe("number"); expect(typeof resp.state).toBe("string"); expect(typeof resp.lastTimestamp).toBe("string"); if (resp.marketSymbol) { expect(typeof resp.marketSymbol).toBe("string"); } }); }); describe("getStockChartImage", () => { test("should return chart image blob", async () => { const resp = await client.getStockChartImage({ symbol: "TUPRS", region: Region.Tr, }); expect(resp).toBeDefined(); expect(resp).toBeInstanceOf(Blob); expect(resp.size).toBeGreaterThan(0); }, 10000); }); }); describe("Mock Tests", () => { beforeEach(() => { jest.clearAllMocks(); }); describe("getAllStocks", () => { test("should handle getAllStocks response correctly with mock data", async () => { jest.spyOn(client, 'getAllStocks').mockResolvedValue(mockStocksResponse); const resp = await client.getAllStocks(Region.Tr); expect(resp).toHaveLength(2); const firstStock = resp[0]; expect(firstStock.id).toBe("61dd0d6f0ec2114146342fd0"); expect(firstStock.assetType).toBe(AssetType.Stock); expect(firstStock.name).toBe("Tüpraş"); expect(firstStock.symbol).toBe("TUPRS"); expect(firstStock.sectorId).toBe("sector123"); expect(firstStock.industryId).toBe("industry456"); expect(firstStock.updatedDate).toBe("2024-03-14T10:00:00Z"); expect(firstStock.dailyChange).toBe(2.5); expect(firstStock.active).toBe(true); const secondStock = resp[1]; expect(secondStock.id).toBe("61dd0d6f0ec2114146342fd1"); expect(secondStock.symbol).toBe("GARAN"); expect(secondStock.dailyChange).toBe(-1.2); expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr); }); test("should handle pagination correctly with mock data", async () => { jest.spyOn(client, 'getAllStocks').mockResolvedValue([mockStocksResponse[0]]); const resp = await client.getAllStocks(Region.Tr, 1, 0); expect(resp).toHaveLength(1); expect(resp[0].symbol).toBe("TUPRS"); expect(client.getAllStocks).toHaveBeenCalledWith(Region.Tr, 1, 0); }); test("should handle API errors correctly", async () => { jest.spyOn(client, 'getAllStocks').mockRejectedValue(new Error("API Error")); await expect(client.getAllStocks(Region.Tr)).rejects.toThrow("API Error"); }); }); describe("getStockDetailById", () => { test("should return stock detail by ID with mock data", async () => { jest.spyOn(client, 'getStockDetailById').mockResolvedValue(mockStockDetailResponse); const resp = await client.getStockDetailById("61dd0d6f0ec2114146342fd0", Locale.Tr); expect(resp).toBeDefined(); expect(resp.id).toBe("61dd0d6f0ec2114146342fd0"); expect(resp.assetType).toBe(AssetType.Stock); expect(resp.assetClass).toBe(AssetClass.Equity); expect(resp.description).toBe("Türkiye'nin en büyük rafineri şirketi"); expect(resp.shortDescription).toBe("Rafineri şirketi"); expect(resp.region).toBe(Region.Tr); expect(resp.localized_description).toEqual({ tr: "Türkiye'nin en büyük rafineri şirketi", en: "Turkey's largest refinery company" }); expect(resp.localizedShortDescription).toEqual({ tr: "Rafineri şirketi", en: "Refinery company" }); expect(resp.markets).toEqual([Market.Yildiz]); expect(client.getStockDetailById).toHaveBeenCalledWith("61dd0d6f0ec2114146342fd0", Locale.Tr); }); test("should handle API errors for stock detail", async () => { jest.spyOn(client, 'getStockDetailById').mockRejectedValue(new Error("Stock not found")); await expect(client.getStockDetailById("invalid_id", Locale.Tr)) .rejects.toThrow("Stock not found"); }); }); describe("getHistoricalPrices", () => { test("should return historical prices for multiple symbols with mock data", async () => { jest.spyOn(client, 'getHistoricalPrices').mockResolvedValue(mockHistoricalPricesResponse); const symbols = ["TUPRS"]; const periods = [ HistoricalPricePeriod.OneDay, HistoricalPricePeriod.OneWeek, HistoricalPricePeriod.OneMonth ]; const resp = await client.getHistoricalPrices(symbols, Region.Tr, periods); expect(resp).toHaveLength(1); const firstPriceGraph = resp[0]; expect(firstPriceGraph.symbol).toBe("TUPRS"); expect(firstPriceGraph["1D"]).toHaveLength(2); const firstDayPoint = firstPriceGraph["1D"][0]; expect(firstDayPoint.d).toBe(1710374400000); expect(firstDayPoint.c).toBe(425.5); expect(firstDayPoint.h).toBe(428.0); expect(firstDayPoint.l).toBe(422.0); expect(firstDayPoint.o).toBe(423.0); expect(firstPriceGraph["1W"]).toHaveLength(2); expect(firstPriceGraph["1M"]).toHaveLength(2); expect(client.getHistoricalPrices).toHaveBeenCalledWith( symbols, Region.Tr, periods ); }); test("should handle API errors for historical prices", async () => { jest.spyOn(client, 'getHistoricalPrices').mockRejectedValue(new Error("Failed to fetch historical prices")); await expect(client.getHistoricalPrices( ["TUPRS"], Region.Tr, [HistoricalPricePeriod.OneDay] )).rejects.toThrow("Failed to fetch historical prices"); }); }); describe("getStockRestrictions", () => { test("should return stock restrictions with mock data", async () => { jest.spyOn(client, 'getStockRestrictions').mockResolvedValue(mockStockRestrictionsResponse); const resp = await client.getStockRestrictions("TUPRS", Region.Tr); expect(resp).toHaveLength(2); const firstRestriction = resp[0]; expect(firstRestriction.id).toBe(1); expect(firstRestriction.title).toBe("Bedelli Sermaye Artırımı"); expect(firstRestriction.description).toBe("Şirket bedelli sermaye artırımı yapacaktır"); expect(firstRestriction.symbol).toBe("TUPRS"); expect(firstRestriction.startDate).toBe("2024-03-15T00:00:00Z"); expect(firstRestriction.endDate).toBe("2024-03-20T00:00:00Z"); expect(firstRestriction.market).toBe(Market.Yildiz); expect(client.getStockRestrictions).toHaveBeenCalledWith("TUPRS", Region.Tr); }); test("should handle API errors for stock restrictions", async () => { jest.spyOn(client, 'getStockRestrictions').mockRejectedValue(new Error("Failed to fetch restrictions")); await expect(client.getStockRestrictions("TUPRS", Region.Tr)) .rejects.toThrow("Failed to fetch restrictions"); }); }); describe("getTickRules", () => { test("should return tick rules with mock data", async () => { jest.spyOn(client, 'getTickRules').mockResolvedValue(mockTickRulesResponse); const resp = await client.getTickRules("TUPRS", Region.Tr); expect(resp.basePrice).toBe(425.5); expect(resp.additionalPrice).toBe(0.1); expect(resp.lowerPriceLimit).toBe(382.95); expect(resp.upperPriceLimit).toBe(468.05); expect(resp.rules).toHaveLength(3); const firstRule = resp.rules![0]; expect(firstRule.priceFrom).toBe(0); expect(firstRule.priceTo).toBe(20); expect(firstRule.tickSize).toBe(0.01); expect(client.getTickRules).toHaveBeenCalledWith("TUPRS", Region.Tr); }); test("should handle API errors for tick rules", async () => { jest.spyOn(client, 'getTickRules').mockRejectedValue(new Error("Failed to fetch tick rules")); await expect(client.getTickRules("TUPRS", Region.Tr)) .rejects.toThrow("Failed to fetch tick rules"); }); }); describe("getEarningsTranscripts", () => { test("should return earnings transcript list with mock data", async () => { jest.spyOn(client, 'getEarningsTranscripts').mockResolvedValue(mockEarningsTranscriptList); const resp = await client.getEarningsTranscripts("AAPL", Region.Us); expect(resp).toHaveLength(2); const firstTranscript = resp[0]; expect(firstTranscript.symbol).toBe("AAPL"); expect(firstTranscript.year).toBe(2024); expect(firstTranscript.quarter).toBe(1); expect(firstTranscript.date).toBe("2024-05-15"); expect(firstTranscript.fiscal_year).toBe(2024); const secondTranscript = resp[1]; expect(secondTranscript.year).toBe(2023); expect(secondTranscript.quarter).toBe(4); expect(client.getEarningsTranscripts).toHaveBeenCalledWith( "AAPL", Region.Us ); }); test("should handle API errors for earnings transcripts", async () => { jest.spyOn(client, 'getEarningsTranscripts').mockRejectedValue(new Error("Transcripts not found")); await expect( client.getEarningsTranscripts("INVALID", Region.Us) ).rejects.toThrow("Transcripts not found"); }); }); describe("getEarningsTranscript", () => { test("should return earnings transcript detail with mock data", async () => { jest.spyOn(client, 'getEarningsTranscript').mockResolvedValue(mockEarningsTranscriptDetail); const resp = await client.getEarningsTranscript("AAPL", 2024, 1); expect(resp.symbol).toBe("AAPL"); expect(resp.year).toBe(2024); expect(resp.quarter).toBe(1); expect(resp.date).toBe("2024-05-15"); expect(resp.content).toBe("Q1 2024 earnings call transcript content..."); expect(resp.summary).toBe("Strong Q1 performance with 15% revenue growth"); expect(resp.has_summary).toBe(true); expect(client.getEarningsTranscript).toHaveBeenCalledWith( "AAPL", 2024, 1 ); }); test("should handle API errors for earnings transcript detail", async () => { jest.spyOn(client, 'getEarningsTranscript').mockRejectedValue(new Error("Transcript not found")); await expect( client.getEarningsTranscript("AAPL", 2020, 1) ).rejects.toThrow("Transcript not found"); }); }); describe("getStockStateAll", () => { test("should return paginated stock states with mock data", async () => { jest.spyOn(client, 'getStockStateAll').mockResolvedValue(mockPaginatedMarketStates); const resp = await client.getStockStateAll(0, 10, Region.Tr); expect(resp.items).toHaveLength(2); expect(resp.recordCount).toBe(2); const firstState = resp.items[0]; expect(firstState.id).toBe(1); expect(firstState.marketSymbol).toBe("BIST"); expect(firstState.state).toBe("OPEN"); expect(firstState.stockSymbol).toBe("TUPRS"); expect(client.getStockStateAll).toHaveBeenCalledWith(0, 10, Region.Tr); }); test("should handle API errors for stock state all", async () => { jest.spyOn(client, 'getStockStateAll').mockRejectedValue(new Error("Failed to fetch stock states")); await expect(client.getStockStateAll(0, 10, Region.Tr)) .rejects.toThrow("Failed to fetch stock states"); }); }); describe("getStockState", () => { test("should return single stock state with mock data", async () => { jest.spyOn(client, 'getStockState').mockResolvedValue(mockSingleMarketState); const resp = await client.getStockState("TUPRS"); expect(resp.id).toBe(1); expect(resp.marketSymbol).toBe("BIST"); expect(resp.state).toBe("OPEN"); expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z"); expect(resp.stockSymbol).toBe("TUPRS"); expect(client.getStockState).toHaveBeenCalledWith("TUPRS"); }); test("should handle API errors for single stock state", async () => { jest.spyOn(client, 'getStockState').mockRejectedValue(new Error("Stock state not found")); await expect(client.getStockState("INVALID")) .rejects.toThrow("Stock state not found"); }); }); describe("getStateAll", () => { test("should return paginated market states with mock data", async () => { jest.spyOn(client, 'getStateAll').mockResolvedValue(mockPaginatedMarketStates); const resp = await client.getStateAll(0, 10, Region.Tr); expect(resp.items).toHaveLength(2); expect(resp.recordCount).toBe(2); const firstState = resp.items[0]; expect(firstState.state).toBe("OPEN"); expect(firstState.lastTimestamp).toBe("2024-03-14T10:00:00Z"); expect(client.getStateAll).toHaveBeenCalledWith(0, 10, Region.Tr); }); test("should handle API errors for state all", async () => { jest.spyOn(client, 'getStateAll').mockRejectedValue(new Error("Failed to fetch states")); await expect(client.getStateAll(0, 10, Region.Tr)) .rejects.toThrow("Failed to fetch states"); }); }); describe("getState", () => { test("should return single market state with mock data", async () => { jest.spyOn(client, 'getState').mockResolvedValue(mockSingleMarketState); const resp = await client.getState("BIST"); expect(resp.id).toBe(1); expect(resp.marketSymbol).toBe("BIST"); expect(resp.state).toBe("OPEN"); expect(resp.lastTimestamp).toBe("2024-03-14T10:00:00Z"); expect(client.getState).toHaveBeenCalledWith("BIST"); }); test("should handle API errors for single state", async () => { jest.spyOn(client, 'getState').mockRejectedValue(new Error("Market state not found")); await expect(client.getState("INVALID")) .rejects.toThrow("Market state not found"); }); }); describe("getStockChartImage", () => { test("should return chart image with mock data", async () => { jest.spyOn(client, 'getStockChartImage').mockResolvedValue(mockChartImageBlob); const resp = await client.getStockChartImage({ symbol: "TUPRS", region: Region.Tr, }); expect(resp).toBeDefined(); expect(resp).toBeInstanceOf(Blob); expect(resp.type).toBe('image/png'); }); test("should handle API errors for chart image", async () => { jest.spyOn(client, 'getStockChartImage').mockRejectedValue(new Error("Failed to generate chart")); await expect(client.getStockChartImage({ symbol: "INVALID", region: Region.Tr })).rejects.toThrow("Failed to generate chart"); }); }); }); });