import { describe, expect, test, mock } from "bun:test"; import { ItemSchema, ItemSlot, getItemIndexByName, getTradableStatusByDefindex, getTradableStatusByName, linkFestiveVariants, prepareSchema } from '../src/content/schemaService' // Mock the storage and log functions mock.module('../src/content/storage', () => ({ setStorageValue: mock(async (key: string, value: any) => {}), getStorageValue: mock(async (key: string, defaultValue: any) => defaultValue) })); mock.module('../src/content/utils/log', () => ({ logDebug: mock(() => {}), log: mock(() => {}), logError: mock(() => {}) })); const mockSchema: ItemSchema = { '21': { name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: false, hasAustraliumVariant: false, canKillstreakify: true, festiveVariant: null }, '208': { name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: true, canKillstreakify: true, festiveVariant: 659 }, '659': { name: 'Festive Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: false, canKillstreakify: true, festiveVariant: null }, '5021': { name: 'Mann Co. Supply Crate Key', slot: ItemSlot.Tool, tradable: true, hasAustraliumVariant: false, canKillstreakify: false, festiveVariant: null }, '15141': { name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: false, canKillstreakify: true, festiveVariant: null }, '69420': { name: 'Non-Tradable Item', slot: ItemSlot.Misc, tradable: false, hasAustraliumVariant: false, canKillstreakify: false, festiveVariant: null } } describe('Schema Service', () => { test('getItemIndexByName returns correct defindex', () => { expect(getItemIndexByName(mockSchema, 'Flame Thrower')).toBe(208) expect(getItemIndexByName(mockSchema, 'Mann Co. Supply Crate Key')).toBe(5021) expect(getItemIndexByName(mockSchema, 'Non-Existent Item')).toBeNull() }) test('getTradableStatusByDefindex returns correct status', () => { expect(getTradableStatusByDefindex(mockSchema, 208)).toBe(true) expect(getTradableStatusByDefindex(mockSchema, 5021)).toBe(true) expect(getTradableStatusByDefindex(mockSchema, 69420)).toBe(false) expect(() => getTradableStatusByDefindex(mockSchema, 999)).toThrow() }) test('getTradableStatusByName returns correct status', () => { expect(getTradableStatusByName(mockSchema, 'Flame Thrower')).toBe(true) expect(getTradableStatusByName(mockSchema, 'Mann Co. Supply Crate Key')).toBe(true) expect(getTradableStatusByName(mockSchema, 'Non-Tradable Item')).toBe(false) expect(getTradableStatusByName(mockSchema, 'Non-Existent Item')).toBe(true) }) test('prepareSchema fetches and processes schema correctly', async () => { // Mock GM_fetch response const mockResponse = { ok: true, json: async () => [ { defindex: 1, item_name: 'Test Item', item_slot: 'misc', attributes: [ { "name": "cannot trade", "class": "cannot_trade", "value": 1 } ], capabilities: {} }, { defindex: 208, item_name: 'Flame Thrower', item_slot: 'primary', capabilities: { can_killstreakify: true } } ] }; // Mock GM_fetch globalThis.GM_fetch = mock(async () => mockResponse); const result = await prepareSchema(); expect(result).toEqual({ '1': { name: 'Test Item', slot: ItemSlot.Misc, tradable: false, canKillstreakify: false, hasAustraliumVariant: false }, '208': { name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: true, canKillstreakify: true, hasAustraliumVariant: true } }); }); describe('linkFestiveVariants', () => { test('should link festive variants to their original counterparts', () => { const testSchema = { '21': { // Stock (should be ignored) name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: false, hasAustraliumVariant: false, canKillstreakify: false, festiveVariant: null }, '208': { // Original Flame Thrower name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: true, canKillstreakify: true, festiveVariant: null }, '659': { // Festive Flame Thrower (should be detected) name: 'Festive Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: false, canKillstreakify: true, festiveVariant: null }, '15141': { // Decorated (should be ignored) name: 'Flame Thrower', slot: ItemSlot.Primary, tradable: true, hasAustraliumVariant: false, canKillstreakify: true, festiveVariant: null } }; const mockResponseItems = [ { item_class: 'tf_weapon_flamethrower', defindex: 21, item_name: 'Flame Thrower' }, // Incorrect; stock { item_class: 'tf_weapon_flamethrower', defindex: 208, item_name: 'Flame Thrower' }, // Original { item_class: 'tf_weapon_flamethrower', defindex: 659, item_name: 'Festive Flame Thrower' }, // Festive { item_class: 'tf_weapon_flamethrower', defindex: 15141, item_name: 'Flame Thrower' }, // Incorrect; decorated ]; linkFestiveVariants(mockResponseItems, testSchema) expect(testSchema['21'].festiveVariant).toBeNull() expect(testSchema['208'].festiveVariant).toBe(659) expect(testSchema['659'].festiveVariant).toBeNull(); expect(testSchema['15141'].festiveVariant).toBeNull() }) test('should not link if no festive variant exists', () => { const testSchema = { '163': { name: 'Crit-a-Cola', slot: ItemSlot.Secondary, tradable: true, hasAustraliumVariant: false, canKillstreakify: false, festiveVariant: null } }; const mockResponseItems = [ { item_class: 'tf_weapon_lunchbox_drink', defindex: 163, item_name: 'Crit-a-Cola' } ]; linkFestiveVariants(mockResponseItems, testSchema); expect(testSchema['163'].festiveVariant).toBeNull(); }); }); })