Louis 81fea5665b
chore: enhance onboarding screen's models (#4723)
* chore: enhance onboarding screen's models

* chore: lint fix

* chore: correct lint fix command

* chore: fix tests
2025-02-25 09:36:55 +07:00

201 lines
5.1 KiB
TypeScript

import React from 'react'
import { render, screen, fireEvent } from '@testing-library/react'
import { Provider } from 'jotai'
import OnDeviceStarterScreen from './index'
import * as jotai from 'jotai'
import '@testing-library/jest-dom'
jest.mock('jotai', () => ({
...jest.requireActual('jotai'),
useAtomValue: jest.fn(),
useSetAtom: jest.fn(),
}))
jest.mock('next/image', () => ({
__esModule: true,
default: (props: any) => <img {...props} />,
}))
jest.mock('@janhq/joi', () => ({
Button: (props: any) => <button {...props} />,
Input: ({ prefixIcon, ...props }: any) => (
<div>
{prefixIcon}
<input {...props} />
</div>
),
Progress: () => <div data-testid="progress" />,
ScrollArea: ({ children }: any) => <div>{children}</div>,
useClickOutside: jest.fn(),
}))
jest.mock('@/containers/Brand/Logo/Mark', () => () => (
<div data-testid="logo-mark" />
))
jest.mock('@/containers/CenterPanelContainer', () => ({ children }: any) => (
<div>{children}</div>
))
jest.mock('@/containers/Loader/ProgressCircle', () => () => (
<div data-testid="progress-circle" />
))
jest.mock('@/containers/ModelLabel', () => () => (
<div data-testid="model-label" />
))
jest.mock('@/hooks/useDownloadModel', () => ({
__esModule: true,
default: () => ({ downloadModel: jest.fn() }),
}))
// Mock the necessary atoms
const mockAtomValue = jest.spyOn(jotai, 'useAtomValue')
const mockSetAtom = jest.spyOn(jotai, 'useSetAtom')
jest.mock('@/hooks/useModelSource')
import * as source from '@/hooks/useModelSource'
describe('OnDeviceStarterScreen', () => {
beforeEach(() => {
mockAtomValue.mockImplementation(() => [])
mockSetAtom.mockImplementation(() => jest.fn())
})
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: [],
error: null,
mutate: jest.fn(),
})
it('renders the component', () => {
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: [],
error: null,
mutate: jest.fn(),
})
render(
<Provider>
<OnDeviceStarterScreen isShowStarterScreen={true} />
</Provider>
)
expect(screen.getByText('Select a model to start')).toBeInTheDocument()
expect(screen.getByTestId('logo-mark')).toBeInTheDocument()
})
it('handles search input', () => {
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: [],
error: null,
mutate: jest.fn(),
})
render(
<Provider>
<OnDeviceStarterScreen isShowStarterScreen={true} />
</Provider>
)
const searchInput = screen.getByPlaceholderText('Search...')
fireEvent.change(searchInput, { target: { value: 'test model' } })
expect(searchInput).toHaveValue('test model')
})
it('displays "No Result Found" when no models match the search', () => {
mockAtomValue.mockImplementation(() => [])
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: [],
error: null,
mutate: jest.fn(),
})
render(
<Provider>
<OnDeviceStarterScreen isShowStarterScreen={true} />
</Provider>
)
const searchInput = screen.getByPlaceholderText('Search...')
fireEvent.change(searchInput, { target: { value: 'nonexistent model' } })
expect(screen.getByText('No Result Found')).toBeInTheDocument()
})
it('renders featured models', () => {
const mockConfiguredModels = [
{
id: 'cortexso/deepseek-r1',
name: 'DeepSeek R1',
metadata: {
tags: ['Featured'],
author: 'Test Author',
size: 3000000000,
},
models: [
{
id: 'cortexso/deepseek-r1',
name: 'DeepSeek R1',
metadata: {
tags: ['Featured'],
},
},
],
},
{
id: 'cortexso/llama3.2',
name: 'Llama 3.1',
metadata: { tags: [], author: 'Test Author', size: 2000000000 },
models: [
{
id: 'cortexso/deepseek-r1',
name: 'DeepSeek R1',
metadata: {
tags: ['Featured'],
},
},
],
},
]
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: mockConfiguredModels,
error: null,
mutate: jest.fn(),
})
render(
<Provider>
<OnDeviceStarterScreen isShowStarterScreen={true} />
</Provider>
)
expect(screen.getAllByText('deepseek-r1')[0]).toBeInTheDocument()
})
it('renders cloud models', () => {
jest.spyOn(source, 'useGetModelSources').mockReturnValue({
sources: [],
error: null,
mutate: jest.fn(),
})
const mockRemoteModels = [
{ id: 'remote-model-1', name: 'Remote Model 1', engine: 'openai' },
{ id: 'remote-model-2', name: 'Remote Model 2', engine: 'anthropic' },
]
mockAtomValue.mockImplementation((atom) => {
if (atom === jotai.atom([])) {
return mockRemoteModels
}
return []
})
render(
<Provider>
<OnDeviceStarterScreen isShowStarterScreen={true} />
</Provider>
)
expect(screen.getByText('Cloud Models')).toBeInTheDocument()
})
})