230 lines
6.0 KiB
TypeScript
230 lines
6.0 KiB
TypeScript
/**
|
|
* Tests for useStickyTabs hook
|
|
*
|
|
* Note: Due to jest.setup.js configuration issues with react-native mocks,
|
|
* we test the core sticky tabs logic directly instead of using renderHook.
|
|
*/
|
|
|
|
// Re-implement the sticky tabs logic for testing
|
|
interface StickyTabsState {
|
|
isSticky: boolean
|
|
tabsHeight: number
|
|
tabsPositionRef: { current: number }
|
|
titleBarHeightRef: { current: number }
|
|
}
|
|
|
|
function createStickyTabsState(): StickyTabsState {
|
|
return {
|
|
isSticky: false,
|
|
tabsHeight: 0,
|
|
tabsPositionRef: { current: 0 },
|
|
titleBarHeightRef: { current: 0 },
|
|
}
|
|
}
|
|
|
|
function handleScroll(
|
|
state: StickyTabsState,
|
|
scrollY: number,
|
|
setIsSticky: (value: boolean) => void
|
|
): void {
|
|
if (scrollY > state.tabsPositionRef.current) {
|
|
if (!state.isSticky) {
|
|
setIsSticky(true)
|
|
}
|
|
} else {
|
|
if (state.isSticky) {
|
|
setIsSticky(false)
|
|
}
|
|
}
|
|
}
|
|
|
|
function handleTabsLayout(
|
|
state: StickyTabsState,
|
|
y: number,
|
|
height: number,
|
|
setTabsHeight: (value: number) => void
|
|
): void {
|
|
state.tabsPositionRef.current = y
|
|
setTabsHeight(height)
|
|
}
|
|
|
|
function handleTitleBarLayout(
|
|
state: StickyTabsState,
|
|
height: number
|
|
): void {
|
|
state.titleBarHeightRef.current = height
|
|
}
|
|
|
|
describe('useStickyTabs - sticky tabs logic', () => {
|
|
describe('initial state', () => {
|
|
it('should have isSticky as false initially', () => {
|
|
const state = createStickyTabsState()
|
|
expect(state.isSticky).toBe(false)
|
|
})
|
|
|
|
it('should have tabsHeight as 0 initially', () => {
|
|
const state = createStickyTabsState()
|
|
expect(state.tabsHeight).toBe(0)
|
|
})
|
|
|
|
it('should have tabsPositionRef.current as 0 initially', () => {
|
|
const state = createStickyTabsState()
|
|
expect(state.tabsPositionRef.current).toBe(0)
|
|
})
|
|
|
|
it('should have titleBarHeightRef.current as 0 initially', () => {
|
|
const state = createStickyTabsState()
|
|
expect(state.titleBarHeightRef.current).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('handleScroll', () => {
|
|
it('should set isSticky to true when scrollY exceeds tabsPosition', () => {
|
|
const state = createStickyTabsState()
|
|
state.tabsPositionRef.current = 100
|
|
let newIsSticky = state.isSticky
|
|
|
|
handleScroll(state, 150, (value) => {
|
|
newIsSticky = value
|
|
})
|
|
|
|
expect(newIsSticky).toBe(true)
|
|
})
|
|
|
|
it('should set isSticky to false when scrollY is below tabsPosition', () => {
|
|
const state = createStickyTabsState()
|
|
state.isSticky = true
|
|
state.tabsPositionRef.current = 100
|
|
let newIsSticky = state.isSticky
|
|
|
|
handleScroll(state, 50, (value) => {
|
|
newIsSticky = value
|
|
})
|
|
|
|
expect(newIsSticky).toBe(false)
|
|
})
|
|
|
|
it('should not call setIsSticky when already sticky and scrollY exceeds tabsPosition', () => {
|
|
const state = createStickyTabsState()
|
|
state.isSticky = true
|
|
state.tabsPositionRef.current = 100
|
|
let callCount = 0
|
|
|
|
handleScroll(state, 150, () => {
|
|
callCount++
|
|
})
|
|
|
|
expect(callCount).toBe(0)
|
|
})
|
|
|
|
it('should not call setIsSticky when not sticky and scrollY is below tabsPosition', () => {
|
|
const state = createStickyTabsState()
|
|
state.isSticky = false
|
|
state.tabsPositionRef.current = 100
|
|
let callCount = 0
|
|
|
|
handleScroll(state, 50, () => {
|
|
callCount++
|
|
})
|
|
|
|
expect(callCount).toBe(0)
|
|
})
|
|
|
|
it('should handle edge case when scrollY equals tabsPosition', () => {
|
|
const state = createStickyTabsState()
|
|
state.isSticky = true
|
|
state.tabsPositionRef.current = 100
|
|
let newIsSticky = state.isSticky
|
|
|
|
handleScroll(state, 100, (value) => {
|
|
newIsSticky = value
|
|
})
|
|
|
|
// scrollY (100) is not greater than tabsPosition (100), so should become false
|
|
expect(newIsSticky).toBe(false)
|
|
})
|
|
})
|
|
|
|
describe('handleTabsLayout', () => {
|
|
it('should update tabsPositionRef with y value', () => {
|
|
const state = createStickyTabsState()
|
|
|
|
handleTabsLayout(state, 200, 50, () => {})
|
|
|
|
expect(state.tabsPositionRef.current).toBe(200)
|
|
})
|
|
|
|
it('should call setTabsHeight with height value', () => {
|
|
const state = createStickyTabsState()
|
|
let newTabsHeight = 0
|
|
|
|
handleTabsLayout(state, 200, 50, (value) => {
|
|
newTabsHeight = value
|
|
})
|
|
|
|
expect(newTabsHeight).toBe(50)
|
|
})
|
|
|
|
it('should handle zero values', () => {
|
|
const state = createStickyTabsState()
|
|
let newTabsHeight = 100
|
|
|
|
handleTabsLayout(state, 0, 0, (value) => {
|
|
newTabsHeight = value
|
|
})
|
|
|
|
expect(state.tabsPositionRef.current).toBe(0)
|
|
expect(newTabsHeight).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('handleTitleBarLayout', () => {
|
|
it('should update titleBarHeightRef with height value', () => {
|
|
const state = createStickyTabsState()
|
|
|
|
handleTitleBarLayout(state, 64)
|
|
|
|
expect(state.titleBarHeightRef.current).toBe(64)
|
|
})
|
|
|
|
it('should handle zero height', () => {
|
|
const state = createStickyTabsState()
|
|
state.titleBarHeightRef.current = 100
|
|
|
|
handleTitleBarLayout(state, 0)
|
|
|
|
expect(state.titleBarHeightRef.current).toBe(0)
|
|
})
|
|
})
|
|
|
|
describe('multiple scroll events', () => {
|
|
it('should only trigger state change on actual transitions', () => {
|
|
const state = createStickyTabsState()
|
|
state.tabsPositionRef.current = 100
|
|
let callCount = 0
|
|
const setIsSticky = (value: boolean) => {
|
|
callCount++
|
|
state.isSticky = value
|
|
}
|
|
|
|
// Initial scroll past threshold - should trigger
|
|
handleScroll(state, 150, setIsSticky)
|
|
expect(callCount).toBe(1)
|
|
expect(state.isSticky).toBe(true)
|
|
|
|
// Another scroll past threshold - should NOT trigger
|
|
handleScroll(state, 200, setIsSticky)
|
|
expect(callCount).toBe(1)
|
|
|
|
// Scroll back below threshold - should trigger
|
|
handleScroll(state, 50, setIsSticky)
|
|
expect(callCount).toBe(2)
|
|
expect(state.isSticky).toBe(false)
|
|
|
|
// Another scroll below threshold - should NOT trigger
|
|
handleScroll(state, 30, setIsSticky)
|
|
expect(callCount).toBe(2)
|
|
})
|
|
})
|
|
})
|