| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 |
- /** Models section registration: declaration-aware deferral, locale re-registration, and HMR recovery. */
- import { Context } from 'cordis'
- import { describe, expect, it } from 'vitest'
- import { SlotsService } from '@deepseek-ai/dsh-client-runtime/client'
- import { LocaleService } from '@deepseek-ai/dsh-client-locale/client'
- import { apply, inject } from '@deepseek-ai/dsh-client-ui-models/client'
- import { ModelsSection } from '../src/client/ModelsSection.tsx'
- async function bench() {
- const ctx = new Context()
- await ctx.plugin(SlotsService).await()
- const locale = new LocaleService(ctx)
- ctx.provide('locale', locale)
- return { ctx, slots: ctx.get('slots') as SlotsService, locale }
- }
- function declare(slots: SlotsService): () => void {
- return slots.register(
- { name: 'root', children: { 'settings.section': { kind: 'list', scope: 'root' } } } as never,
- () => null,
- )
- }
- describe('ui-models apply', () => {
- it('declares the services it uses', () => {
- expect(inject).toEqual(['slots', 'locale'])
- })
- it('registers the models nav entry for declarations before or after apply', async () => {
- const before = await bench()
- declare(before.slots)
- await before.ctx.plugin({ inject: [...inject], apply }).await()
- const entry = before.slots.entries('settings.section')[0]!
- expect(entry.component).toBe(ModelsSection)
- expect(entry.options).toEqual({ id: 'models', order: 10, label: '模型' })
- const after = await bench()
- await after.ctx.plugin({ inject: [...inject], apply }).await()
- expect(after.slots.entries('settings.section')).toHaveLength(0)
- declare(after.slots)
- await Promise.resolve()
- expect(after.slots.entries('settings.section')[0]!.component).toBe(ModelsSection)
- // The self-inflicted ledger notifications hit the duplicate guard.
- expect(after.slots.entries('settings.section')).toHaveLength(1)
- })
- it('re-registers with fresh label text on locale change', async () => {
- const b = await bench()
- declare(b.slots)
- await b.ctx.plugin({ inject: [...inject], apply }).await()
- b.locale.setLocale('en')
- expect(b.slots.entries('settings.section')[0]!.options.label).toBe('Models')
- b.locale.setLocale('zh')
- expect(b.slots.entries('settings.section')[0]!.options.label).toBe('模型')
- })
- it('locale change while the slot is undeclared stays a no-op', async () => {
- const b = await bench()
- await b.ctx.plugin({ inject: [...inject], apply }).await()
- b.locale.setLocale('en')
- expect(b.slots.entries('settings.section')).toHaveLength(0)
- b.locale.setLocale('zh')
- })
- it('re-registers after an HMR collapse re-declares the slot (stale disposer must not block)', async () => {
- const b = await bench()
- const redeclare = declare(b.slots)
- await b.ctx.plugin({ inject: [...inject], apply }).await()
- expect(b.slots.entries('settings.section')).toHaveLength(1)
- // Declarer unload: the cascade removes our entry while our local
- // disposer variable goes stale.
- redeclare()
- expect(b.slots.entries('settings.section')).toHaveLength(0)
- declare(b.slots)
- await Promise.resolve()
- expect(b.slots.entries('settings.section')[0]!.component).toBe(ModelsSection)
- // The locale path also recovers through the same ledger re-check.
- b.locale.setLocale('en')
- expect(b.slots.entries('settings.section')[0]!.options.label).toBe('Models')
- b.locale.setLocale('zh')
- })
- it('registers the zh/en nav dictionaries and disposes everything with the fiber', async () => {
- const b = await bench()
- declare(b.slots)
- const fiber = b.ctx.plugin({ inject: [...inject], apply })
- await fiber.await()
- expect(b.locale.bind('settings.models')('nav')).toBe('模型')
- await fiber.dispose()
- expect(b.slots.entries('settings.section')).toHaveLength(0)
- // The (ns, locale) seats are free again — the dictionary disposers ran.
- expect(() => b.locale.register('settings.models', 'zh', {})).not.toThrow()
- expect(() => b.locale.register('settings.models', 'en', {})).not.toThrow()
- })
- })
|