| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104 |
- // @vitest-environment jsdom
- import { Context, Service } from '@deepseek-ai/cordis'
- import { afterEach, describe, expect, it, vi } from 'vitest'
- import { cleanup } from '@testing-library/react'
- import { LocaleRuntime } from '@deepseek-ai/dsh-client-locale/client'
- import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client'
- import { resolveSlotLabel } from '@deepseek-ai/dsh-client-ui-slots'
- import { usePinnedBrowserLanguages } from '@deepseek-ai/dsh-client-test-runtime'
- import { apply, inject, NS } from '../src/client/index.ts'
- import { PluginInventorySettingsTab } from '../src/client/PluginInventorySettingsTab.tsx'
- import type { PluginInventorySettingsTabInjected } from '../src/client/PluginInventorySettingsTab.tsx'
- import { apply as hostApply } from '../src/index.ts'
- usePinnedBrowserLanguages('zh-CN')
- afterEach(cleanup)
- const EMPTY = { entries: [] }
- type ListResult =
- | { readonly ok: true; readonly value: typeof EMPTY }
- | { readonly ok: false; readonly error: { readonly code: string; readonly message: string } }
- async function bench() {
- const ctx = new Context()
- await ctx.plugin(SlotRegistry).await()
- const locale = new LocaleRuntime(ctx)
- ctx.provide('locale', locale)
- class RemoteService extends Service {
- constructor(serviceCtx: Context) {
- super(serviceCtx, 'remote')
- }
- }
- new RemoteService(ctx)
- const list = vi.fn<() => Promise<ListResult>>()
- .mockResolvedValue({ ok: true, value: EMPTY })
- ctx.provide('remote.pluginInventory', { list })
- return { ctx, slots: ctx.get('slots') as SlotRegistry, locale, list }
- }
- function declare(slots: SlotRegistry): () => void {
- return slots.register({
- name: 'root',
- children: { 'settings.plugins.tab': { kind: 'list', scope: 'root' } },
- } as never, () => null)
- }
- describe('ui-settings-plugin-inventory browser plugin', () => {
- it('keeps the host Loader entry inert', () => {
- expect(hostApply).not.toThrow()
- })
- it('declares only the services used by the Settings Remote contribution', () => {
- expect(inject).toEqual(['slots', 'locale', 'remote', 'remote.pluginInventory'])
- })
- it('registers a localized tab without reading the Remote eagerly', async () => {
- const b = await bench()
- declare(b.slots)
- await b.ctx.plugin({ inject: [...inject], apply }).await()
- const entry = b.slots.entries('settings.plugins.tab')[0]!
- expect(entry.component).toBe(PluginInventorySettingsTab)
- expect(entry.options).toMatchObject({ id: 'all', order: 10 })
- expect(entry.locale).toBe(NS)
- expect(resolveSlotLabel(entry.options.label)).toBe('插件列表')
- expect(b.list).not.toHaveBeenCalled()
- const injected = (entry.inject as unknown as () => PluginInventorySettingsTabInjected)()
- await expect(injected.list()).resolves.toEqual(EMPTY)
- expect(b.list).toHaveBeenCalledOnce()
- b.list.mockResolvedValueOnce({ ok: false, error: { code: 'REMOTE_ERROR', message: 'unavailable' } })
- await expect(injected.list()).rejects.toThrow('pluginInventory.list failed: REMOTE_ERROR: unavailable')
- // Shipped preset names resolve over the agent-preset dictionaries the
- // real plugin registers; user-authored metadata stays untranslated.
- b.locale.register('settings.agentPreset', 'zh', { presetStandardName: '标准模式' } as never)
- expect(injected.presetName({ id: 'standard', trust: 'system', isDefault: true, rows: [] })).toBe('标准模式')
- expect(injected.presetName({ id: 'mine', trust: 'user', name: '我自己的', isDefault: false, rows: [] })).toBe('我自己的')
- await b.ctx.fiber.dispose()
- })
- it('follows locale and recovers across late declaration and declarer reload', async () => {
- const b = await bench()
- const fiber = b.ctx.plugin({ inject: [...inject], apply })
- await fiber.await()
- expect(b.slots.entries('settings.plugins.tab')).toHaveLength(0)
- const stop = declare(b.slots)
- await vi.waitFor(() => { expect(b.slots.entries('settings.plugins.tab')).toHaveLength(1) })
- b.locale.setLocale('en')
- expect(resolveSlotLabel(b.slots.entries('settings.plugins.tab')[0]!.options.label)).toBe('Plugin list')
- stop()
- expect(b.slots.entries('settings.plugins.tab')).toHaveLength(0)
- declare(b.slots)
- await vi.waitFor(() => {
- expect(b.slots.entries('settings.plugins.tab')[0]?.component).toBe(PluginInventorySettingsTab)
- })
- await fiber.dispose()
- expect(b.slots.entries('settings.plugins.tab')).toHaveLength(0)
- expect(() => b.locale.register(NS, 'zh', {})).not.toThrow()
- await b.ctx.fiber.dispose()
- })
- })
|