Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

sidebar-animation-issues.spec.tsx 12KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297
  1. import React from 'react'
  2. import { fireEvent, render, screen } from '@testing-library/react'
  3. import '@testing-library/jest-dom'
  4. // Simple Mock Components that reproduce the exact UI issues
  5. const MockNavLink = ({ name, mode }: { name: string; mode: string }) => {
  6. return (
  7. <a
  8. className={`
  9. group flex h-9 items-center rounded-md py-2 text-sm font-normal
  10. ${mode === 'expand' ? 'px-3' : 'px-2.5'}
  11. `}
  12. data-testid={`nav-link-${name}`}
  13. data-mode={mode}
  14. >
  15. {/* Icon with inconsistent margin - reproduces issue #2 */}
  16. <svg
  17. className={`h-4 w-4 shrink-0 ${mode === 'expand' ? 'mr-2' : 'mr-0'}`}
  18. data-testid={`nav-icon-${name}`}
  19. />
  20. {/* Text that appears/disappears abruptly - reproduces issue #2 */}
  21. {mode === 'expand' && <span data-testid={`nav-text-${name}`}>{name}</span>}
  22. </a>
  23. )
  24. }
  25. const MockSidebarToggleButton = ({ expand, onToggle }: { expand: boolean; onToggle: () => void }) => {
  26. return (
  27. <div
  28. className={`
  29. flex shrink-0 flex-col border-r border-divider-burn bg-background-default-subtle transition-all
  30. ${expand ? 'w-[216px]' : 'w-14'}
  31. `}
  32. data-testid="sidebar-container"
  33. >
  34. {/* Top section with variable padding - reproduces issue #1 */}
  35. <div className={`shrink-0 ${expand ? 'p-2' : 'p-1'}`} data-testid="top-section">
  36. App Info Area
  37. </div>
  38. {/* Navigation section - reproduces issue #2 */}
  39. <nav className={`grow space-y-1 ${expand ? 'p-4' : 'px-2.5 py-4'}`} data-testid="navigation">
  40. <MockNavLink name="Orchestrate" mode={expand ? 'expand' : 'collapse'} />
  41. <MockNavLink name="API Access" mode={expand ? 'expand' : 'collapse'} />
  42. <MockNavLink name="Logs & Annotations" mode={expand ? 'expand' : 'collapse'} />
  43. <MockNavLink name="Monitoring" mode={expand ? 'expand' : 'collapse'} />
  44. </nav>
  45. {/* Toggle button section with consistent padding - issue #1 FIXED */}
  46. <div
  47. className="shrink-0 px-4 py-3"
  48. data-testid="toggle-section"
  49. >
  50. <button
  51. className='flex h-6 w-6 cursor-pointer items-center justify-center'
  52. onClick={onToggle}
  53. data-testid="toggle-button"
  54. >
  55. {expand ? '→' : '←'}
  56. </button>
  57. </div>
  58. </div>
  59. )
  60. }
  61. const MockAppInfo = ({ expand }: { expand: boolean }) => {
  62. return (
  63. <div data-testid="app-info" data-expand={expand}>
  64. <button className='block w-full'>
  65. {/* Container with layout mode switching - reproduces issue #3 */}
  66. <div className={`flex rounded-lg ${expand ? 'flex-col gap-2 p-2 pb-2.5' : 'items-start justify-center gap-1 p-1'}`}>
  67. {/* Icon container with justify-between to flex-col switch - reproduces issue #3 */}
  68. <div className={`flex items-center self-stretch ${expand ? 'justify-between' : 'flex-col gap-1'}`} data-testid="icon-container">
  69. {/* Icon with size changes - reproduces issue #3 */}
  70. <div
  71. data-testid="app-icon"
  72. data-size={expand ? 'large' : 'small'}
  73. style={{
  74. width: expand ? '40px' : '24px',
  75. height: expand ? '40px' : '24px',
  76. backgroundColor: '#000',
  77. transition: 'all 0.3s ease', // This broad transition causes bounce
  78. }}
  79. >
  80. Icon
  81. </div>
  82. <div className='flex items-center justify-center rounded-md p-0.5'>
  83. <div className='flex h-5 w-5 items-center justify-center'>
  84. ⚙️
  85. </div>
  86. </div>
  87. </div>
  88. {/* Text that appears/disappears conditionally */}
  89. {expand && (
  90. <div className='flex flex-col items-start gap-1'>
  91. <div className='flex w-full'>
  92. <div className='system-md-semibold truncate text-text-secondary'>Test App</div>
  93. </div>
  94. <div className='system-2xs-medium-uppercase text-text-tertiary'>chatflow</div>
  95. </div>
  96. )}
  97. </div>
  98. </button>
  99. </div>
  100. )
  101. }
  102. describe('Sidebar Animation Issues Reproduction', () => {
  103. beforeEach(() => {
  104. // Mock getBoundingClientRect for position testing
  105. Element.prototype.getBoundingClientRect = jest.fn(() => ({
  106. width: 200,
  107. height: 40,
  108. x: 10,
  109. y: 10,
  110. left: 10,
  111. right: 210,
  112. top: 10,
  113. bottom: 50,
  114. toJSON: jest.fn(),
  115. }))
  116. })
  117. describe('Issue #1: Toggle Button Position Movement - FIXED', () => {
  118. it('should verify consistent padding prevents button position shift', () => {
  119. let expanded = false
  120. const handleToggle = () => {
  121. expanded = !expanded
  122. }
  123. const { rerender } = render(<MockSidebarToggleButton expand={false} onToggle={handleToggle} />)
  124. // Check collapsed state padding
  125. const toggleSection = screen.getByTestId('toggle-section')
  126. expect(toggleSection).toHaveClass('px-4') // Consistent padding
  127. expect(toggleSection).not.toHaveClass('px-5')
  128. expect(toggleSection).not.toHaveClass('px-6')
  129. // Switch to expanded state
  130. rerender(<MockSidebarToggleButton expand={true} onToggle={handleToggle} />)
  131. // Check expanded state padding - should be the same
  132. expect(toggleSection).toHaveClass('px-4') // Same consistent padding
  133. expect(toggleSection).not.toHaveClass('px-5')
  134. expect(toggleSection).not.toHaveClass('px-6')
  135. // THE FIX: px-4 in both states prevents position movement
  136. console.log('✅ Issue #1 FIXED: Toggle button now has consistent padding')
  137. console.log(' - Before: px-4 (collapsed) vs px-6 (expanded) - 8px difference')
  138. console.log(' - After: px-4 (both states) - 0px difference')
  139. console.log(' - Result: No button position movement during transition')
  140. })
  141. it('should verify sidebar width animation is working correctly', () => {
  142. const handleToggle = jest.fn()
  143. const { rerender } = render(<MockSidebarToggleButton expand={false} onToggle={handleToggle} />)
  144. const container = screen.getByTestId('sidebar-container')
  145. // Collapsed state
  146. expect(container).toHaveClass('w-14')
  147. expect(container).toHaveClass('transition-all')
  148. // Expanded state
  149. rerender(<MockSidebarToggleButton expand={true} onToggle={handleToggle} />)
  150. expect(container).toHaveClass('w-[216px]')
  151. console.log('✅ Sidebar width transition is properly configured')
  152. })
  153. })
  154. describe('Issue #2: Navigation Text Squeeze Animation', () => {
  155. it('should reproduce text squeeze effect from padding and margin changes', () => {
  156. const { rerender } = render(<MockNavLink name="Orchestrate" mode="collapse" />)
  157. const link = screen.getByTestId('nav-link-Orchestrate')
  158. const icon = screen.getByTestId('nav-icon-Orchestrate')
  159. // Collapsed state checks
  160. expect(link).toHaveClass('px-2.5') // 10px padding
  161. expect(icon).toHaveClass('mr-0') // No margin
  162. expect(screen.queryByTestId('nav-text-Orchestrate')).not.toBeInTheDocument()
  163. // Switch to expanded state
  164. rerender(<MockNavLink name="Orchestrate" mode="expand" />)
  165. // Expanded state checks
  166. expect(link).toHaveClass('px-3') // 12px padding (+2px)
  167. expect(icon).toHaveClass('mr-2') // 8px margin (+8px)
  168. expect(screen.getByTestId('nav-text-Orchestrate')).toBeInTheDocument()
  169. // THE BUG: Multiple simultaneous changes create squeeze effect
  170. console.log('🐛 Issue #2 Reproduced: Text squeeze effect from multiple layout changes')
  171. console.log(' - Link padding: px-2.5 → px-3 (+2px)')
  172. console.log(' - Icon margin: mr-0 → mr-2 (+8px)')
  173. console.log(' - Text appears: none → visible (abrupt)')
  174. console.log(' - Result: Text appears with squeeze effect due to layout shifts')
  175. })
  176. it('should document the abrupt text rendering issue', () => {
  177. const { rerender } = render(<MockNavLink name="API Access" mode="collapse" />)
  178. // Text completely absent
  179. expect(screen.queryByTestId('nav-text-API Access')).not.toBeInTheDocument()
  180. rerender(<MockNavLink name="API Access" mode="expand" />)
  181. // Text suddenly appears - no transition
  182. expect(screen.getByTestId('nav-text-API Access')).toBeInTheDocument()
  183. console.log('🐛 Issue #2 Detail: Conditional rendering {mode === "expand" && name}')
  184. console.log(' - Problem: Text appears/disappears abruptly without transition')
  185. console.log(' - Should use: opacity or width transition for smooth appearance')
  186. })
  187. })
  188. describe('Issue #3: App Icon Bounce Animation', () => {
  189. it('should reproduce icon bounce from layout mode switching', () => {
  190. const { rerender } = render(<MockAppInfo expand={true} />)
  191. const iconContainer = screen.getByTestId('icon-container')
  192. const appIcon = screen.getByTestId('app-icon')
  193. // Expanded state layout
  194. expect(iconContainer).toHaveClass('justify-between')
  195. expect(iconContainer).not.toHaveClass('flex-col')
  196. expect(appIcon).toHaveAttribute('data-size', 'large')
  197. // Switch to collapsed state
  198. rerender(<MockAppInfo expand={false} />)
  199. // Collapsed state layout - completely different layout mode
  200. expect(iconContainer).toHaveClass('flex-col')
  201. expect(iconContainer).toHaveClass('gap-1')
  202. expect(iconContainer).not.toHaveClass('justify-between')
  203. expect(appIcon).toHaveAttribute('data-size', 'small')
  204. // THE BUG: Layout mode switch causes icon to "bounce"
  205. console.log('🐛 Issue #3 Reproduced: Icon bounce from layout mode switching')
  206. console.log(' - Layout change: justify-between → flex-col gap-1')
  207. console.log(' - Icon size: large (40px) → small (24px)')
  208. console.log(' - Transition: transition-all causes excessive animation')
  209. console.log(' - Result: Icon appears to bounce to right then back during collapse')
  210. })
  211. it('should identify the problematic transition-all property', () => {
  212. render(<MockAppInfo expand={true} />)
  213. const appIcon = screen.getByTestId('app-icon')
  214. const computedStyle = window.getComputedStyle(appIcon)
  215. // The problematic broad transition
  216. expect(computedStyle.transition).toContain('all')
  217. console.log('🐛 Issue #3 Detail: transition-all affects ALL CSS properties')
  218. console.log(' - Problem: Animates layout properties that should not transition')
  219. console.log(' - Solution: Use specific transition properties instead of "all"')
  220. })
  221. })
  222. describe('Interactive Toggle Test', () => {
  223. it('should demonstrate all issues in a single interactive test', () => {
  224. let expanded = false
  225. const handleToggle = () => {
  226. expanded = !expanded
  227. }
  228. const { rerender } = render(
  229. <div data-testid="complete-sidebar">
  230. <MockSidebarToggleButton expand={expanded} onToggle={handleToggle} />
  231. <MockAppInfo expand={expanded} />
  232. </div>,
  233. )
  234. const toggleButton = screen.getByTestId('toggle-button')
  235. // Initial state verification
  236. expect(expanded).toBe(false)
  237. console.log('🔄 Starting interactive test - all issues will be reproduced')
  238. // Simulate toggle click
  239. fireEvent.click(toggleButton)
  240. expanded = true
  241. rerender(
  242. <div data-testid="complete-sidebar">
  243. <MockSidebarToggleButton expand={expanded} onToggle={handleToggle} />
  244. <MockAppInfo expand={expanded} />
  245. </div>,
  246. )
  247. console.log('✨ All three issues successfully reproduced in interactive test:')
  248. console.log(' 1. Toggle button position movement (padding inconsistency)')
  249. console.log(' 2. Navigation text squeeze effect (multiple layout changes)')
  250. console.log(' 3. App icon bounce animation (layout mode switching)')
  251. })
  252. })
  253. })