diff --git a/web-app/src/containers/__tests__/SettingsMenu.test.tsx b/web-app/src/containers/__tests__/SettingsMenu.test.tsx
index 14b7bfca7..56a73fbb8 100644
--- a/web-app/src/containers/__tests__/SettingsMenu.test.tsx
+++ b/web-app/src/containers/__tests__/SettingsMenu.test.tsx
@@ -5,7 +5,6 @@ import SettingsMenu from '../SettingsMenu'
import { useNavigate, useMatches } from '@tanstack/react-router'
import { useGeneralSetting } from '@/hooks/useGeneralSetting'
import { useModelProvider } from '@/hooks/useModelProvider'
-import { useAppState } from '@/hooks/useAppState'
// Mock dependencies
vi.mock('@tanstack/react-router', () => ({
@@ -25,9 +24,7 @@ vi.mock('@/i18n/react-i18next-compat', () => ({
}))
vi.mock('@/hooks/useGeneralSetting', () => ({
- useGeneralSetting: vi.fn(() => ({
- experimentalFeatures: false,
- })),
+ useGeneralSetting: vi.fn(() => ({})),
}))
vi.mock('@/hooks/useModelProvider', () => ({
@@ -71,14 +68,14 @@ describe('SettingsMenu', () => {
beforeEach(() => {
vi.clearAllMocks()
-
+
vi.mocked(useNavigate).mockReturnValue(mockNavigate)
vi.mocked(useMatches).mockReturnValue(mockMatches)
})
it('renders all menu items', () => {
render()
-
+
expect(screen.getByText('common:general')).toBeInTheDocument()
expect(screen.getByText('common:appearance')).toBeInTheDocument()
expect(screen.getByText('common:privacy')).toBeInTheDocument()
@@ -88,29 +85,14 @@ describe('SettingsMenu', () => {
expect(screen.getByText('common:local_api_server')).toBeInTheDocument()
expect(screen.getByText('common:https_proxy')).toBeInTheDocument()
expect(screen.getByText('common:extensions')).toBeInTheDocument()
- })
-
- it('does not show MCP Servers when experimental features disabled', () => {
- render()
-
- expect(screen.queryByText('common:mcp-servers')).not.toBeInTheDocument()
- })
-
- it('shows MCP Servers when experimental features enabled', () => {
- vi.mocked(useGeneralSetting).mockReturnValue({
- experimentalFeatures: true,
- })
-
- render()
-
expect(screen.getByText('common:mcp-servers')).toBeInTheDocument()
})
it('shows provider expansion chevron when providers are active', () => {
render()
-
+
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
expect(chevron).toBeInTheDocument()
@@ -119,14 +101,14 @@ describe('SettingsMenu', () => {
it('expands providers submenu when chevron is clicked', async () => {
const user = userEvent.setup()
render()
-
+
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
if (!chevron) throw new Error('Chevron button not found')
await user.click(chevron)
-
+
expect(screen.getByTestId('provider-avatar-openai')).toBeInTheDocument()
expect(screen.getByTestId('provider-avatar-llama.cpp')).toBeInTheDocument()
})
@@ -138,52 +120,56 @@ describe('SettingsMenu', () => {
params: { providerName: 'openai' },
},
])
-
+
render()
-
+
expect(screen.getByTestId('provider-avatar-openai')).toBeInTheDocument()
expect(screen.getByTestId('provider-avatar-llama.cpp')).toBeInTheDocument()
})
it('highlights active provider in submenu', async () => {
const user = userEvent.setup()
-
+
vi.mocked(useMatches).mockReturnValue([
{
routeId: '/settings/providers/$providerName',
params: { providerName: 'openai' },
},
])
-
+
render()
-
+
// First expand the providers submenu
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
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()
})
it('navigates to provider when provider is clicked', async () => {
const user = userEvent.setup()
render()
-
+
// First expand the providers
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
if (!chevron) throw new Error('Chevron button not found')
await user.click(chevron)
-
+
// 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!)
-
+
expect(mockNavigate).toHaveBeenCalledWith({
to: '/settings/providers/$providerName',
params: { providerName: 'openai' },
@@ -192,18 +178,22 @@ describe('SettingsMenu', () => {
it('shows mobile menu toggle button', () => {
render()
-
- const menuToggle = screen.getByRole('button', { name: 'Toggle settings menu' })
+
+ const menuToggle = screen.getByRole('button', {
+ name: 'Toggle settings menu',
+ })
expect(menuToggle).toBeInTheDocument()
})
it('opens mobile menu when toggle is clicked', async () => {
const user = userEvent.setup()
render()
-
- const menuToggle = screen.getByRole('button', { name: 'Toggle settings menu' })
+
+ const menuToggle = screen.getByRole('button', {
+ name: 'Toggle settings menu',
+ })
await user.click(menuToggle)
-
+
// Menu should now be visible
const menu = screen.getByText('common:general').closest('div')
expect(menu).toHaveClass('flex')
@@ -212,21 +202,23 @@ describe('SettingsMenu', () => {
it('closes mobile menu when X is clicked', async () => {
const user = userEvent.setup()
render()
-
+
// 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)
-
+
// Then close it
await user.click(menuToggle)
-
+
// Just verify the toggle button is still there after clicking twice
expect(menuToggle).toBeInTheDocument()
})
it('hides llamacpp provider during setup remote provider step', async () => {
const user = userEvent.setup()
-
+
vi.mocked(useMatches).mockReturnValue([
{
routeId: '/settings/providers/',
@@ -234,16 +226,16 @@ describe('SettingsMenu', () => {
search: { step: 'setup_remote_provider' },
},
])
-
+
render()
-
+
// First expand the providers submenu
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
if (chevron) await user.click(chevron)
-
+
// llamacpp provider div should have hidden class
const llamacppElement = screen.getByTestId('provider-avatar-llama.cpp')
expect(llamacppElement.parentElement).toHaveClass('hidden')
@@ -253,7 +245,7 @@ describe('SettingsMenu', () => {
it('filters out inactive providers from submenu', async () => {
const user = userEvent.setup()
-
+
vi.mocked(useModelProvider).mockReturnValue({
providers: [
{
@@ -268,17 +260,19 @@ describe('SettingsMenu', () => {
},
],
})
-
+
render()
-
+
// Expand providers
const chevronButtons = screen.getAllByRole('button')
- const chevron = chevronButtons.find(button =>
+ const chevron = chevronButtons.find((button) =>
button.querySelector('svg.tabler-icon-chevron-right')
)
if (chevron) await user.click(chevron)
-
+
expect(screen.getByTestId('provider-avatar-openai')).toBeInTheDocument()
- expect(screen.queryByTestId('provider-avatar-anthropic')).not.toBeInTheDocument()
+ expect(
+ screen.queryByTestId('provider-avatar-anthropic')
+ ).not.toBeInTheDocument()
})
-})
\ No newline at end of file
+})
diff --git a/web-app/src/hooks/__tests__/useGeneralSetting.test.ts b/web-app/src/hooks/__tests__/useGeneralSetting.test.ts
index 19e71c4fa..f55835c0f 100644
--- a/web-app/src/hooks/__tests__/useGeneralSetting.test.ts
+++ b/web-app/src/hooks/__tests__/useGeneralSetting.test.ts
@@ -31,16 +31,15 @@ describe('useGeneralSetting', () => {
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,
- experimentalFeatures: false,
huggingfaceToken: undefined,
})
@@ -49,7 +48,7 @@ describe('useGeneralSetting', () => {
getSettings: vi.fn().mockResolvedValue(null),
updateSettings: vi.fn(),
})
-
+
mockExtensionManager.getInstance.mockReturnValue({
getByName: mockGetByName,
})
@@ -60,11 +59,9 @@ describe('useGeneralSetting', () => {
expect(result.current.currentLanguage).toBe('en')
expect(result.current.spellCheckChatInput).toBe(true)
- expect(result.current.experimentalFeatures).toBe(false)
expect(result.current.huggingfaceToken).toBeUndefined()
expect(typeof result.current.setCurrentLanguage).toBe('function')
expect(typeof result.current.setSpellCheckChatInput).toBe('function')
- expect(typeof result.current.setExperimentalFeatures).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', () => {
it('should set huggingface token', () => {
const { result } = renderHook(() => useGeneralSetting())
@@ -235,7 +196,7 @@ describe('useGeneralSetting', () => {
const mockGetByName = vi.fn()
const mockGetSettings = vi.fn().mockResolvedValue(mockSettings)
const mockUpdateSettings = vi.fn()
-
+
mockExtensionManager.getInstance.mockReturnValue({
getByName: mockGetByName,
})
@@ -252,9 +213,9 @@ describe('useGeneralSetting', () => {
expect(mockExtensionManager.getInstance).toHaveBeenCalled()
expect(mockGetByName).toHaveBeenCalledWith('@janhq/download-extension')
-
+
// Wait for async operations
- await new Promise(resolve => setTimeout(resolve, 0))
+ await new Promise((resolve) => setTimeout(resolve, 0))
expect(mockGetSettings).toHaveBeenCalled()
expect(mockUpdateSettings).toHaveBeenCalledWith([
@@ -272,13 +233,11 @@ describe('useGeneralSetting', () => {
act(() => {
result1.current.setCurrentLanguage('id')
result1.current.setSpellCheckChatInput(false)
- result1.current.setExperimentalFeatures(true)
result1.current.setHuggingfaceToken('shared-token')
})
expect(result2.current.currentLanguage).toBe('id')
expect(result2.current.spellCheckChatInput).toBe(false)
- expect(result2.current.experimentalFeatures).toBe(true)
expect(result2.current.huggingfaceToken).toBe('shared-token')
})
})
@@ -290,13 +249,11 @@ describe('useGeneralSetting', () => {
act(() => {
result.current.setCurrentLanguage('vn')
result.current.setSpellCheckChatInput(false)
- result.current.setExperimentalFeatures(true)
result.current.setHuggingfaceToken('complex-token-123')
})
expect(result.current.currentLanguage).toBe('vn')
expect(result.current.spellCheckChatInput).toBe(false)
- expect(result.current.experimentalFeatures).toBe(true)
expect(result.current.huggingfaceToken).toBe('complex-token-123')
})
@@ -314,11 +271,9 @@ describe('useGeneralSetting', () => {
// Second update
act(() => {
- result.current.setExperimentalFeatures(true)
result.current.setHuggingfaceToken('sequential-token')
})
- expect(result.current.experimentalFeatures).toBe(true)
expect(result.current.huggingfaceToken).toBe('sequential-token')
// Third update
@@ -331,4 +286,4 @@ describe('useGeneralSetting', () => {
expect(result.current.spellCheckChatInput).toBe(true)
})
})
-})
\ No newline at end of file
+})
diff --git a/web-app/src/routes/settings/__tests__/general.test.tsx b/web-app/src/routes/settings/__tests__/general.test.tsx
index 96388b0fb..e21a28dcf 100644
--- a/web-app/src/routes/settings/__tests__/general.test.tsx
+++ b/web-app/src/routes/settings/__tests__/general.test.tsx
@@ -61,8 +61,6 @@ vi.mock('@/hooks/useGeneralSetting', () => ({
useGeneralSetting: () => ({
spellCheckChatInput: true,
setSpellCheckChatInput: vi.fn(),
- experimentalFeatures: false,
- setExperimentalFeatures: vi.fn(),
huggingfaceToken: 'test-token',
setHuggingfaceToken: vi.fn(),
}),
@@ -188,12 +186,14 @@ vi.mock('@tauri-apps/plugin-opener', () => ({
}))
vi.mock('@tauri-apps/api/webviewWindow', () => {
- const MockWebviewWindow = vi.fn().mockImplementation((label: string, options: any) => ({
- once: vi.fn(),
- setFocus: vi.fn(),
- }))
+ const MockWebviewWindow = vi
+ .fn()
+ .mockImplementation((label: string, options: any) => ({
+ once: vi.fn(),
+ setFocus: vi.fn(),
+ }))
MockWebviewWindow.getByLabel = vi.fn().mockReturnValue(null)
-
+
return {
WebviewWindow: MockWebviewWindow,
}
@@ -299,16 +299,6 @@ describe('General Settings Route', () => {
// 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()
- })
-
- const switches = screen.getAllByTestId('switch')
- expect(switches.length).toBeGreaterThanOrEqual(2)
- })
-
it('should render huggingface token input', async () => {
const Component = GeneralRoute.component as React.ComponentType
await act(async () => {
@@ -336,24 +326,6 @@ describe('General Settings Route', () => {
expect(switches[0]).toBeInTheDocument()
})
- it('should handle experimental features toggle', async () => {
- const Component = GeneralRoute.component as React.ComponentType
- await act(async () => {
- render()
- })
-
- 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 () => {
const Component = GeneralRoute.component as React.ComponentType
await act(async () => {
@@ -514,16 +486,16 @@ describe('General Settings Route', () => {
act(() => {
fireEvent.click(checkUpdateButton)
})
-
+
// Now the button should be disabled while checking
expect(checkUpdateButton).toBeDisabled()
-
+
// Resolve the promise to finish the update check
await act(async () => {
resolveUpdate!(null)
await updatePromise
})
-
+
// Button should be enabled again
expect(checkUpdateButton).not.toBeDisabled()
}