import { describe, expect, test, jest, mock, beforeEach } from "bun:test"; import { ItemPriceData, fetchPrice, fetchKeyPrice } from '../src/content/priceService' import { PricesResponse, priceUsingPricesTF } from '../src/content/pricing/pricestf' import { getStorageValue, setStorageValue } from '../src/content/storage' import { defindex_key } from "../src/content/config"; // Mock the storage module mock.module('../src/content/storage', () => ({ getStorageValue: jest.fn(), setStorageValue: jest.fn() })) // Mock the pricing module mock.module('../src/content/pricing/pricestf', () => ({ priceUsingPricesTF: jest.fn() })) describe('Price Service', () => { const mockToken = 'test-token' const mockDefIndex = 105 // Brigade Helm const mockQuality = 11 // Strange const mockSku = `${mockDefIndex};${mockQuality}` const mockDate = new Date() const mockTtl = 30 * 60 * 1000 // 30 minutes const mockPriceResponse: PricesResponse = { keys: 1, metal: 21.33 } const mockKeyPriceResponse: PricesResponse = { keys: 0, metal: 60.11 } const mockCachedData: ItemPriceData = { sku: mockSku, update: new Date(Date.now() - 15 * 60 * 1000).getTime(), // 15 minutes ago ttl: mockTtl, keys: 1, metal: 21.11, scmPrice: 0 } beforeEach(() => { jest.clearAllMocks() }) test('fetchPrice returns cached data if available and not expired', async () => { (getStorageValue as jest.Mock).mockResolvedValue(mockCachedData) const result = await fetchPrice(mockToken, mockDefIndex + ";" + mockQuality) expect(getStorageValue).toHaveBeenCalledWith(expect.stringContaining(mockSku), null) expect(result).toEqual(mockCachedData) }) test('fetchPrice fetches new data when cache is expired', async () => { const expiredCache: ItemPriceData = { ...mockCachedData, update: new Date(Date.now() - 2 * mockTtl).getTime() }; (getStorageValue as jest.Mock).mockResolvedValue(expiredCache); (priceUsingPricesTF as jest.Mock).mockResolvedValue(mockPriceResponse); (chrome.runtime.sendMessage as jest.Fn).mockImplementation(() => mockPriceResponse); const result = await fetchPrice(mockToken, mockDefIndex + ";" + mockQuality) expect(setStorageValue).toHaveBeenCalled() expect(result.metal).not.toBe(mockCachedData.metal) expect(result.metal).toBe(mockPriceResponse.metal) }) test('fetchPrice rejects with 401 when no token provided', async () => { await expect(fetchPrice('', mockDefIndex + ";" + mockQuality)).rejects.toThrow() }) test('fetchPrice handles pricing API errors', async () => { (chrome.runtime.sendMessage as jest.Fn).mockResolvedValue(null); (priceUsingPricesTF as jest.Mock).mockImplementation(() => Promise.reject(new Error('500 Internal Server Error'))); (getStorageValue as jest.Mock).mockResolvedValue(null) await expect(fetchPrice(mockToken, mockDefIndex + ";" + mockQuality)).rejects.toThrow() }) test('fetchKeyPrice uses correct parameters', async () => { (getStorageValue as jest.Mock).mockResolvedValue(null); (priceUsingPricesTF as jest.Mock).mockResolvedValue(mockKeyPriceResponse); (chrome.runtime.sendMessage as jest.Fn).mockImplementation(() => mockKeyPriceResponse); const result = await fetchKeyPrice(mockToken) expect(result.keys).toBe(0) // A key cannot cost a key :P expect(result.metal).toBe(mockKeyPriceResponse.metal) }) test('ItemPriceData.toString() returns formatted string', () => { const data = new ItemPriceData() data.sku = mockSku data.update = mockDate.getTime() data.ttl = mockTtl data.keys = 1 data.metal = 10.66 data.scmPrice = 2.68 const result = data.toString() expect(result).toContain(`Price for ${mockSku}`) expect(result).toContain(mockDate.toString()) expect(result).toContain(new Date(mockDate.getTime() + mockTtl).toString()) expect(result).toContain(`"keys":${data.keys}`) expect(result).toContain(`"metal":${data.metal}`) expect(result).toContain(`"scmPrice":${data.scmPrice}`) }) })