@lobehub/chat
Version:
Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.
195 lines (155 loc) • 5.19 kB
text/typescript
import { renderHook } from '@testing-library/react';
import { uniq } from 'lodash-es';
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { HOTKEYS_REGISTRATION } from '@/const/hotkeys';
import { HotkeyEnum, HotkeyScopeEnum } from '@/types/hotkey';
import { useHotkeyById } from './useHotkeyById';
// Mock dependencies
vi.mock('lodash-es', async (importOriginal) => {
const actual: any = await importOriginal();
return {
...actual,
uniq: vi.fn((arr) => [...new Set(arr)]),
};
});
// Mock react-hotkeys-hook
const mockRef = { current: document.createElement('div') };
const mockUseHotkeys = vi.fn(() => mockRef);
vi.mock('react-hotkeys-hook', () => ({
// @ts-ignore
useHotkeys: (...args: any[]) => mockUseHotkeys(...args),
}));
// Mock store and environment
let isMobileValue = false;
const mockHotkey = 'mod+k';
vi.mock('@/store/serverConfig', () => ({
useServerConfigStore: (selector: (state: any) => any) => selector({ isMobile: isMobileValue }),
}));
vi.mock('@/store/user', () => ({
useUserStore: (selector: any) => selector(),
}));
vi.mock('@/store/user/selectors', () => ({
settingsSelectors: {
getHotkeyById: () => () => mockHotkey,
},
}));
vi.mock('@/utils/env', () => ({
isDev: false,
}));
describe('useHotkeyById', () => {
const mockCallback = vi.fn();
beforeEach(() => {
vi.clearAllMocks();
isMobileValue = false;
});
it('should register hotkey with correct parameters', () => {
const { result } = renderHook(() => useHotkeyById(HotkeyEnum.Search, mockCallback));
// 验证 useHotkeys 被调用,但不检查具体函数引用
expect(mockUseHotkeys).toHaveBeenCalled();
// 获取实际调用参数
const callArgs: any = mockUseHotkeys.mock.calls[0];
// 验证第一个参数是正确的热键
expect(callArgs[0]).toBe(mockHotkey);
// 验证第二个参数是函数
expect(typeof callArgs[1]).toBe('function');
// 验证第三个参数包含预期的属性
expect(callArgs[2]).toMatchObject({
enableOnFormTags: true,
preventDefault: true,
scopes: [HotkeyEnum.Search, HotkeyScopeEnum.Global],
});
// 验证第四个参数是 undefined
expect(callArgs[3]).toBeUndefined();
// 验证返回值
expect(result.current).toEqual({
id: HotkeyEnum.Search,
ref: mockRef,
});
});
it('should disable hotkey on mobile devices', () => {
// Set as mobile
isMobileValue = true;
renderHook(() => useHotkeyById(HotkeyEnum.Search, mockCallback, { enabled: true }));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.objectContaining({
enabled: false, // Should be disabled on mobile
}),
undefined,
);
});
it('should handle options parameter correctly', () => {
const options = {
enabled: true,
scopes: ['customScope'],
};
renderHook(() => useHotkeyById(HotkeyEnum.Search, mockCallback, options));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.objectContaining({
enabled: true,
scopes: expect.arrayContaining([HotkeyEnum.Search, HotkeyScopeEnum.Global, 'customScope']),
}),
undefined,
);
expect(uniq).toHaveBeenCalled();
});
it('should handle dependencies parameter correctly', () => {
const deps = [1, 2, 3];
renderHook(() => useHotkeyById(HotkeyEnum.Search, mockCallback, deps));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.any(Object),
deps,
);
});
it('should handle both options and dependencies correctly', () => {
const options = { enabled: true };
const deps = [1, 2, 3];
renderHook(() => useHotkeyById(HotkeyEnum.Search, mockCallback, options, deps));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.objectContaining({
enabled: true,
}),
deps,
);
});
it('should combine scopes from registration and options', () => {
const testHotkeyId = HotkeyEnum.ToggleLeftPanel;
const registrationItem = HOTKEYS_REGISTRATION.find((item) => item.id === testHotkeyId);
const options = {
scopes: ['customScope'],
};
renderHook(() => useHotkeyById(testHotkeyId, mockCallback, options));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.objectContaining({
scopes: expect.arrayContaining([
testHotkeyId,
...(registrationItem?.scopes || []),
'customScope',
]),
}),
undefined,
);
});
it('should handle case when no registration item is found', () => {
// Using a non-existent ID to test this case
const nonExistentId = 'nonExistentId' as any;
renderHook(() => useHotkeyById(nonExistentId, mockCallback));
expect(mockUseHotkeys).toHaveBeenCalledWith(
mockHotkey,
expect.any(Function),
expect.objectContaining({
scopes: expect.arrayContaining([nonExistentId]),
}),
undefined,
);
});
});