* fix: #1142 - Toggle off experimental toggle does not turn off gated features * test: add tests
This commit is contained in:
parent
8e603bd5db
commit
031b3517dc
@ -100,6 +100,7 @@ const DataFolder = () => {
|
|||||||
<div className="flex items-center gap-x-3">
|
<div className="flex items-center gap-x-3">
|
||||||
<div className="relative">
|
<div className="relative">
|
||||||
<Input
|
<Input
|
||||||
|
data-testid="jan-data-folder-input"
|
||||||
value={janDataFolderPath}
|
value={janDataFolderPath}
|
||||||
className="w-full pr-8 sm:w-[240px]"
|
className="w-full pr-8 sm:w-[240px]"
|
||||||
disabled
|
disabled
|
||||||
|
|||||||
@ -22,7 +22,11 @@ const FactoryReset = () => {
|
|||||||
recommended only if the application is in a corrupted state.
|
recommended only if the application is in a corrupted state.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button theme="destructive" onClick={() => setModalValidation(true)}>
|
<Button
|
||||||
|
data-testid="reset-button"
|
||||||
|
theme="destructive"
|
||||||
|
onClick={() => setModalValidation(true)}
|
||||||
|
>
|
||||||
Reset
|
Reset
|
||||||
</Button>
|
</Button>
|
||||||
<ModalValidation />
|
<ModalValidation />
|
||||||
|
|||||||
154
web/screens/Settings/Advanced/index.test.tsx
Normal file
154
web/screens/Settings/Advanced/index.test.tsx
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||||
|
import '@testing-library/jest-dom'
|
||||||
|
import Advanced from '.'
|
||||||
|
|
||||||
|
class ResizeObserverMock {
|
||||||
|
observe() {}
|
||||||
|
unobserve() {}
|
||||||
|
disconnect() {}
|
||||||
|
}
|
||||||
|
|
||||||
|
global.ResizeObserver = ResizeObserverMock
|
||||||
|
// @ts-ignore
|
||||||
|
global.window.core = {
|
||||||
|
api: {
|
||||||
|
getAppConfigurations: () => jest.fn(),
|
||||||
|
updateAppConfiguration: () => jest.fn(),
|
||||||
|
relaunch: () => jest.fn(),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const setSettingsMock = jest.fn()
|
||||||
|
|
||||||
|
// Mock useSettings hook
|
||||||
|
jest.mock('@/hooks/useSettings', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
useSettings: () => ({
|
||||||
|
readSettings: () => ({
|
||||||
|
run_mode: 'gpu',
|
||||||
|
experimental: false,
|
||||||
|
proxy: false,
|
||||||
|
gpus: [{ name: 'gpu-1' }, { name: 'gpu-2' }],
|
||||||
|
gpus_in_use: ['0'],
|
||||||
|
quick_ask: false,
|
||||||
|
}),
|
||||||
|
setSettings: setSettingsMock,
|
||||||
|
}),
|
||||||
|
}))
|
||||||
|
|
||||||
|
import * as toast from '@/containers/Toast'
|
||||||
|
|
||||||
|
jest.mock('@/containers/Toast')
|
||||||
|
|
||||||
|
jest.mock('@janhq/core', () => ({
|
||||||
|
__esModule: true,
|
||||||
|
...jest.requireActual('@janhq/core'),
|
||||||
|
fs: {
|
||||||
|
rm: jest.fn(),
|
||||||
|
},
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Simulate a full advanced settings screen
|
||||||
|
// @ts-ignore
|
||||||
|
global.isMac = false
|
||||||
|
// @ts-ignore
|
||||||
|
global.isWindows = true
|
||||||
|
|
||||||
|
describe('Advanced', () => {
|
||||||
|
it('renders the component', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Experimental Mode')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('HTTPS Proxy')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('Ignore SSL certificates')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('Jan Data Folder')).toBeInTheDocument()
|
||||||
|
expect(screen.getByText('Reset to Factory Settings')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates Experimental enabled', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
let experimentalToggle
|
||||||
|
await waitFor(() => {
|
||||||
|
experimentalToggle = screen.getByTestId(/experimental-switch/i)
|
||||||
|
fireEvent.click(experimentalToggle!)
|
||||||
|
})
|
||||||
|
expect(experimentalToggle).toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates Experimental disabled', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
|
||||||
|
let experimentalToggle
|
||||||
|
await waitFor(() => {
|
||||||
|
experimentalToggle = screen.getByTestId(/experimental-switch/i)
|
||||||
|
fireEvent.click(experimentalToggle!)
|
||||||
|
})
|
||||||
|
expect(experimentalToggle).not.toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('clears logs', async () => {
|
||||||
|
const jestMock = jest.fn()
|
||||||
|
jest.spyOn(toast, 'toaster').mockImplementation(jestMock)
|
||||||
|
|
||||||
|
render(<Advanced />)
|
||||||
|
let clearLogsButton
|
||||||
|
await waitFor(() => {
|
||||||
|
clearLogsButton = screen.getByTestId(/clear-logs/i)
|
||||||
|
fireEvent.click(clearLogsButton)
|
||||||
|
})
|
||||||
|
expect(clearLogsButton).toBeInTheDocument()
|
||||||
|
expect(jestMock).toHaveBeenCalled()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toggles proxy enabled', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
let proxyToggle
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('HTTPS Proxy')).toBeInTheDocument()
|
||||||
|
proxyToggle = screen.getByTestId(/proxy-switch/i)
|
||||||
|
fireEvent.click(proxyToggle)
|
||||||
|
})
|
||||||
|
expect(proxyToggle).toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('updates proxy settings', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
let proxyInput
|
||||||
|
await waitFor(() => {
|
||||||
|
const proxyToggle = screen.getByTestId(/proxy-switch/i)
|
||||||
|
fireEvent.click(proxyToggle)
|
||||||
|
proxyInput = screen.getByTestId(/proxy-input/i)
|
||||||
|
fireEvent.change(proxyInput, { target: { value: 'http://proxy.com' } })
|
||||||
|
})
|
||||||
|
expect(proxyInput).toHaveValue('http://proxy.com')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('toggles ignore SSL certificates', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
let ignoreSslToggle
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Ignore SSL certificates')).toBeInTheDocument()
|
||||||
|
ignoreSslToggle = screen.getByTestId(/ignore-ssl-switch/i)
|
||||||
|
fireEvent.click(ignoreSslToggle)
|
||||||
|
})
|
||||||
|
expect(ignoreSslToggle).toBeChecked()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders DataFolder component', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Jan Data Folder')).toBeInTheDocument()
|
||||||
|
expect(screen.getByTestId(/jan-data-folder-input/i)).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('renders FactoryReset component', async () => {
|
||||||
|
render(<Advanced />)
|
||||||
|
await waitFor(() => {
|
||||||
|
expect(screen.getByText('Reset to Factory Settings')).toBeInTheDocument()
|
||||||
|
expect(screen.getByTestId(/reset-button/i)).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@ -43,19 +43,10 @@ type GPU = {
|
|||||||
name: string
|
name: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const test = [
|
/**
|
||||||
{
|
* Advanced Settings Screen
|
||||||
id: 'test a',
|
* @returns
|
||||||
vram: 2,
|
*/
|
||||||
name: 'nvidia A',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
id: 'test',
|
|
||||||
vram: 2,
|
|
||||||
name: 'nvidia B',
|
|
||||||
},
|
|
||||||
]
|
|
||||||
|
|
||||||
const Advanced = () => {
|
const Advanced = () => {
|
||||||
const [experimentalEnabled, setExperimentalEnabled] = useAtom(
|
const [experimentalEnabled, setExperimentalEnabled] = useAtom(
|
||||||
experimentalFeatureEnabledAtom
|
experimentalFeatureEnabledAtom
|
||||||
@ -69,7 +60,7 @@ const Advanced = () => {
|
|||||||
|
|
||||||
const [partialProxy, setPartialProxy] = useState<string>(proxy)
|
const [partialProxy, setPartialProxy] = useState<string>(proxy)
|
||||||
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
|
const [gpuEnabled, setGpuEnabled] = useState<boolean>(false)
|
||||||
const [gpuList, setGpuList] = useState<GPU[]>(test)
|
const [gpuList, setGpuList] = useState<GPU[]>([])
|
||||||
const [gpusInUse, setGpusInUse] = useState<string[]>([])
|
const [gpusInUse, setGpusInUse] = useState<string[]>([])
|
||||||
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
const [dropdownOptions, setDropdownOptions] = useState<HTMLDivElement | null>(
|
||||||
null
|
null
|
||||||
@ -87,6 +78,9 @@ const Advanced = () => {
|
|||||||
return y['name']
|
return y['name']
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle proxy change
|
||||||
|
*/
|
||||||
const onProxyChange = useCallback(
|
const onProxyChange = useCallback(
|
||||||
(event: ChangeEvent<HTMLInputElement>) => {
|
(event: ChangeEvent<HTMLInputElement>) => {
|
||||||
const value = event.target.value || ''
|
const value = event.target.value || ''
|
||||||
@ -100,6 +94,12 @@ const Advanced = () => {
|
|||||||
[setPartialProxy, setProxy]
|
[setPartialProxy, setProxy]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Quick Ask Enabled
|
||||||
|
* @param e
|
||||||
|
* @param relaunch
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
const updateQuickAskEnabled = async (
|
const updateQuickAskEnabled = async (
|
||||||
e: boolean,
|
e: boolean,
|
||||||
relaunch: boolean = true
|
relaunch: boolean = true
|
||||||
@ -111,6 +111,12 @@ const Advanced = () => {
|
|||||||
if (relaunch) window.core?.api?.relaunch()
|
if (relaunch) window.core?.api?.relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Vulkan Enabled
|
||||||
|
* @param e
|
||||||
|
* @param relaunch
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
const updateVulkanEnabled = async (e: boolean, relaunch: boolean = true) => {
|
const updateVulkanEnabled = async (e: boolean, relaunch: boolean = true) => {
|
||||||
toaster({
|
toaster({
|
||||||
title: 'Reload',
|
title: 'Reload',
|
||||||
@ -123,11 +129,19 @@ const Advanced = () => {
|
|||||||
if (relaunch) window.location.reload()
|
if (relaunch) window.location.reload()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update Experimental Enabled
|
||||||
|
* @param e
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
const updateExperimentalEnabled = async (
|
const updateExperimentalEnabled = async (
|
||||||
e: ChangeEvent<HTMLInputElement>
|
e: ChangeEvent<HTMLInputElement>
|
||||||
) => {
|
) => {
|
||||||
setExperimentalEnabled(e.target.checked)
|
setExperimentalEnabled(e.target.checked)
|
||||||
if (e) return
|
|
||||||
|
// If it checked, we don't need to do anything else
|
||||||
|
// Otherwise have to reset other settings
|
||||||
|
if (e.target.checked) return
|
||||||
|
|
||||||
// It affects other settings, so we need to reset them
|
// It affects other settings, so we need to reset them
|
||||||
const isRelaunch = quickAskEnabled || vulkanEnabled
|
const isRelaunch = quickAskEnabled || vulkanEnabled
|
||||||
@ -136,6 +150,9 @@ const Advanced = () => {
|
|||||||
if (isRelaunch) window.core?.api?.relaunch()
|
if (isRelaunch) window.core?.api?.relaunch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* useEffect to set GPU enabled if possible
|
||||||
|
*/
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const setUseGpuIfPossible = async () => {
|
const setUseGpuIfPossible = async () => {
|
||||||
const settings = await readSettings()
|
const settings = await readSettings()
|
||||||
@ -149,6 +166,10 @@ const Advanced = () => {
|
|||||||
setUseGpuIfPossible()
|
setUseGpuIfPossible()
|
||||||
}, [readSettings, setGpuList, setGpuEnabled, setGpusInUse, setVulkanEnabled])
|
}, [readSettings, setGpuList, setGpuEnabled, setGpusInUse, setVulkanEnabled])
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear logs
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
const clearLogs = async () => {
|
const clearLogs = async () => {
|
||||||
try {
|
try {
|
||||||
await fs.rm(`file://logs`)
|
await fs.rm(`file://logs`)
|
||||||
@ -163,6 +184,11 @@ const Advanced = () => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle GPU Change
|
||||||
|
* @param gpuId
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
const handleGPUChange = (gpuId: string) => {
|
const handleGPUChange = (gpuId: string) => {
|
||||||
let updatedGpusInUse = [...gpusInUse]
|
let updatedGpusInUse = [...gpusInUse]
|
||||||
if (updatedGpusInUse.includes(gpuId)) {
|
if (updatedGpusInUse.includes(gpuId)) {
|
||||||
@ -188,6 +214,9 @@ const Advanced = () => {
|
|||||||
const gpuSelectionPlaceHolder =
|
const gpuSelectionPlaceHolder =
|
||||||
gpuList.length > 0 ? 'Select GPU' : "You don't have any compatible GPU"
|
gpuList.length > 0 ? 'Select GPU' : "You don't have any compatible GPU"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle click outside
|
||||||
|
*/
|
||||||
useClickOutside(() => setOpen(false), null, [dropdownOptions, toggle])
|
useClickOutside(() => setOpen(false), null, [dropdownOptions, toggle])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
@ -204,6 +233,7 @@ const Advanced = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
|
data-testid="experimental-switch"
|
||||||
checked={experimentalEnabled}
|
checked={experimentalEnabled}
|
||||||
onChange={updateExperimentalEnabled}
|
onChange={updateExperimentalEnabled}
|
||||||
/>
|
/>
|
||||||
@ -401,11 +431,13 @@ const Advanced = () => {
|
|||||||
|
|
||||||
<div className="flex w-full flex-shrink-0 flex-col items-end gap-2 pr-1 sm:w-1/2">
|
<div className="flex w-full flex-shrink-0 flex-col items-end gap-2 pr-1 sm:w-1/2">
|
||||||
<Switch
|
<Switch
|
||||||
|
data-testid="proxy-switch"
|
||||||
checked={proxyEnabled}
|
checked={proxyEnabled}
|
||||||
onChange={() => setProxyEnabled(!proxyEnabled)}
|
onChange={() => setProxyEnabled(!proxyEnabled)}
|
||||||
/>
|
/>
|
||||||
<div className="w-full">
|
<div className="w-full">
|
||||||
<Input
|
<Input
|
||||||
|
data-testid="proxy-input"
|
||||||
placeholder={'http://<user>:<password>@<domain or IP>:<port>'}
|
placeholder={'http://<user>:<password>@<domain or IP>:<port>'}
|
||||||
value={partialProxy}
|
value={partialProxy}
|
||||||
onChange={onProxyChange}
|
onChange={onProxyChange}
|
||||||
@ -428,6 +460,7 @@ const Advanced = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
|
data-testid="ignore-ssl-switch"
|
||||||
checked={ignoreSSL}
|
checked={ignoreSSL}
|
||||||
onChange={(e) => setIgnoreSSL(e.target.checked)}
|
onChange={(e) => setIgnoreSSL(e.target.checked)}
|
||||||
/>
|
/>
|
||||||
@ -448,6 +481,7 @@ const Advanced = () => {
|
|||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Switch
|
<Switch
|
||||||
|
data-testid="quick-ask-switch"
|
||||||
checked={quickAskEnabled}
|
checked={quickAskEnabled}
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
toaster({
|
toaster({
|
||||||
@ -471,7 +505,11 @@ const Advanced = () => {
|
|||||||
Clear all logs from Jan app.
|
Clear all logs from Jan app.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Button theme="destructive" onClick={clearLogs}>
|
<Button
|
||||||
|
data-testid="clear-logs"
|
||||||
|
theme="destructive"
|
||||||
|
onClick={clearLogs}
|
||||||
|
>
|
||||||
Clear
|
Clear
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user