import { describe, it, expect, vi, afterEach } from 'vitest'; import { createKillSwitchClient } from './index.js'; describe('createKillSwitchClient', () => { const baseConfig = { baseUrl: 'http://localhost:4003/api', productId: 'testapp', }; afterEach(() => { vi.restoreAllMocks(); }); it('should return disabled=false when app is not disabled', async () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ disabled: false, message: null }), }) ); const ks = createKillSwitchClient(baseConfig); const result = await ks.check(); expect(result.disabled).toBe(false); expect(result.message).toBeNull(); }); it('should return disabled=true with message when app is disabled', async () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ disabled: true, message: 'Maintenance in progress' }), }) ); const ks = createKillSwitchClient(baseConfig); const result = await ks.check(); expect(result.disabled).toBe(true); expect(result.message).toBe('Maintenance in progress'); }); it('should fail-open on network error', async () => { vi.stubGlobal('fetch', vi.fn().mockRejectedValue(new Error('network'))); const ks = createKillSwitchClient(baseConfig); const result = await ks.check(); expect(result.disabled).toBe(false); expect(result.message).toBeNull(); }); it('should fail-open on non-OK response', async () => { vi.stubGlobal( 'fetch', vi.fn().mockResolvedValue({ ok: false, status: 500, }) ); const ks = createKillSwitchClient(baseConfig); const result = await ks.check(); expect(result.disabled).toBe(false); }); it('should send correct product-id header', async () => { const fetchMock = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ disabled: false }), }); vi.stubGlobal('fetch', fetchMock); const ks = createKillSwitchClient(baseConfig); await ks.check(); expect(fetchMock).toHaveBeenCalledWith( expect.stringContaining('/flags/kill-switch'), expect.objectContaining({ headers: expect.objectContaining({ 'x-product-id': 'testapp' }), }) ); }); it('should include platform in query string', async () => { const fetchMock = vi.fn().mockResolvedValue({ ok: true, json: () => Promise.resolve({ disabled: false }), }); vi.stubGlobal('fetch', fetchMock); const ks = createKillSwitchClient({ ...baseConfig, platform: 'ios' }); await ks.check(); const url = fetchMock.mock.calls[0][0] as string; expect(url).toContain('platform=ios'); }); });