mattermost-mobile/app/hooks/header.test.tsx
Joram Wilander 4187e9f81a
MM-59741 + others - Add tests for remaining app/hooks files (#8517)
* test: Add tests for useHandleSendMessage hook

* test: Add tests for header hooks

* test: Add tests for device hooks

* test: Add tests for useChannelSwitch hook

* test: Add tests for useTeamSwitch hook

* test: Add tests for useInputPropagation hook

* test: Add tests for useWhyDidYouUpdate hook

* test: Add tests for useFreeze hook

* test: Add tests for useAutocompleteDefaultAnimatedValues hook

* test: Add tests for usePersistentNotificationProps hook

* test: Add tests for useFetchingThreadState hook

* test: Add tests for useBackNavigation hook

* test: Add tests for useShowMoreAnimatedStyle hook

* test: Add tests for useTeamsLoading hook

* test: Add tests for useNavButtonPressed hook

* test: Add tests for useDidUpdate hook

* test: Add tests for useAppBinding hook

* Fix type error and test
2025-01-28 08:51:50 -05:00

209 lines
7.4 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {renderHook} from '@testing-library/react-hooks';
import {act} from '@testing-library/react-native';
import {useSafeAreaInsets} from 'react-native-safe-area-context';
import ViewConstants from '@constants/view';
import {useIsTablet} from '@hooks/device';
import {useDefaultHeaderHeight, useLargeHeaderHeight, useHeaderHeight, useCollapsibleHeader} from './header';
jest.mock('react-native-reanimated', () => {
const sharedValues = new Map();
return {
...jest.requireActual('react-native-reanimated/mock'),
useAnimatedRef: jest.fn(() => ({
current: {
scrollTo: jest.fn(),
},
})),
useSharedValue: jest.fn((initial) => {
const key = Math.random();
const sv = {
value: initial,
_key: key,
};
sharedValues.set(key, sv);
return sv;
}),
useAnimatedScrollHandler: jest.fn((handlers) => (event: any) => {
if (handlers.onScroll) {
handlers.onScroll(event);
}
}),
scrollTo: jest.fn(),
};
});
jest.mock('react-native-safe-area-context', () => ({
useSafeAreaInsets: jest.fn(),
}));
jest.mock('@hooks/device', () => ({
useIsTablet: jest.fn(),
}));
describe('Header Hooks', () => {
beforeEach(() => {
(useSafeAreaInsets as jest.Mock).mockReturnValue({top: 20});
(useIsTablet as jest.Mock).mockReturnValue(false);
});
describe('useDefaultHeaderHeight', () => {
it('should return correct height for mobile', () => {
const {result} = renderHook(() => useDefaultHeaderHeight());
expect(result.current).toBe(ViewConstants.DEFAULT_HEADER_HEIGHT + 20);
});
it('should return correct height for tablet', () => {
(useIsTablet as jest.Mock).mockReturnValue(true);
const {result} = renderHook(() => useDefaultHeaderHeight());
expect(result.current).toBe(ViewConstants.TABLET_HEADER_HEIGHT + 20);
});
});
describe('useLargeHeaderHeight', () => {
it('should return correct large header height', () => {
const {result} = renderHook(() => useLargeHeaderHeight());
const expectedHeight = ViewConstants.DEFAULT_HEADER_HEIGHT +
ViewConstants.LARGE_HEADER_TITLE_HEIGHT +
ViewConstants.SUBTITLE_HEIGHT + 20;
expect(result.current).toBe(expectedHeight);
});
});
describe('useHeaderHeight', () => {
it('should return correct height values', () => {
const {result} = renderHook(() => useHeaderHeight());
const defaultHeight = ViewConstants.DEFAULT_HEADER_HEIGHT + 20;
const largeHeight = defaultHeight +
ViewConstants.LARGE_HEADER_TITLE_HEIGHT +
ViewConstants.SUBTITLE_HEIGHT;
expect(result.current).toEqual({
defaultHeight,
largeHeight,
headerOffset: largeHeight - defaultHeight,
});
});
});
describe('useCollapsibleHeader', () => {
const mockScrollTo = jest.fn();
const mockScrollToOffset = jest.fn();
beforeEach(() => {
jest.clearAllMocks();
});
it('should initialize with correct values', () => {
const onSnap = jest.fn();
const {result} = renderHook(() => useCollapsibleHeader(true, onSnap));
expect(result.current.defaultHeight).toBeDefined();
expect(result.current.largeHeight).toBeDefined();
expect(result.current.scrollPaddingTop).toBeDefined();
expect(result.current.scrollRef).toBeDefined();
expect(result.current.scrollValue).toBeDefined();
expect(result.current.onScroll).toBeDefined();
expect(result.current.hideHeader).toBeDefined();
expect(result.current.lockValue).toBe(0);
expect(result.current.scrollEnabled.value).toBe(true);
});
it('should handle header lock and unlock', () => {
const {result} = renderHook(() => useCollapsibleHeader(true));
act(() => {
result.current.hideHeader(true);
});
expect(result.current.lockValue).toBe(result.current.defaultHeight);
act(() => {
result.current.scrollEnabled.value = false;
});
expect(result.current.scrollEnabled.value).toBe(false);
act(() => {
result.current.unlock();
});
expect(result.current.lockValue).toBe(0);
expect(result.current.scrollEnabled.value).toBe(true);
});
it('should handle auto-scroll correctly', () => {
const {result} = renderHook(() => useCollapsibleHeader(true));
act(() => {
result.current.setAutoScroll(true);
});
expect(result.current.scrollValue.value).toBe(0);
});
it('should calculate correct scroll padding for large and normal headers', () => {
const {result: largeTitleResult} = renderHook(() => useCollapsibleHeader(true));
const {result: normalTitleResult} = renderHook(() => useCollapsibleHeader(false));
expect(largeTitleResult.current.scrollPaddingTop).toBe(largeTitleResult.current.largeHeight);
expect(normalTitleResult.current.scrollPaddingTop).toBe(normalTitleResult.current.defaultHeight);
});
it('should handle hideHeader with scrollTo', () => {
const {result} = renderHook(() => useCollapsibleHeader(true));
// @ts-expect-error override for test mock
result.current.scrollRef.current = {
scrollTo: mockScrollTo,
} as any;
act(() => {
result.current.hideHeader();
});
expect(mockScrollTo).toHaveBeenCalledWith({
y: result.current.headerOffset,
animated: true,
});
});
it('should handle hideHeader with scrollToOffset', () => {
const {result} = renderHook(() => useCollapsibleHeader(true));
// @ts-expect-error override for test mock
result.current.scrollRef.current = {
scrollToOffset: mockScrollToOffset,
} as any;
act(() => {
result.current.hideHeader();
});
expect(mockScrollToOffset).toHaveBeenCalledWith({
offset: result.current.headerOffset,
animated: true,
});
});
it('should handle snap callback', () => {
const onSnap = jest.fn();
const {result} = renderHook(() => useCollapsibleHeader(true, onSnap));
act(() => {
const mockScrollEvent = {
contentOffset: {y: 10},
contentSize: {height: 1000},
layoutMeasurement: {height: 100},
};
// Simulate scroll event
result.current.scrollValue.value = mockScrollEvent.contentOffset.y;
result.current.onScroll(mockScrollEvent as any);
});
expect(result.current.scrollValue.value).toBe(10);
});
});
});