fix(web): align session search contracts

This commit is contained in:
Hypatia May
2026-07-27 18:38:00 +08:00
parent 621f414407
commit 4727d742db
42 changed files with 235 additions and 196 deletions
@@ -26,7 +26,7 @@ async function bench() {
ctx.provide('workspaces', {
create, startSession, rename, insertSessionBefore,
} as never)
ctx.provide('sessions', { open, clear, search } as never)
ctx.provide('sessions', { open, clear, search, searchResultLimit: 20 } as never)
return {
ctx,
slots: ctx.get('slots') as SlotsService,
@@ -86,6 +86,7 @@ describe('ui-workspace apply', () => {
hasMore: false,
})
expect(b.search).toHaveBeenCalledWith('match', signal)
expect(browser.searchResultLimit).toBe(20)
await browser.renameWorkspace('ws' as never, 'renamed')
expect(b.rename).toHaveBeenCalledWith('ws', 'renamed')
await browser.insertSessionBefore('ws' as never, 's1' as never, 's2' as never)
@@ -167,6 +167,7 @@ describe('deriveSearchResults', () => {
],
hasMore: false,
},
10,
)
expect(result).toEqual({
@@ -214,6 +215,7 @@ describe('deriveSearchResults', () => {
],
hasMore: false,
},
10,
)
expect(result.items).toEqual([{
id: currentBlank.id,
@@ -224,14 +226,20 @@ describe('deriveSearchResults', () => {
}])
})
it('caps merged rows at 20 and preserves either local overflow or backend hasMore', () => {
const rows = Array.from({ length: 22 }, (_, index) => {
it('uses the supplied cap and preserves either local overflow or backend hasMore', () => {
const rows = Array.from({ length: 5 }, (_, index) => {
const item = summary(`s-${String(index).padStart(2, '0')}`, index)
item.displayTitle = `Needle ${String(index)}`
return item
})
const overflow = deriveSearchResults(list(...rows), [], 'needle', { items: [], hasMore: false })
expect(overflow.items).toHaveLength(20)
const overflow = deriveSearchResults(
list(...rows),
[],
'needle',
{ items: [], hasMore: false },
3,
)
expect(overflow.items).toHaveLength(3)
expect(overflow.hasMore).toBe(true)
const backendMore = deriveSearchResults(
@@ -239,10 +247,11 @@ describe('deriveSearchResults', () => {
[],
'needle',
{ items: [{ sessionId: sid('body'), snippet: 'needle' }], hasMore: true },
3,
)
expect(backendMore.items).toHaveLength(1)
expect(backendMore.hasMore).toBe(true)
expect(deriveSearchResults(list(), [], ' ', { items: [], hasMore: true }))
expect(deriveSearchResults(list(), [], ' ', { items: [], hasMore: true }, 3))
.toEqual({ items: [], hasMore: false })
})
})
@@ -54,6 +54,7 @@ function mount(overrides: Partial<WorkspaceBrowserProps> = {}) {
startSession: vi.fn(),
open: vi.fn(),
searchSessions: vi.fn(async () => ({ items: [], hasMore: false })),
searchResultLimit: 20,
renameWorkspace: vi.fn(async () => {}),
deleteWorkspace: vi.fn(async () => {}),
insertSessionBefore: vi.fn(async () => {}),
@@ -217,10 +218,12 @@ describe('WorkspaceBrowser', () => {
})
const input = screen.getByPlaceholderText<HTMLInputElement>('Search names or content…')
fireEvent.change(input, { target: { value: 'needle' } })
expect(screen.getByRole('tree', { name: 'Search results' })).toBeTruthy()
const resultTree = screen.getByRole('tree', { name: 'Search results' })
expect(screen.getByText('Needle row')).toBeTruthy()
expect(screen.queryByText('Other row')).toBeNull()
expect(screen.getByText('Searching session history…')).toBeTruthy()
const status = screen.getByRole('status')
expect(status.textContent).toBe('Searching session history…')
expect(resultTree.contains(status)).toBe(false)
fireEvent.change(input, { target: { value: 'zzz' } })
await act(async () => { await vi.advanceTimersByTimeAsync(250) })