1
0

browser-plugin.client.spec.ts 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import { Context } from '@deepseek-ai/cordis'
  2. import { describe, expect, it } from 'vitest'
  3. import { SlotRegistry } from '@deepseek-ai/dsh-client-ui-renderer/client'
  4. import { stubSettingsScope } from '@deepseek-ai/dsh-client-test-runtime'
  5. import { apply as applyLocale, inject as localeInject } from '@deepseek-ai/dsh-client-locale/client'
  6. import { apply, inject } from '../src/client/index.ts'
  7. import { apply as applyNode } from '../src/index.ts'
  8. import { en, NS, zh } from '../src/client/locales.ts'
  9. const Empty = () => null
  10. function headerEntryIds(ctx: Context): (string | undefined)[] {
  11. return ctx.slots
  12. .entries('conversation.session.header.actions')
  13. .map(entry => entry.options.id)
  14. }
  15. async function baseContext(): Promise<Context> {
  16. const ctx = new Context()
  17. await ctx.plugin(SlotRegistry).await()
  18. ctx.provide('connection', { api: { settings: {} }, isLoopback: false } as never)
  19. ctx.provide('remote', { $on: () => () => {} } as never)
  20. ctx.provide('settingsScope', { bind: () => stubSettingsScope().scope } as never)
  21. await ctx.plugin({ inject: localeInject, apply: applyLocale }).await()
  22. return ctx
  23. }
  24. function declareHeader(ctx: Context): () => void {
  25. return ctx.slots.register({
  26. name: 'root',
  27. children: {
  28. 'conversation.session.header.actions': { kind: 'list', scope: 'session' },
  29. },
  30. } as never, Empty)
  31. }
  32. describe('ui-schedule browser half', () => {
  33. it('declares only the services used by registration', () => {
  34. expect(inject).toEqual(['slots', 'locale'])
  35. })
  36. it('waits for the header declaration, orders between static context and Jobs, and tears down', async () => {
  37. const ctx = await baseContext()
  38. const fiber = ctx.plugin({ inject: [...inject], apply })
  39. await fiber.await()
  40. expect(headerEntryIds(ctx)).toEqual([])
  41. const header = declareHeader(ctx)
  42. ctx.slots.register({
  43. name: 'conversation.session.header.actions', id: 'agent-preset', order: -10,
  44. }, Empty)
  45. ctx.slots.register({
  46. name: 'conversation.session.header.actions', id: 'job-list', order: 20,
  47. }, Empty)
  48. expect(headerEntryIds(ctx)).toEqual(['agent-preset', 'schedule-catalog', 'job-list'])
  49. await fiber.dispose()
  50. expect(headerEntryIds(ctx)).toEqual(['agent-preset', 'job-list'])
  51. header()
  52. await ctx.fiber.dispose()
  53. })
  54. it('registers both dictionaries and releases them with its fiber', async () => {
  55. const ctx = await baseContext()
  56. declareHeader(ctx)
  57. ctx.locale.setLocale('zh')
  58. const fiber = ctx.plugin({ inject: [...inject], apply })
  59. await fiber.await()
  60. const translate = ctx.locale.bind(NS)
  61. expect(translate('list.aria')).toBe(zh['list.aria'])
  62. ctx.locale.setLocale('en')
  63. expect(translate('list.aria')).toBe(en['list.aria'])
  64. expect(Object.keys(en).sort()).toEqual(Object.keys(zh).sort())
  65. await fiber.dispose()
  66. expect(translate('list.aria')).not.toBe(en['list.aria'])
  67. await ctx.fiber.dispose()
  68. })
  69. })
  70. describe('ui-schedule node half', () => {
  71. it('keeps the node half inert', () => {
  72. expect(applyNode).not.toThrow()
  73. })
  74. })