Files
readest/apps/readest-app/src/__tests__/components/useBookShortcuts.test.tsx
T
Mohammed Efaz 888f4afde9 fix: preserve paragraph mode reading layouts and other UI/UX fixes (#3730)
* fix: paragraph mode

* test: paragraph mode

* test: remove paragraph mode

* fix: paragraph utils

* fix: paragraph hook

* fix: paragraph overlay

* fix: paragraph bar

* fix: paragraph control

* fix: paragraph shortcuts

* test: paragraph utils

* test: paragraph hook

* test: paragraph overlay

* test: paragraph shortcuts

* fix: paragraph overlay

* test: paragraph mode

* test: shortcuts

* test: remove overlay

* test: remove hook

* test: remove utils

* fix: paragraph overlay

* fix: paragraph overlay

* feat: paragraph overlay

* fix: vertical container sizing

* test: paragraph container

* fix: paragraph animation

* fix: paragraph text animation

* fix: remove container morph
2026-04-02 20:56:38 +02:00

181 lines
4.3 KiB
TypeScript

import { cleanup, render } from '@testing-library/react';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import useBookShortcuts from '@/app/reader/hooks/useBookShortcuts';
import { eventDispatcher } from '@/utils/event';
const shortcutState = {
actions: null as Record<
string,
((event?: KeyboardEvent | MessageEvent) => void) | undefined
> | null,
};
const mockView = {
book: { dir: 'ltr' },
prev: vi.fn(),
next: vi.fn(),
pan: vi.fn(),
renderer: {
scrolled: false,
setAttribute: vi.fn(),
},
history: {
back: vi.fn(),
forward: vi.fn(),
},
};
const currentViewSettings = {
defaultFontSize: 16,
lineHeight: 1.5,
readingRulerEnabled: true,
writingMode: 'horizontal-tb',
vertical: false,
rtl: false,
paragraphMode: { enabled: false },
};
vi.mock('@/store/readerStore', () => ({
useReaderStore: () => ({
getView: () => mockView,
getViewState: () => ({ ttsEnabled: false }),
getViewSettings: () => currentViewSettings,
setViewSettings: vi.fn(),
}),
}));
vi.mock('@/store/sidebarStore', () => ({
useSidebarStore: () => ({
toggleSideBar: vi.fn(),
setSideBarBookKey: vi.fn(),
}),
}));
vi.mock('@/store/settingsStore', () => ({
useSettingsStore: () => ({
setSettingsDialogOpen: vi.fn(),
}),
}));
vi.mock('@/store/bookDataStore', () => ({
useBookDataStore: () => ({
getBookData: vi.fn(),
}),
}));
vi.mock('@/store/notebookStore', () => ({
useNotebookStore: () => ({
toggleNotebook: vi.fn(),
}),
}));
vi.mock('@/store/themeStore', () => ({
useThemeStore: () => ({
safeAreaInsets: null,
}),
}));
vi.mock('@/components/command-palette', () => ({
useCommandPalette: () => ({
open: vi.fn(),
}),
}));
vi.mock('@/hooks/useShortcuts', () => ({
default: (actions: typeof shortcutState.actions) => {
shortcutState.actions = actions;
},
}));
vi.mock('@/services/environment', () => ({
isTauriAppPlatform: () => false,
}));
vi.mock('@/utils/window', () => ({
tauriHandleClose: vi.fn(),
tauriHandleToggleFullScreen: vi.fn(),
tauriQuitApp: vi.fn(),
}));
vi.mock('@/utils/style', () => ({
getStyles: vi.fn(),
}));
vi.mock('@/services/constants', () => ({
MAX_ZOOM_LEVEL: 200,
MIN_ZOOM_LEVEL: 50,
ZOOM_STEP: 10,
}));
vi.mock('@/app/reader/hooks/useBooksManager', () => ({
default: () => ({
getNextBookKey: () => 'book-1',
}),
}));
const Harness = () => {
useBookShortcuts({ sideBarBookKey: 'book-1', bookKeys: ['book-1'] });
return null;
};
describe('useBookShortcuts', () => {
beforeEach(() => {
vi.clearAllMocks();
shortcutState.actions = null;
currentViewSettings.readingRulerEnabled = true;
currentViewSettings.writingMode = 'horizontal-tb';
currentViewSettings.vertical = false;
currentViewSettings.rtl = false;
currentViewSettings.paragraphMode.enabled = false;
mockView.book.dir = 'ltr';
});
afterEach(() => {
cleanup();
});
it('routes page-turn shortcuts to reading ruler movement when enabled', () => {
const dispatchSpy = vi.spyOn(eventDispatcher, 'dispatchSync').mockReturnValue(true);
render(<Harness />);
shortcutState.actions?.['onGoNext']?.();
expect(dispatchSpy).toHaveBeenCalledWith('reading-ruler-move', {
bookKey: 'book-1',
direction: 'forward',
});
expect(mockView.next).not.toHaveBeenCalled();
});
it('uses reading order when directional shortcuts are handled in rtl books', () => {
const dispatchSpy = vi.spyOn(eventDispatcher, 'dispatchSync').mockReturnValue(true);
mockView.book.dir = 'rtl';
render(<Harness />);
shortcutState.actions?.['onGoRight']?.();
expect(dispatchSpy).toHaveBeenCalledWith('reading-ruler-move', {
bookKey: 'book-1',
direction: 'backward',
});
});
it('falls back to normal page navigation when the ruler is disabled', () => {
currentViewSettings.readingRulerEnabled = false;
render(<Harness />);
shortcutState.actions?.['onGoNext']?.();
expect(mockView.next).toHaveBeenCalledWith(72);
});
it('falls back to normal page navigation when the ruler cannot move further', () => {
vi.spyOn(eventDispatcher, 'dispatchSync').mockReturnValue(false);
render(<Harness />);
shortcutState.actions?.['onGoNext']?.();
expect(mockView.next).toHaveBeenCalledWith(72);
});
});