jan/web-app/src/hooks/__tests__/useLlamacppDevices.test.ts
2025-09-30 21:48:38 +07:00

158 lines
4.3 KiB
TypeScript

import { renderHook, act } from '@testing-library/react'
import { describe, it, expect, vi, beforeEach } from 'vitest'
import { useLlamacppDevices } from '../useLlamacppDevices'
// Mock the ServiceHub
const mockGetLlamacppDevices = vi.fn()
vi.mock('@/hooks/useServiceHub', () => ({
getServiceHub: () => ({
hardware: () => ({
getLlamacppDevices: mockGetLlamacppDevices,
}),
providers: () => ({
updateSettings: vi.fn().mockResolvedValue(undefined),
}),
}),
}))
// Mock useModelProvider
const mockUpdateProvider = vi.fn()
vi.mock('../useModelProvider', () => ({
useModelProvider: {
getState: () => ({
getProviderByName: () => ({
settings: [
{
key: 'device',
controller_props: { value: '' },
},
],
}),
updateProvider: mockUpdateProvider,
}),
},
}))
// Mock the window.core object
Object.defineProperty(window, 'core', {
value: {
extensionManager: {
getByName: vi.fn(),
},
},
writable: true,
})
describe('useLlamacppDevices', () => {
beforeEach(() => {
vi.clearAllMocks()
})
it('should initialize with default state', () => {
const { result } = renderHook(() => useLlamacppDevices())
expect(result.current.devices).toEqual([])
expect(result.current.loading).toBe(false)
expect(result.current.error).toBeNull()
expect(typeof result.current.fetchDevices).toBe('function')
expect(typeof result.current.clearError).toBe('function')
expect(typeof result.current.setDevices).toBe('function')
expect(typeof result.current.toggleDevice).toBe('function')
})
it('should fetch devices successfully with activation status', async () => {
const mockDevices = [
{ id: 'CUDA0', name: 'NVIDIA GeForce RTX 4090', mem: 24576, free: 20480 },
{ id: 'CUDA1', name: 'NVIDIA GeForce RTX 3080', mem: 10240, free: 8192 },
]
mockGetLlamacppDevices.mockResolvedValue(mockDevices)
const { result } = renderHook(() => useLlamacppDevices())
await act(async () => {
await result.current.fetchDevices()
})
// Should have devices with activated property (empty setting means all activated)
expect(result.current.devices).toEqual([
{ ...mockDevices[0], activated: true },
{ ...mockDevices[1], activated: true },
])
expect(result.current.loading).toBe(false)
expect(result.current.error).toBeNull()
expect(mockGetLlamacppDevices).toHaveBeenCalledOnce()
})
it('should clear error', () => {
const { result } = renderHook(() => useLlamacppDevices())
// Set an error first
act(() => {
result.current.setDevices([])
})
// Clear the error
act(() => {
result.current.clearError()
})
expect(result.current.error).toBeNull()
})
it('should set devices directly', () => {
const mockDevices = [
{ id: 'CUDA0', name: 'NVIDIA GeForce RTX 4090', mem: 24576, free: 20480 },
]
const { result } = renderHook(() => useLlamacppDevices())
act(() => {
result.current.setDevices(mockDevices)
})
expect(result.current.devices).toEqual(mockDevices)
})
it('should toggle device activation', async () => {
const { result } = renderHook(() => useLlamacppDevices())
// Set initial devices with activation status
act(() => {
result.current.setDevices([
{ id: 'CUDA0', name: 'NVIDIA GeForce RTX 4090', mem: 24576, free: 20480, activated: false },
{ id: 'CUDA1', name: 'NVIDIA GeForce RTX 3080', mem: 10240, free: 8192, activated: false },
])
})
// Toggle a device on
await act(async () => {
await result.current.toggleDevice('CUDA0')
})
expect(result.current.devices[0].activated).toBe(true)
expect(result.current.devices[1].activated).toBe(false)
// Toggle the same device off
await act(async () => {
await result.current.toggleDevice('CUDA0')
})
expect(result.current.devices[0].activated).toBe(false)
expect(result.current.devices[1].activated).toBe(false)
// Toggle multiple devices
await act(async () => {
await result.current.toggleDevice('CUDA0')
})
await act(async () => {
await result.current.toggleDevice('CUDA1')
})
expect(result.current.devices[0].activated).toBe(true)
expect(result.current.devices[1].activated).toBe(true)
})
})