apply.client.spec.ts 3.5 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182
  1. /** Browser type, Slot, locale, and HMR disposal through the real registries. */
  2. import { describe, expect, it, vi } from 'vitest'
  3. import { Context } from '@deepseek-ai/cordis'
  4. import { SidebarRightTabRegistry } from '@deepseek-ai/dsh-client-ui-sidebar-right/src/client/tab-registry.ts'
  5. import { BrowserBody } from '../src/client/view/BrowserBody.tsx'
  6. import { BrowserTitle } from '../src/client/view/BrowserTitle.tsx'
  7. import type { BrowserInjected } from '../src/client/browser/BrowserController.ts'
  8. import { BROWSER_ID, BROWSER_KIND } from '../src/client/definition.tsx'
  9. import { apply, inject } from '../src/client/index.ts'
  10. import { en, zh } from '../src/client/locales.ts'
  11. import { apply as hostApply } from '../src/index.ts'
  12. interface Recorded {
  13. name: string
  14. key: string
  15. locale?: string
  16. store?: unknown
  17. inject?: unknown
  18. component: unknown
  19. }
  20. async function boot() {
  21. const ctx = new Context()
  22. const tabs = new SidebarRightTabRegistry(ctx)
  23. const registered: Recorded[] = []
  24. const slots = {
  25. inject: vi.fn((_name: string, register: () => () => void) => register()),
  26. register: vi.fn((options: Omit<Recorded, 'component'>, component: unknown) => {
  27. const entry: Recorded = { ...options, component }
  28. registered.push(entry)
  29. return () => { registered.splice(registered.indexOf(entry), 1) }
  30. }),
  31. }
  32. const dictionaries = new Map<string, unknown>()
  33. const locale = {
  34. bind: vi.fn(() => (key: string) => key),
  35. register: vi.fn((namespace: string, value: unknown) => {
  36. dictionaries.set(namespace, value)
  37. return () => { dictionaries.delete(namespace) }
  38. }),
  39. }
  40. ctx.provide('sidebarRightTabs', tabs as never)
  41. ctx.provide('slots', slots as never)
  42. ctx.provide('locale', locale as never)
  43. const fiber = ctx.plugin({ inject: [...inject], apply })
  44. await fiber.await()
  45. return { tabs, registered, dictionaries, fiber }
  46. }
  47. describe('ui-sidebar-browser apply', () => {
  48. it('keeps the Host Loader entry inert', () => {
  49. expect(hostApply).not.toThrow()
  50. })
  51. it('registers a multi-instance builtin and its body and title', async () => {
  52. const { tabs, registered, dictionaries } = await boot()
  53. const definition = tabs.get(BROWSER_KIND)
  54. expect(definition).toMatchObject({ id: BROWSER_ID, kind: BROWSER_KIND, multiple: true, priority: 'builtin' })
  55. expect(definition?.title('sidebar://browser')).toBe('type.label')
  56. expect(definition?.guide?.map(entry => [entry.order, entry.title(), entry.description?.()]))
  57. .toEqual([[30, 'guide.title', 'guide.description']])
  58. expect(dictionaries.get('sidebarBrowser')).toEqual({ zh, en })
  59. expect(registered.map(entry => [entry.name, entry.key, entry.locale, entry.component])).toEqual([
  60. ['sidebar.right.pane.tab', BROWSER_ID, 'sidebarBrowser', BrowserBody],
  61. ['sidebar.right.pane.tab.title', BROWSER_ID, undefined, BrowserTitle],
  62. ])
  63. expect(registered[0]?.store).toBeDefined()
  64. expect(registered[0]?.inject).toBeTypeOf('function')
  65. const injectFace = registered[0]?.inject as ((sessionId: string, actions: unknown) => unknown)
  66. const browser = injectFace('session', { replace: vi.fn(), forget: vi.fn() }) as BrowserInjected
  67. expect(browser.keyedHooks.browserFrame('missing')).toBeUndefined()
  68. expect(typeof browser.mount).toBe('function')
  69. })
  70. it('removes every registration when the plugin is disposed', async () => {
  71. const { tabs, registered, dictionaries, fiber } = await boot()
  72. await fiber.dispose()
  73. expect(tabs.get(BROWSER_KIND)).toBeUndefined()
  74. expect(registered).toEqual([])
  75. expect(dictionaries.size).toBe(0)
  76. })
  77. })