/** * Vitest unit tests for the system AI provider client helpers. * * Tests verify that getAiConfig, saveAiConfig, and testAiConnection * construct the correct fetch payloads (path, method, body, encoding). * * D-11 frontend coverage — CLAUDE.md mandate: every new function has at least one test. */ import { describe, it, expect, vi, beforeEach } from 'vitest' // ── Mock Pinia auth store (request() lazy-imports it) ──────────────────────── // The request() helper in client.js does: // const { useAuthStore } = await import('../stores/auth.js') // const authStore = useAuthStore() // We stub the module so it returns a store with no accessToken, // preventing Pinia initialization in unit tests. vi.mock('../src/stores/auth.js', () => ({ useAuthStore: () => ({ accessToken: null }), })) // ── Mock global fetch ───────────────────────────────────────────────────────── let fetchMock beforeEach(() => { fetchMock = vi.fn(() => Promise.resolve( new Response(JSON.stringify({ ok: true }), { status: 200, headers: { 'Content-Type': 'application/json' }, }) ) ) vi.stubGlobal('fetch', fetchMock) }) // ── Import helpers under test ───────────────────────────────────────────────── import { getAiConfig, saveAiConfig, testAiConnection } from '../src/api/client.js' // ── Tests ───────────────────────────────────────────────────────────────────── describe('getAiConfig', () => { it('issues GET /api/admin/ai-config', async () => { await getAiConfig() expect(fetchMock).toHaveBeenCalledOnce() const [url, init] = fetchMock.mock.calls[0] expect(url).toMatch(/\/api\/admin\/ai-config$/) expect(init.method).toBe('GET') }) }) describe('saveAiConfig', () => { it('issues PUT with JSON body containing provider_id and api_key', async () => { const payload = { provider_id: 'openai', api_key: 'sk-x' } await saveAiConfig(payload) expect(fetchMock).toHaveBeenCalledOnce() const [url, init] = fetchMock.mock.calls[0] expect(url).toMatch(/\/api\/admin\/ai-config$/) expect(init.method).toBe('PUT') expect(init.headers?.['Content-Type'] || init.headers?.get?.('Content-Type')).toBe('application/json') expect(JSON.parse(init.body)).toEqual({ provider_id: 'openai', api_key: 'sk-x' }) }) }) describe('testAiConnection', () => { it('issues GET with URL-encoded provider_id', async () => { // Provider ID with a space to verify encodeURIComponent is applied await testAiConnection('open ai') expect(fetchMock).toHaveBeenCalledOnce() const [url, init] = fetchMock.mock.calls[0] expect(url).toContain('/api/admin/ai-config/test-connection?provider_id=open%20ai') expect(init.method).toBe('GET') }) it('issues GET with a plain provider_id that needs no encoding', async () => { await testAiConnection('openai') const [url] = fetchMock.mock.calls[0] expect(url).toContain('/api/admin/ai-config/test-connection?provider_id=openai') }) })