Files
tf2wikipricing/__tests__/priceService.test.ts
2025-05-01 18:31:58 -04:00

112 lines
4.0 KiB
TypeScript

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}`)
})
})