FloatingMobileToolbar.utils.test.ts98 lines · main
| 1 | import { describe, expect, it } from 'vitest' |
| 2 | |
| 3 | import { |
| 4 | clampPosition, |
| 5 | getNextPosition, |
| 6 | getToolbarStyle, |
| 7 | isMenuContent, |
| 8 | shouldShowMenuButton, |
| 9 | } from './FloatingMobileToolbar.utils' |
| 10 | |
| 11 | describe('isMenuContent', () => { |
| 12 | it('returns false for null', () => { |
| 13 | expect(isMenuContent(null)).toBe(false) |
| 14 | }) |
| 15 | |
| 16 | it('returns false for sidebar id string', () => { |
| 17 | expect(isMenuContent('help-panel')).toBe(false) |
| 18 | }) |
| 19 | |
| 20 | it('returns true for non-string content', () => { |
| 21 | expect(isMenuContent({})).toBe(true) |
| 22 | expect(isMenuContent(0)).toBe(true) |
| 23 | }) |
| 24 | }) |
| 25 | |
| 26 | describe('shouldShowMenuButton', () => { |
| 27 | it('returns true for project, org, account paths', () => { |
| 28 | expect(shouldShowMenuButton('/project/ref')).toBe(true) |
| 29 | expect(shouldShowMenuButton('/org/slug')).toBe(true) |
| 30 | expect(shouldShowMenuButton('/account/me')).toBe(true) |
| 31 | }) |
| 32 | |
| 33 | it('returns false for other paths', () => { |
| 34 | expect(shouldShowMenuButton('/organizations')).toBe(false) |
| 35 | expect(shouldShowMenuButton('/')).toBe(false) |
| 36 | }) |
| 37 | }) |
| 38 | |
| 39 | describe('clampPosition', () => { |
| 40 | const viewport = { width: 400, height: 800 } |
| 41 | const navSize = { width: 100, height: 48 } |
| 42 | |
| 43 | it('clamps to viewport bounds', () => { |
| 44 | const next = clampPosition({ x: 0, y: 0 }, { dx: 500, dy: 900 }, viewport, navSize) |
| 45 | expect(next.x).toBe(300) |
| 46 | expect(next.y).toBe(752) |
| 47 | }) |
| 48 | |
| 49 | it('does not go negative', () => { |
| 50 | const next = clampPosition({ x: 10, y: 10 }, { dx: -20, dy: -20 }, viewport, navSize) |
| 51 | expect(next.x).toBe(0) |
| 52 | expect(next.y).toBe(0) |
| 53 | }) |
| 54 | }) |
| 55 | |
| 56 | describe('getNextPosition', () => { |
| 57 | const viewport = { width: 400, height: 800 } |
| 58 | const navSize = { width: 100, height: 48 } |
| 59 | const dragStart = { x: 50, y: 100, startX: 60, startY: 110 } |
| 60 | |
| 61 | it('returns null when under threshold', () => { |
| 62 | expect(getNextPosition(dragStart, 62, 111, viewport, navSize, 8)).toBeNull() |
| 63 | }) |
| 64 | |
| 65 | it('returns clamped position when over threshold', () => { |
| 66 | const next = getNextPosition(dragStart, 80, 130, viewport, navSize, 5) |
| 67 | expect(next).toEqual({ x: 70, y: 120 }) |
| 68 | }) |
| 69 | }) |
| 70 | |
| 71 | describe('getToolbarStyle', () => { |
| 72 | const viewport = { width: 390, height: 844 } |
| 73 | const navSize = { width: 200, height: 48 } |
| 74 | |
| 75 | it('returns style with transform and zIndex', () => { |
| 76 | const style = getToolbarStyle({ |
| 77 | position: null, |
| 78 | navSize, |
| 79 | isSheetOpen: false, |
| 80 | viewport, |
| 81 | isDragging: false, |
| 82 | }) |
| 83 | expect(style.zIndex).toBe(41) |
| 84 | expect(style.transform).toBeDefined() |
| 85 | expect(style.left).toBe('50%') |
| 86 | }) |
| 87 | |
| 88 | it('uses higher zIndex when sheet open', () => { |
| 89 | const style = getToolbarStyle({ |
| 90 | position: null, |
| 91 | navSize, |
| 92 | isSheetOpen: true, |
| 93 | viewport, |
| 94 | isDragging: false, |
| 95 | }) |
| 96 | expect(style.zIndex).toBe(101) |
| 97 | }) |
| 98 | }) |