- guard confirmByok() against byok-ack POST failure (leave modal open on error) - fix drag reorder to use ID-based index lookup (not filtered-list index) - guard cancelByok() against empty snapshot - add LlmConfigPayload Pydantic model for PUT endpoint - add test for confirmByok() failure path
73 lines
3.3 KiB
TypeScript
73 lines
3.3 KiB
TypeScript
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
|
import { setActivePinia, createPinia } from 'pinia'
|
|
import { useSystemStore } from './system'
|
|
|
|
vi.mock('../../composables/useApi', () => ({ useApiFetch: vi.fn() }))
|
|
import { useApiFetch } from '../../composables/useApi'
|
|
const mockFetch = vi.mocked(useApiFetch)
|
|
|
|
describe('useSystemStore — BYOK gate', () => {
|
|
beforeEach(() => { setActivePinia(createPinia()); vi.clearAllMocks() })
|
|
|
|
it('save() proceeds without modal when no cloud backends enabled', async () => {
|
|
mockFetch.mockResolvedValue({ data: { ok: true }, error: null })
|
|
const store = useSystemStore()
|
|
store.backends = [{ id: 'ollama', enabled: true, priority: 1 }]
|
|
store.byokAcknowledged = []
|
|
await store.trySave()
|
|
expect(store.byokPending).toHaveLength(0)
|
|
expect(mockFetch).toHaveBeenCalledWith('/api/settings/system/llm', expect.anything())
|
|
})
|
|
|
|
it('save() sets byokPending when new cloud backend enabled', async () => {
|
|
const store = useSystemStore()
|
|
store.backends = [{ id: 'anthropic', enabled: true, priority: 1 }]
|
|
store.byokAcknowledged = []
|
|
await store.trySave()
|
|
expect(store.byokPending).toContain('anthropic')
|
|
expect(mockFetch).not.toHaveBeenCalledWith('/api/settings/system/llm', expect.anything())
|
|
})
|
|
|
|
it('save() skips modal for already-acknowledged backends', async () => {
|
|
mockFetch.mockResolvedValue({ data: { ok: true }, error: null })
|
|
const store = useSystemStore()
|
|
store.backends = [{ id: 'anthropic', enabled: true, priority: 1 }]
|
|
store.byokAcknowledged = ['anthropic']
|
|
await store.trySave()
|
|
expect(store.byokPending).toHaveLength(0)
|
|
})
|
|
|
|
it('confirmByok() saves acknowledgment then commits LLM config', async () => {
|
|
mockFetch.mockResolvedValue({ data: { ok: true }, error: null })
|
|
const store = useSystemStore()
|
|
store.byokPending = ['anthropic']
|
|
store.backends = [{ id: 'anthropic', enabled: true, priority: 1 }]
|
|
await store.confirmByok()
|
|
expect(mockFetch).toHaveBeenCalledWith('/api/settings/system/llm/byok-ack', expect.anything())
|
|
expect(mockFetch).toHaveBeenCalledWith('/api/settings/system/llm', expect.anything())
|
|
})
|
|
|
|
it('confirmByok() sets saveError and leaves modal open when ack POST fails', async () => {
|
|
mockFetch.mockResolvedValue({ data: null, error: 'Network error' })
|
|
const store = useSystemStore()
|
|
store.byokPending = ['anthropic']
|
|
store.backends = [{ id: 'anthropic', enabled: true, priority: 1 }]
|
|
await store.confirmByok()
|
|
expect(store.saveError).toBeTruthy()
|
|
expect(store.byokPending).toContain('anthropic') // modal stays open
|
|
expect(mockFetch).not.toHaveBeenCalledWith('/api/settings/system/llm', expect.anything())
|
|
})
|
|
|
|
it('cancelByok() clears pending and restores backends to pre-save state', async () => {
|
|
mockFetch.mockResolvedValue({ data: { ok: true }, error: null })
|
|
const store = useSystemStore()
|
|
const original = [{ id: 'ollama', enabled: true, priority: 1 }]
|
|
store.backends = [...original]
|
|
await store.trySave() // captures snapshot, commits (no cloud backends)
|
|
store.backends = [{ id: 'anthropic', enabled: true, priority: 1 }]
|
|
store.byokPending = ['anthropic']
|
|
store.cancelByok()
|
|
expect(store.byokPending).toHaveLength(0)
|
|
expect(store.backends).toEqual(original)
|
|
})
|
|
})
|