290 lines
8.3 KiB
TypeScript
290 lines
8.3 KiB
TypeScript
import { describe, it, expect, beforeEach, vi } from 'vitest'
|
|
import { renderHook, act } from '@testing-library/react'
|
|
import { useGeneralSetting } from '../useGeneralSetting'
|
|
|
|
// Mock constants
|
|
vi.mock('@/constants/localStorage', () => ({
|
|
localStorageKey: {
|
|
settingGeneral: 'general-settings',
|
|
},
|
|
}))
|
|
|
|
// Mock zustand persist
|
|
vi.mock('zustand/middleware', () => ({
|
|
persist: (fn: any) => fn,
|
|
createJSONStorage: () => ({
|
|
getItem: vi.fn(),
|
|
setItem: vi.fn(),
|
|
removeItem: vi.fn(),
|
|
}),
|
|
}))
|
|
|
|
// Mock ExtensionManager
|
|
vi.mock('@/lib/extension', () => ({
|
|
ExtensionManager: {
|
|
getInstance: vi.fn(),
|
|
},
|
|
}))
|
|
|
|
describe('useGeneralSetting', () => {
|
|
let mockExtensionManager: any
|
|
|
|
beforeEach(async () => {
|
|
vi.clearAllMocks()
|
|
|
|
// Get the mocked ExtensionManager
|
|
const { ExtensionManager } = await import('@/lib/extension')
|
|
mockExtensionManager = ExtensionManager
|
|
|
|
// Reset store state to defaults
|
|
useGeneralSetting.setState({
|
|
currentLanguage: 'en',
|
|
spellCheckChatInput: true,
|
|
huggingfaceToken: undefined,
|
|
})
|
|
|
|
// Setup default mock behavior to prevent errors
|
|
const mockGetByName = vi.fn().mockReturnValue({
|
|
getSettings: vi.fn().mockResolvedValue(null),
|
|
updateSettings: vi.fn(),
|
|
})
|
|
|
|
mockExtensionManager.getInstance.mockReturnValue({
|
|
getByName: mockGetByName,
|
|
})
|
|
})
|
|
|
|
it('should initialize with default values', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
expect(result.current.currentLanguage).toBe('en')
|
|
expect(result.current.spellCheckChatInput).toBe(true)
|
|
expect(result.current.huggingfaceToken).toBeUndefined()
|
|
expect(typeof result.current.setCurrentLanguage).toBe('function')
|
|
expect(typeof result.current.setSpellCheckChatInput).toBe('function')
|
|
expect(typeof result.current.setHuggingfaceToken).toBe('function')
|
|
})
|
|
|
|
describe('setCurrentLanguage', () => {
|
|
it('should set language to English', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('en')
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('en')
|
|
})
|
|
|
|
it('should set language to Indonesian', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('id')
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('id')
|
|
})
|
|
|
|
it('should set language to Vietnamese', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('vn')
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('vn')
|
|
})
|
|
|
|
it('should change language multiple times', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('id')
|
|
})
|
|
expect(result.current.currentLanguage).toBe('id')
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('vn')
|
|
})
|
|
expect(result.current.currentLanguage).toBe('vn')
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('en')
|
|
})
|
|
expect(result.current.currentLanguage).toBe('en')
|
|
})
|
|
})
|
|
|
|
describe('setSpellCheckChatInput', () => {
|
|
it('should enable spell check', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setSpellCheckChatInput(true)
|
|
})
|
|
|
|
expect(result.current.spellCheckChatInput).toBe(true)
|
|
})
|
|
|
|
it('should disable spell check', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setSpellCheckChatInput(false)
|
|
})
|
|
|
|
expect(result.current.spellCheckChatInput).toBe(false)
|
|
})
|
|
|
|
it('should toggle spell check multiple times', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setSpellCheckChatInput(false)
|
|
})
|
|
expect(result.current.spellCheckChatInput).toBe(false)
|
|
|
|
act(() => {
|
|
result.current.setSpellCheckChatInput(true)
|
|
})
|
|
expect(result.current.spellCheckChatInput).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('setHuggingfaceToken', () => {
|
|
it('should set huggingface token', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('test-token-123')
|
|
})
|
|
|
|
expect(result.current.huggingfaceToken).toBe('test-token-123')
|
|
})
|
|
|
|
it('should update huggingface token', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('old-token')
|
|
})
|
|
expect(result.current.huggingfaceToken).toBe('old-token')
|
|
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('new-token')
|
|
})
|
|
expect(result.current.huggingfaceToken).toBe('new-token')
|
|
})
|
|
|
|
it('should handle empty token', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('')
|
|
})
|
|
|
|
expect(result.current.huggingfaceToken).toBe('')
|
|
})
|
|
|
|
it('should call ExtensionManager when setting token', async () => {
|
|
const mockSettings = [
|
|
{ key: 'hf-token', controllerProps: { value: 'old-value' } },
|
|
{ key: 'other-setting', controllerProps: { value: 'other-value' } },
|
|
]
|
|
|
|
const mockGetByName = vi.fn()
|
|
const mockGetSettings = vi.fn().mockResolvedValue(mockSettings)
|
|
const mockUpdateSettings = vi.fn()
|
|
|
|
mockExtensionManager.getInstance.mockReturnValue({
|
|
getByName: mockGetByName,
|
|
})
|
|
mockGetByName.mockReturnValue({
|
|
getSettings: mockGetSettings,
|
|
updateSettings: mockUpdateSettings,
|
|
})
|
|
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('new-token')
|
|
})
|
|
|
|
expect(mockExtensionManager.getInstance).toHaveBeenCalled()
|
|
expect(mockGetByName).toHaveBeenCalledWith('@janhq/download-extension')
|
|
|
|
// Wait for async operations
|
|
await new Promise((resolve) => setTimeout(resolve, 0))
|
|
|
|
expect(mockGetSettings).toHaveBeenCalled()
|
|
expect(mockUpdateSettings).toHaveBeenCalledWith([
|
|
{ key: 'hf-token', controllerProps: { value: 'new-token' } },
|
|
{ key: 'other-setting', controllerProps: { value: 'other-value' } },
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('state management', () => {
|
|
it('should maintain state across multiple hook instances', () => {
|
|
const { result: result1 } = renderHook(() => useGeneralSetting())
|
|
const { result: result2 } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result1.current.setCurrentLanguage('id')
|
|
result1.current.setSpellCheckChatInput(false)
|
|
result1.current.setHuggingfaceToken('shared-token')
|
|
})
|
|
|
|
expect(result2.current.currentLanguage).toBe('id')
|
|
expect(result2.current.spellCheckChatInput).toBe(false)
|
|
expect(result2.current.huggingfaceToken).toBe('shared-token')
|
|
})
|
|
})
|
|
|
|
describe('complex scenarios', () => {
|
|
it('should handle complete settings configuration', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
act(() => {
|
|
result.current.setCurrentLanguage('vn')
|
|
result.current.setSpellCheckChatInput(false)
|
|
result.current.setHuggingfaceToken('complex-token-123')
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('vn')
|
|
expect(result.current.spellCheckChatInput).toBe(false)
|
|
expect(result.current.huggingfaceToken).toBe('complex-token-123')
|
|
})
|
|
|
|
it('should handle multiple sequential updates', () => {
|
|
const { result } = renderHook(() => useGeneralSetting())
|
|
|
|
// First update
|
|
act(() => {
|
|
result.current.setCurrentLanguage('id')
|
|
result.current.setSpellCheckChatInput(false)
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('id')
|
|
expect(result.current.spellCheckChatInput).toBe(false)
|
|
|
|
// Second update
|
|
act(() => {
|
|
result.current.setHuggingfaceToken('sequential-token')
|
|
})
|
|
|
|
expect(result.current.huggingfaceToken).toBe('sequential-token')
|
|
|
|
// Third update
|
|
act(() => {
|
|
result.current.setCurrentLanguage('en')
|
|
result.current.setSpellCheckChatInput(true)
|
|
})
|
|
|
|
expect(result.current.currentLanguage).toBe('en')
|
|
expect(result.current.spellCheckChatInput).toBe(true)
|
|
})
|
|
})
|
|
})
|