fix: test

This commit is contained in:
Louis 2025-08-21 12:01:45 +07:00
parent cfbc6b9150
commit 8de5c1709b
No known key found for this signature in database
GPG Key ID: 44FA9F4D33C37DE2
3 changed files with 71 additions and 150 deletions

View File

@ -5,7 +5,6 @@ import SettingsMenu from '../SettingsMenu'
import { useNavigate, useMatches } from '@tanstack/react-router' import { useNavigate, useMatches } from '@tanstack/react-router'
import { useGeneralSetting } from '@/hooks/useGeneralSetting' import { useGeneralSetting } from '@/hooks/useGeneralSetting'
import { useModelProvider } from '@/hooks/useModelProvider' import { useModelProvider } from '@/hooks/useModelProvider'
import { useAppState } from '@/hooks/useAppState'
// Mock dependencies // Mock dependencies
vi.mock('@tanstack/react-router', () => ({ vi.mock('@tanstack/react-router', () => ({
@ -25,9 +24,7 @@ vi.mock('@/i18n/react-i18next-compat', () => ({
})) }))
vi.mock('@/hooks/useGeneralSetting', () => ({ vi.mock('@/hooks/useGeneralSetting', () => ({
useGeneralSetting: vi.fn(() => ({ useGeneralSetting: vi.fn(() => ({})),
experimentalFeatures: false,
})),
})) }))
vi.mock('@/hooks/useModelProvider', () => ({ vi.mock('@/hooks/useModelProvider', () => ({
@ -88,21 +85,6 @@ describe('SettingsMenu', () => {
expect(screen.getByText('common:local_api_server')).toBeInTheDocument() expect(screen.getByText('common:local_api_server')).toBeInTheDocument()
expect(screen.getByText('common:https_proxy')).toBeInTheDocument() expect(screen.getByText('common:https_proxy')).toBeInTheDocument()
expect(screen.getByText('common:extensions')).toBeInTheDocument() expect(screen.getByText('common:extensions')).toBeInTheDocument()
})
it('does not show MCP Servers when experimental features disabled', () => {
render(<SettingsMenu />)
expect(screen.queryByText('common:mcp-servers')).not.toBeInTheDocument()
})
it('shows MCP Servers when experimental features enabled', () => {
vi.mocked(useGeneralSetting).mockReturnValue({
experimentalFeatures: true,
})
render(<SettingsMenu />)
expect(screen.getByText('common:mcp-servers')).toBeInTheDocument() expect(screen.getByText('common:mcp-servers')).toBeInTheDocument()
}) })
@ -110,7 +92,7 @@ describe('SettingsMenu', () => {
render(<SettingsMenu />) render(<SettingsMenu />)
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
expect(chevron).toBeInTheDocument() expect(chevron).toBeInTheDocument()
@ -121,7 +103,7 @@ describe('SettingsMenu', () => {
render(<SettingsMenu />) render(<SettingsMenu />)
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
if (!chevron) throw new Error('Chevron button not found') if (!chevron) throw new Error('Chevron button not found')
@ -159,12 +141,14 @@ describe('SettingsMenu', () => {
// First expand the providers submenu // First expand the providers submenu
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
if (chevron) await user.click(chevron) if (chevron) await user.click(chevron)
const openaiProvider = screen.getByTestId('provider-avatar-openai').closest('div') const openaiProvider = screen
.getByTestId('provider-avatar-openai')
.closest('div')
expect(openaiProvider).toBeInTheDocument() expect(openaiProvider).toBeInTheDocument()
}) })
@ -174,14 +158,16 @@ describe('SettingsMenu', () => {
// First expand the providers // First expand the providers
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
if (!chevron) throw new Error('Chevron button not found') if (!chevron) throw new Error('Chevron button not found')
await user.click(chevron) await user.click(chevron)
// Then click on a provider // Then click on a provider
const openaiProvider = screen.getByTestId('provider-avatar-openai').closest('div') const openaiProvider = screen
.getByTestId('provider-avatar-openai')
.closest('div')
await user.click(openaiProvider!) await user.click(openaiProvider!)
expect(mockNavigate).toHaveBeenCalledWith({ expect(mockNavigate).toHaveBeenCalledWith({
@ -193,7 +179,9 @@ describe('SettingsMenu', () => {
it('shows mobile menu toggle button', () => { it('shows mobile menu toggle button', () => {
render(<SettingsMenu />) render(<SettingsMenu />)
const menuToggle = screen.getByRole('button', { name: 'Toggle settings menu' }) const menuToggle = screen.getByRole('button', {
name: 'Toggle settings menu',
})
expect(menuToggle).toBeInTheDocument() expect(menuToggle).toBeInTheDocument()
}) })
@ -201,7 +189,9 @@ describe('SettingsMenu', () => {
const user = userEvent.setup() const user = userEvent.setup()
render(<SettingsMenu />) render(<SettingsMenu />)
const menuToggle = screen.getByRole('button', { name: 'Toggle settings menu' }) const menuToggle = screen.getByRole('button', {
name: 'Toggle settings menu',
})
await user.click(menuToggle) await user.click(menuToggle)
// Menu should now be visible // Menu should now be visible
@ -214,7 +204,9 @@ describe('SettingsMenu', () => {
render(<SettingsMenu />) render(<SettingsMenu />)
// Open menu first // Open menu first
const menuToggle = screen.getByRole('button', { name: 'Toggle settings menu' }) const menuToggle = screen.getByRole('button', {
name: 'Toggle settings menu',
})
await user.click(menuToggle) await user.click(menuToggle)
// Then close it // Then close it
@ -239,7 +231,7 @@ describe('SettingsMenu', () => {
// First expand the providers submenu // First expand the providers submenu
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
if (chevron) await user.click(chevron) if (chevron) await user.click(chevron)
@ -273,12 +265,14 @@ describe('SettingsMenu', () => {
// Expand providers // Expand providers
const chevronButtons = screen.getAllByRole('button') const chevronButtons = screen.getAllByRole('button')
const chevron = chevronButtons.find(button => const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right') button.querySelector('svg.tabler-icon-chevron-right')
) )
if (chevron) await user.click(chevron) if (chevron) await user.click(chevron)
expect(screen.getByTestId('provider-avatar-openai')).toBeInTheDocument() expect(screen.getByTestId('provider-avatar-openai')).toBeInTheDocument()
expect(screen.queryByTestId('provider-avatar-anthropic')).not.toBeInTheDocument() expect(
screen.queryByTestId('provider-avatar-anthropic')
).not.toBeInTheDocument()
}) })
}) })

View File

@ -40,7 +40,6 @@ describe('useGeneralSetting', () => {
useGeneralSetting.setState({ useGeneralSetting.setState({
currentLanguage: 'en', currentLanguage: 'en',
spellCheckChatInput: true, spellCheckChatInput: true,
experimentalFeatures: false,
huggingfaceToken: undefined, huggingfaceToken: undefined,
}) })
@ -60,11 +59,9 @@ describe('useGeneralSetting', () => {
expect(result.current.currentLanguage).toBe('en') expect(result.current.currentLanguage).toBe('en')
expect(result.current.spellCheckChatInput).toBe(true) expect(result.current.spellCheckChatInput).toBe(true)
expect(result.current.experimentalFeatures).toBe(false)
expect(result.current.huggingfaceToken).toBeUndefined() expect(result.current.huggingfaceToken).toBeUndefined()
expect(typeof result.current.setCurrentLanguage).toBe('function') expect(typeof result.current.setCurrentLanguage).toBe('function')
expect(typeof result.current.setSpellCheckChatInput).toBe('function') expect(typeof result.current.setSpellCheckChatInput).toBe('function')
expect(typeof result.current.setExperimentalFeatures).toBe('function')
expect(typeof result.current.setHuggingfaceToken).toBe('function') expect(typeof result.current.setHuggingfaceToken).toBe('function')
}) })
@ -155,42 +152,6 @@ describe('useGeneralSetting', () => {
}) })
}) })
describe('setExperimentalFeatures', () => {
it('should enable experimental features', () => {
const { result } = renderHook(() => useGeneralSetting())
act(() => {
result.current.setExperimentalFeatures(true)
})
expect(result.current.experimentalFeatures).toBe(true)
})
it('should disable experimental features', () => {
const { result } = renderHook(() => useGeneralSetting())
act(() => {
result.current.setExperimentalFeatures(false)
})
expect(result.current.experimentalFeatures).toBe(false)
})
it('should toggle experimental features multiple times', () => {
const { result } = renderHook(() => useGeneralSetting())
act(() => {
result.current.setExperimentalFeatures(true)
})
expect(result.current.experimentalFeatures).toBe(true)
act(() => {
result.current.setExperimentalFeatures(false)
})
expect(result.current.experimentalFeatures).toBe(false)
})
})
describe('setHuggingfaceToken', () => { describe('setHuggingfaceToken', () => {
it('should set huggingface token', () => { it('should set huggingface token', () => {
const { result } = renderHook(() => useGeneralSetting()) const { result } = renderHook(() => useGeneralSetting())
@ -254,7 +215,7 @@ describe('useGeneralSetting', () => {
expect(mockGetByName).toHaveBeenCalledWith('@janhq/download-extension') expect(mockGetByName).toHaveBeenCalledWith('@janhq/download-extension')
// Wait for async operations // Wait for async operations
await new Promise(resolve => setTimeout(resolve, 0)) await new Promise((resolve) => setTimeout(resolve, 0))
expect(mockGetSettings).toHaveBeenCalled() expect(mockGetSettings).toHaveBeenCalled()
expect(mockUpdateSettings).toHaveBeenCalledWith([ expect(mockUpdateSettings).toHaveBeenCalledWith([
@ -272,13 +233,11 @@ describe('useGeneralSetting', () => {
act(() => { act(() => {
result1.current.setCurrentLanguage('id') result1.current.setCurrentLanguage('id')
result1.current.setSpellCheckChatInput(false) result1.current.setSpellCheckChatInput(false)
result1.current.setExperimentalFeatures(true)
result1.current.setHuggingfaceToken('shared-token') result1.current.setHuggingfaceToken('shared-token')
}) })
expect(result2.current.currentLanguage).toBe('id') expect(result2.current.currentLanguage).toBe('id')
expect(result2.current.spellCheckChatInput).toBe(false) expect(result2.current.spellCheckChatInput).toBe(false)
expect(result2.current.experimentalFeatures).toBe(true)
expect(result2.current.huggingfaceToken).toBe('shared-token') expect(result2.current.huggingfaceToken).toBe('shared-token')
}) })
}) })
@ -290,13 +249,11 @@ describe('useGeneralSetting', () => {
act(() => { act(() => {
result.current.setCurrentLanguage('vn') result.current.setCurrentLanguage('vn')
result.current.setSpellCheckChatInput(false) result.current.setSpellCheckChatInput(false)
result.current.setExperimentalFeatures(true)
result.current.setHuggingfaceToken('complex-token-123') result.current.setHuggingfaceToken('complex-token-123')
}) })
expect(result.current.currentLanguage).toBe('vn') expect(result.current.currentLanguage).toBe('vn')
expect(result.current.spellCheckChatInput).toBe(false) expect(result.current.spellCheckChatInput).toBe(false)
expect(result.current.experimentalFeatures).toBe(true)
expect(result.current.huggingfaceToken).toBe('complex-token-123') expect(result.current.huggingfaceToken).toBe('complex-token-123')
}) })
@ -314,11 +271,9 @@ describe('useGeneralSetting', () => {
// Second update // Second update
act(() => { act(() => {
result.current.setExperimentalFeatures(true)
result.current.setHuggingfaceToken('sequential-token') result.current.setHuggingfaceToken('sequential-token')
}) })
expect(result.current.experimentalFeatures).toBe(true)
expect(result.current.huggingfaceToken).toBe('sequential-token') expect(result.current.huggingfaceToken).toBe('sequential-token')
// Third update // Third update

View File

@ -61,8 +61,6 @@ vi.mock('@/hooks/useGeneralSetting', () => ({
useGeneralSetting: () => ({ useGeneralSetting: () => ({
spellCheckChatInput: true, spellCheckChatInput: true,
setSpellCheckChatInput: vi.fn(), setSpellCheckChatInput: vi.fn(),
experimentalFeatures: false,
setExperimentalFeatures: vi.fn(),
huggingfaceToken: 'test-token', huggingfaceToken: 'test-token',
setHuggingfaceToken: vi.fn(), setHuggingfaceToken: vi.fn(),
}), }),
@ -188,10 +186,12 @@ vi.mock('@tauri-apps/plugin-opener', () => ({
})) }))
vi.mock('@tauri-apps/api/webviewWindow', () => { vi.mock('@tauri-apps/api/webviewWindow', () => {
const MockWebviewWindow = vi.fn().mockImplementation((label: string, options: any) => ({ const MockWebviewWindow = vi
once: vi.fn(), .fn()
setFocus: vi.fn(), .mockImplementation((label: string, options: any) => ({
})) once: vi.fn(),
setFocus: vi.fn(),
}))
MockWebviewWindow.getByLabel = vi.fn().mockReturnValue(null) MockWebviewWindow.getByLabel = vi.fn().mockReturnValue(null)
return { return {
@ -299,16 +299,6 @@ describe('General Settings Route', () => {
// expect(screen.getByTestId('language-switcher')).toBeInTheDocument() // expect(screen.getByTestId('language-switcher')).toBeInTheDocument()
// }) // })
it('should render switches for experimental features and spell check', async () => {
const Component = GeneralRoute.component as React.ComponentType
await act(async () => {
render(<Component />)
})
const switches = screen.getAllByTestId('switch')
expect(switches.length).toBeGreaterThanOrEqual(2)
})
it('should render huggingface token input', async () => { it('should render huggingface token input', async () => {
const Component = GeneralRoute.component as React.ComponentType const Component = GeneralRoute.component as React.ComponentType
await act(async () => { await act(async () => {
@ -336,24 +326,6 @@ describe('General Settings Route', () => {
expect(switches[0]).toBeInTheDocument() expect(switches[0]).toBeInTheDocument()
}) })
it('should handle experimental features toggle', async () => {
const Component = GeneralRoute.component as React.ComponentType
await act(async () => {
render(<Component />)
})
const switches = screen.getAllByTestId('switch')
expect(switches.length).toBeGreaterThan(0)
// Test that switches are interactive
if (switches.length > 1) {
await act(async () => {
fireEvent.click(switches[1])
})
expect(switches[1]).toBeInTheDocument()
}
})
it('should handle huggingface token change', async () => { it('should handle huggingface token change', async () => {
const Component = GeneralRoute.component as React.ComponentType const Component = GeneralRoute.component as React.ComponentType
await act(async () => { await act(async () => {