refactor: simplify event handling and fix test setup in ModelCombobox

This commit is contained in:
lugnicca 2025-08-22 03:12:58 +02:00
parent 9a68631d39
commit 4e8dd9281f
2 changed files with 24 additions and 25 deletions

View File

@ -61,7 +61,7 @@ const ErrorSection = ({ error, onRefresh, t }: { error: string; onRefresh?: () =
size="sm" size="sm"
onClick={(e) => { onClick={(e) => {
e.stopPropagation() e.stopPropagation()
onRefresh?.() onRefresh()
}} }}
className="h-6 w-6 p-0 no-underline hover:bg-main-view-fg/10 text-main-view-fg" className="h-6 w-6 p-0 no-underline hover:bg-main-view-fg/10 text-main-view-fg"
aria-label="Refresh models" aria-label="Refresh models"
@ -171,16 +171,10 @@ function useKeyboardNavigation(
switch (e.key) { switch (e.key) {
case 'ArrowDown': case 'ArrowDown':
e.preventDefault() e.preventDefault()
if (keyRepeatTimeoutRef.current) {
clearTimeout(keyRepeatTimeoutRef.current)
}
setHighlightedIndex((prev: number) => filteredModels.length === 0 ? 0 : (prev < filteredModels.length - 1 ? prev + 1 : 0)) setHighlightedIndex((prev: number) => filteredModels.length === 0 ? 0 : (prev < filteredModels.length - 1 ? prev + 1 : 0))
break break
case 'ArrowUp': case 'ArrowUp':
e.preventDefault() e.preventDefault()
if (keyRepeatTimeoutRef.current) {
clearTimeout(keyRepeatTimeoutRef.current)
}
setHighlightedIndex((prev: number) => filteredModels.length === 0 ? 0 : (prev > 0 ? prev - 1 : filteredModels.length - 1)) setHighlightedIndex((prev: number) => filteredModels.length === 0 ? 0 : (prev > 0 ? prev - 1 : filteredModels.length - 1))
break break
case 'Enter': case 'Enter':
@ -195,9 +189,11 @@ function useKeyboardNavigation(
setHighlightedIndex(-1) setHighlightedIndex(-1)
break break
case 'PageUp': case 'PageUp':
e.preventDefault()
setHighlightedIndex(0) setHighlightedIndex(0)
break break
case 'PageDown': case 'PageDown':
e.preventDefault()
setHighlightedIndex(filteredModels.length - 1) setHighlightedIndex(filteredModels.length - 1)
break break
} }
@ -394,8 +390,6 @@ export function ModelCombobox({
}} }}
data-dropdown="model-combobox" data-dropdown="model-combobox"
onPointerDown={(e) => e.stopPropagation()} onPointerDown={(e) => e.stopPropagation()}
onClick={(e) => e.stopPropagation()}
onMouseDown={(e) => e.stopPropagation()}
onWheel={(e) => e.stopPropagation()} onWheel={(e) => e.stopPropagation()}
> >
{/* Error state */} {/* Error state */}

View File

@ -1,4 +1,4 @@
import { describe, it, expect, vi, beforeEach } from 'vitest' import { describe, it, expect, vi, beforeEach, beforeAll, afterAll } from 'vitest'
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react' import { render, screen, fireEvent, waitFor, act } from '@testing-library/react'
import userEvent from '@testing-library/user-event' import userEvent from '@testing-library/user-event'
import '@testing-library/jest-dom/vitest' import '@testing-library/jest-dom/vitest'
@ -28,10 +28,11 @@ describe('ModelCombobox', () => {
models: ['gpt-3.5-turbo', 'gpt-4', 'claude-3-haiku'], models: ['gpt-3.5-turbo', 'gpt-4', 'claude-3-haiku'],
} }
beforeEach(() => { let bcrSpy: ReturnType<typeof vi.spyOn>
vi.clearAllMocks() let scrollSpy: ReturnType<typeof vi.spyOn>
Element.prototype.getBoundingClientRect = vi.fn(() => ({ beforeAll(() => {
const mockRect = {
width: 300, width: 300,
height: 40, height: 40,
top: 100, top: 100,
@ -41,9 +42,22 @@ describe('ModelCombobox', () => {
x: 50, x: 50,
y: 100, y: 100,
toJSON: () => {}, toJSON: () => {},
})) } as unknown as DOMRect
Element.prototype.scrollIntoView = vi.fn() bcrSpy = vi
.spyOn(Element.prototype as any, 'getBoundingClientRect')
.mockReturnValue(mockRect)
Element.prototype.scrollIntoView = () => {}
})
beforeEach(() => {
vi.clearAllMocks()
})
afterAll(() => {
bcrSpy?.mockRestore()
scrollSpy?.mockRestore()
}) })
it('renders input field with default placeholder', () => { it('renders input field with default placeholder', () => {
@ -369,15 +383,6 @@ describe('ModelCombobox', () => {
expect(localMockOnChange).toHaveBeenCalledWith('gpt') expect(localMockOnChange).toHaveBeenCalledWith('gpt')
}) })
it('updates input value when typing', () => {
render(<ModelCombobox {...defaultProps} />)
const input = screen.getByRole('textbox')
fireEvent.change(input, { target: { value: 'gpt-4' } })
expect(input).toHaveValue('gpt-4')
})
it('displays error message in dropdown', async () => { it('displays error message in dropdown', async () => {
const user = userEvent.setup() const user = userEvent.setup()
render(<ModelCombobox {...defaultProps} error="Network connection failed" />) render(<ModelCombobox {...defaultProps} error="Network connection failed" />)