import { describe, it, expect, vi, afterEach } from 'vitest'; import { loadConfig, DEFAULT_RENDER } from './config'; function mockFetch(body: unknown, ok = true) { vi.stubGlobal('fetch', vi.fn().mockResolvedValue({ ok, json: () => Promise.resolve(body), })); } afterEach(() => vi.unstubAllGlobals()); describe('loadConfig', () => { it('loads stream URL and fills render defaults', async () => { mockFetch({ streamUrl: 'http://cam/stream' }); const cfg = await loadConfig('config.json'); expect(cfg.streamUrl).toBe('http://cam/stream'); expect(cfg.renderDefaults).toEqual(DEFAULT_RENDER); expect(cfg.calibration).toBeNull(); }); it('keeps a valid calibration', async () => { const calibration = { imagePoints: [[0, 0], [1, 0], [1, 1], [0, 1]], machinePoints: [[0, 0], [1, 0], [1, 1], [0, 1]], homography: [1, 0, 0, 0, 1, 0, 0, 0, 1], }; mockFetch({ streamUrl: 'x', calibration }); const cfg = await loadConfig('config.json'); expect(cfg.calibration).toEqual(calibration); }); it('drops a malformed calibration to null', async () => { mockFetch({ streamUrl: 'x', calibration: { homography: [1, 2, 3] } }); const cfg = await loadConfig('config.json'); expect(cfg.calibration).toBeNull(); }); it('throws when the request fails', async () => { mockFetch({}, false); await expect(loadConfig('config.json')).rejects.toThrow(); }); it('ignores malformed renderDefaults fields, keeping defaults and dropping extras', async () => { mockFetch({ streamUrl: 'x', renderDefaults: { lineWidth: 'thick', cutColor: '#abc', bogus: true } }); const cfg = await loadConfig('config.json'); expect(cfg.renderDefaults.cutColor).toBe('#abc'); // valid string kept expect(cfg.renderDefaults.lineWidth).toBe(DEFAULT_RENDER.lineWidth); // invalid number → default expect(cfg.renderDefaults.rapidColor).toBe(DEFAULT_RENDER.rapidColor); // missing → default expect(cfg.renderDefaults).not.toHaveProperty('bogus'); // extra key dropped }); it('rejects a calibration whose homography contains NaN', async () => { const calibration = { imagePoints: [[0, 0], [1, 0], [1, 1], [0, 1]], machinePoints: [[0, 0], [1, 0], [1, 1], [0, 1]], homography: [1, 0, 0, 0, 1, 0, 0, 0, NaN], }; mockFetch({ streamUrl: 'x', calibration }); const cfg = await loadConfig('config.json'); expect(cfg.calibration).toBeNull(); }); });