service.client.spec.ts 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104
  1. import { describe, expect, it, vi } from 'vitest'
  2. import { LayoutController } from '../src/client/service.ts'
  3. import type { MainPanelId, PanelActions } from '../src/client/service.ts'
  4. function fakePanels(): PanelActions {
  5. return {
  6. selectPanel: vi.fn(),
  7. retainMainPanels: vi.fn(),
  8. setSidebar: vi.fn(),
  9. toggleSidebar: vi.fn(),
  10. setViewportWidth: vi.fn(),
  11. setRightbar: vi.fn(),
  12. openRightbar: vi.fn(),
  13. closeRightbar: vi.fn(),
  14. }
  15. }
  16. describe('LayoutController', () => {
  17. it('forwards right column transitions to the constructor-supplied actions', () => {
  18. const panels = fakePanels()
  19. const service = new LayoutController(panels, () => true)
  20. service.openRightbar(true, false)
  21. service.openRightbar(true, true)
  22. service.openRightbar(false, true)
  23. service.closeRightbar()
  24. expect(panels.openRightbar).toHaveBeenNthCalledWith(1, true, false)
  25. expect(panels.openRightbar).toHaveBeenNthCalledWith(2, true, true)
  26. expect(panels.openRightbar).toHaveBeenNthCalledWith(3, false, true)
  27. expect(panels.closeRightbar).toHaveBeenCalledTimes(1)
  28. // The drag width stays the frame's own business, never the caller's.
  29. expect(panels.setRightbar).not.toHaveBeenCalled()
  30. })
  31. it('can toggle the sidebar immediately after construction', () => {
  32. const panels = fakePanels()
  33. const service = new LayoutController(panels, () => true)
  34. service.toggleSidebar()
  35. expect(panels.toggleSidebar).toHaveBeenCalledTimes(1)
  36. expect(panels.setSidebar).not.toHaveBeenCalled()
  37. })
  38. it('forwards panel selection and returning to the Conversation without changing geometry', () => {
  39. const panels = fakePanels()
  40. const service = new LayoutController(panels, () => true)
  41. const panelId = 'panel-a' as MainPanelId
  42. service.selectPanel(panelId)
  43. service.selectPanel(panelId)
  44. service.selectPanel(null)
  45. expect(panels.selectPanel).toHaveBeenNthCalledWith(1, panelId)
  46. expect(panels.selectPanel).toHaveBeenNthCalledWith(2, panelId)
  47. expect(panels.selectPanel).toHaveBeenNthCalledWith(3, null)
  48. expect(panels.toggleSidebar).not.toHaveBeenCalled()
  49. expect(panels.openRightbar).not.toHaveBeenCalled()
  50. expect(panels.closeRightbar).not.toHaveBeenCalled()
  51. })
  52. it('keeps separately constructed controllers bound to their own instances', () => {
  53. const first = fakePanels()
  54. const second = fakePanels()
  55. const firstService = new LayoutController(first, () => true)
  56. const secondService = new LayoutController(second, () => true)
  57. firstService.toggleSidebar()
  58. expect(first.toggleSidebar).toHaveBeenCalledTimes(1)
  59. expect(second.toggleSidebar).not.toHaveBeenCalled()
  60. secondService.closeRightbar()
  61. expect(first.closeRightbar).not.toHaveBeenCalled()
  62. expect(second.closeRightbar).toHaveBeenCalledTimes(1)
  63. })
  64. it('rejects an absent main entry without changing selection or cancelling pending navigation', () => {
  65. const panels = fakePanels()
  66. const present = new Set(['panel-a'])
  67. const service = new LayoutController(panels, id => present.has(id))
  68. service.selectPanel('panel-a' as MainPanelId)
  69. const navigation = service.beginNavigation()
  70. present.delete('panel-a')
  71. expect(() => { service.selectPanel('panel-a' as MainPanelId) }).toThrow('main panel "panel-a" is not registered')
  72. expect(panels.selectPanel).toHaveBeenCalledOnce()
  73. expect(navigation.aborted).toBe(false)
  74. service.selectPanel(null)
  75. expect(navigation.aborted).toBe(true)
  76. })
  77. it('supersedes asynchronous navigation on another request, any valid selection, and disposal', () => {
  78. const service = new LayoutController(fakePanels(), () => true)
  79. const first = service.beginNavigation()
  80. const second = service.beginNavigation()
  81. expect(first.aborted).toBe(true)
  82. expect(second.aborted).toBe(false)
  83. service.selectPanel('panel-a' as MainPanelId)
  84. expect(second.aborted).toBe(true)
  85. const repeated = service.beginNavigation()
  86. service.selectPanel('panel-a' as MainPanelId)
  87. expect(repeated.aborted).toBe(true)
  88. const pending = service.beginNavigation()
  89. service.dispose()
  90. expect(pending.aborted).toBe(true)
  91. service.dispose()
  92. })
  93. })