Files
deepseek-harness/packages/client/ui-sidebar-documentpreview/tests/code-registration.client.spec.tsx
T

90 lines
3.9 KiB
TypeScript

// @vitest-environment jsdom
/** Code renderer registration lifetimes through the production document and Slot registries. */
import { afterEach, describe, expect, it } from 'vitest'
import { act } from '@testing-library/react'
import { SlotTestRuntime } from '@deepseek-ai/dsh-client-test-runtime'
import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client'
import { apply } from '../src/client/code/index.ts'
import { CodeBody } from '../src/client/code/CodeBody.tsx'
import { CODE_EXTENSIONS } from '../src/client/code/languages.ts'
import { DocumentPreviewRegistry } from '../src/client/document/registry.ts'
import { documentTabInfoFactory } from '../src/client/document/contract.ts'
const ID = '@deepseek-ai/dsh-client-ui-sidebar-documentpreview/code'
const SLOT = 'sidebar.right.tab.document'
const plugin = { inject: ['slots', 'locale', 'documentPreviews'], apply }
let runtime: SlotTestRuntime | undefined
afterEach(async () => {
await runtime?.dispose()
runtime = undefined
})
async function boot() {
const rt = await SlotTestRuntime.create()
runtime = rt
const locale = new LocaleRuntime(rt.ctx)
rt.ctx.provide('locale', locale)
rt.slots.installLocale(locale)
const previews = new DocumentPreviewRegistry()
rt.ctx.provide('documentPreviews', previews)
const declare = () => rt.declare({
[SLOT]: { kind: 'keyed', scope: 'session', inject: { hooks: { tabInfo: documentTabInfoFactory } } },
})
return { rt, locale, previews, declare }
}
describe('code renderer registration', () => {
it('publishes builtin metadata before the document slot exists and waits to register its body', async () => {
const h = await boot()
await h.rt.mount(plugin)
expect(h.previews.getSnapshot()).toHaveLength(1)
expect(h.previews.getSnapshot()[0]).toMatchObject({ id: ID, extensions: CODE_EXTENSIONS, priority: 'builtin', loading: 'text-pages', wrap: true })
expect(h.rt.slots.entries(SLOT)).toEqual([])
await h.declare()
const entries = h.rt.slots.entries(SLOT)
expect(entries).toHaveLength(1)
expect(entries[0]).toMatchObject({ options: { key: ID }, locale: 'sidebarCodePreview', component: CodeBody })
expect(h.previews.candidates('notes.unknown')).toEqual([])
})
it('resolves localized names at read time and removes metadata, locale, and body on disposal', async () => {
const h = await boot()
await h.declare()
const feature = await h.rt.mount(plugin)
const definition = h.previews.getSnapshot()[0]
await act(async () => { h.locale.setLocale('en') })
expect(definition?.title()).toBe('Code')
await act(async () => { h.locale.setLocale('zh') })
expect(definition?.title()).toBe('代码')
await feature.dispose()
expect(h.previews.getSnapshot()).toEqual([])
expect(h.rt.slots.entries(SLOT)).toEqual([])
expect(h.locale.bind('sidebarCodePreview')('title')).toBe('title')
})
it('remounts the keyed body after the document owner redeclares its slot', async () => {
const h = await boot()
await h.declare()
await h.rt.mount(plugin)
await act(async () => { h.rt.root.release() })
expect(h.rt.slots.entries(SLOT)).toEqual([])
expect(h.previews.getSnapshot()).toHaveLength(1)
await h.declare()
expect(h.rt.slots.entries(SLOT)).toHaveLength(1)
})
it('keeps prior HTML and Markdown builtins ahead of their optional source renderer', async () => {
const h = await boot()
for (const extension of ['html', 'md']) {
h.rt.ctx.effect(() => h.previews.register({
id: `dedicated-${extension}`, extensions: [extension], priority: 'builtin',
title: () => extension, loading: extension === 'html' ? 'bytes-complete' : 'text-pages',
}))
}
await h.rt.mount(plugin)
expect(h.previews.candidates('page.html').map(item => item.id)).toEqual(['dedicated-html', ID])
expect(h.previews.candidates('README.md').map(item => item.id)).toEqual(['dedicated-md', ID])
})
})