fix: docs
This commit is contained in:
imccyu
2026-07-31 02:13:53 +08:00
parent 085383b145
commit 1e10966ef6
160 files changed
+2521 -1135

No files matched your search

@@ -13,6 +13,7 @@ import type { SessionId } from '@deepseek-ai/dsh-client-runtime/client'
import type { SlashSource } from '@deepseek-ai/dsh-client-ui-slash/client'
import type { CommandServiceContract } from '../src/client/contract.ts'
import type { PopupSelectInjected } from '../src/client/PopupSelectView.tsx'
import { LocaleService } from '@deepseek-ai/dsh-client-locale/client'
import { apply, CommandService, inject } from '../src/client/index.ts'
const sid = (k: string): SessionId => k as SessionId
@@ -41,6 +42,7 @@ async function bench() {
},
})
ctx.provide('conversation', {})
ctx.provide('locale', new LocaleService(ctx))
const fiber = ctx.plugin({ inject: [...inject], apply })
await fiber.await()
const mint = (key: string) => {
@@ -53,7 +55,7 @@ async function bench() {
describe('apply', () => {
it('declares the services it binds', () => {
expect(inject).toEqual(['slash', 'sessions', 'connection'])
expect(inject).toEqual(['slash', 'sessions', 'connection', 'locale'])
})
it('mounts ctx.command, registers the source and the overlay entry, and folds up on disposal', async () => {
@@ -14,6 +14,12 @@ import type { SelectOption } from '../src/client/contract.ts'
import type { PopupSpec, TokenSegment } from '../src/client/popup.ts'
import { PopupSelectController } from '../src/client/popup.ts'
import { PopupSelectView } from '../src/client/PopupSelectView.tsx'
import { makeTranslate } from '@deepseek-ai/dsh-client-test-runtime'
import { zh as commonZh } from '@deepseek-ai/dsh-client-locale/src/locales/zh.ts'
import { zh } from '../src/client/locales.ts'
// The framework-injected t seat, stubbed over the zh dictionaries (the default locale).
const t: Parameters<typeof PopupSelectView>[0]['t'] = makeTranslate(zh, commonZh)
// jsdom has no scrollIntoView; the view calls it on the highlighted row.
const scrollIntoView = vi.fn()
@@ -47,12 +53,12 @@ async function mountOpen(overrides: Partial<PopupSpec<string>> = {}, consumeResu
const consume = vi.fn((_segment: TokenSegment) => consumeResult)
const focusComposer = vi.fn()
const popup = new PopupSelectController<string>({ consume, focusComposer })
const view = render(<PopupSelectView popup={popup} />)
const view = render(<PopupSelectView popup={popup} t={t} />)
await act(async () => {
popup.open('theme', spec(overrides), 'ctx-A', SEGMENT)
await Promise.resolve()
})
return { popup, view, consume, focusComposer, search: screen.getByRole('textbox', { name: 'Filter options' }) }
return { popup, view, consume, focusComposer, search: screen.getByRole('textbox', { name: '筛选选项' }) }
}
function rowLabels(): string[] {
@@ -62,13 +68,13 @@ function rowLabels(): string[] {
describe('PopupSelectView', () => {
it('renders null while closed, opens with focus in the search input', async () => {
const popup = new PopupSelectController<string>({ consume: () => true, focusComposer: () => {} })
const view = render(<PopupSelectView popup={popup} />)
const view = render(<PopupSelectView popup={popup} t={t} />)
expect(view.container.childElementCount).toBe(0)
await act(async () => {
popup.open('theme', spec(), 'ctx-A', SEGMENT)
await Promise.resolve()
})
const search = screen.getByRole('textbox', { name: 'Filter options' })
const search = screen.getByRole('textbox', { name: '筛选选项' })
expect(document.activeElement).toBe(search)
expect(rowLabels()).toEqual(['Dark', 'Light', 'Sepia'])
})
@@ -82,7 +88,7 @@ describe('PopupSelectView', () => {
expect(options).toHaveBeenCalledTimes(1)
act(() => { fireEvent.change(search, { target: { value: 'zzz' } }) })
expect(screen.queryByRole('option')).toBeNull()
expect(screen.queryByText('No options')).not.toBeNull()
expect(screen.queryByText('无选项')).not.toBeNull()
})
it('ArrowUp/Down move the filtered highlight; ArrowLeft/Right are left to the native caret', async () => {
@@ -110,13 +116,13 @@ describe('PopupSelectView', () => {
it('caps the card height at the design maximum when the composer sits low enough', async () => {
vi.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ bottom: 800 } as DOMRect)
await mountOpen()
expect(screen.getByLabelText('/theme options').style.maxHeight).toBe('320px')
expect(screen.getByLabelText('/theme 选项').style.maxHeight).toBe('320px')
})
it('clamps the card height to the space above the composer minus the safe margin', async () => {
vi.spyOn(Element.prototype, 'getBoundingClientRect').mockReturnValue({ bottom: 200 } as DOMRect)
await mountOpen()
expect(screen.getByLabelText('/theme options').style.maxHeight).toBe('188px')
expect(screen.getByLabelText('/theme 选项').style.maxHeight).toBe('188px')
})
it('Enter selects the highlighted row: onSelect, consume, close, focusComposer', async () => {
@@ -148,7 +154,7 @@ describe('PopupSelectView', () => {
const onSelect = vi.fn(() => new Promise<void>((resolve) => { release = resolve }))
const { search, consume } = await mountOpen({ onSelect })
await act(async () => { fireEvent.keyDown(search, { key: 'Enter' }) })
expect(screen.queryByText('Applying…')).not.toBeNull()
expect(screen.queryByText('正在应用…')).not.toBeNull()
expect((search as HTMLInputElement).readOnly).toBe(true)
await act(async () => {
fireEvent.keyDown(search, { key: 'Enter' })
@@ -162,7 +168,7 @@ describe('PopupSelectView', () => {
expect(consume).toHaveBeenCalledTimes(1)
})
it('a failed options load shows the error with a Retry button that reloads', async () => {
it('a failed options load shows the error with a retry button that reloads', async () => {
let attempts = 0
await mountOpen({
options: () => {
@@ -172,7 +178,7 @@ describe('PopupSelectView', () => {
})
expect(screen.getByRole('alert').textContent).toContain('directory down')
await act(async () => {
fireEvent.click(screen.getByRole('button', { name: 'Retry' }))
fireEvent.click(screen.getByRole('button', { name: '重试' }))
await Promise.resolve()
})
expect(attempts).toBe(2)
@@ -183,7 +189,7 @@ describe('PopupSelectView', () => {
const { search, consume } = await mountOpen({ onSelect: () => Promise.reject(new Error('host rejected')) })
await act(async () => { fireEvent.keyDown(search, { key: 'Enter' }) })
expect(screen.getByRole('alert').textContent).toContain('host rejected')
expect(screen.queryByRole('button', { name: 'Retry' })).toBeNull()
expect(screen.queryByRole('button', { name: '重试' })).toBeNull()
expect(consume).not.toHaveBeenCalled()
expect(screen.getAllByRole('option').length).toBe(3)
})