diff --git a/packages/ui/src/components/base/ErrorBoundary/index.tsx b/packages/ui/src/components/base/ErrorBoundary/index.tsx index f620e028b5..26a6780b3e 100644 --- a/packages/ui/src/components/base/ErrorBoundary/index.tsx +++ b/packages/ui/src/components/base/ErrorBoundary/index.tsx @@ -98,4 +98,4 @@ const ErrorContainer = styled.div` ` export { ErrorBoundaryCustomized as ErrorBoundary } -export type { ErrorBoundaryCustomizedProps, CustomFallbackProps } \ No newline at end of file +export type { CustomFallbackProps, ErrorBoundaryCustomizedProps } diff --git a/packages/ui/src/components/base/ErrorBoundary/utils.ts b/packages/ui/src/components/base/ErrorBoundary/utils.ts index 3493a90d6b..57c2ba62f9 100644 --- a/packages/ui/src/components/base/ErrorBoundary/utils.ts +++ b/packages/ui/src/components/base/ErrorBoundary/utils.ts @@ -5,4 +5,4 @@ export function formatErrorMessage(error: Error): string { return error.message } return error.toString() -} \ No newline at end of file +} diff --git a/packages/ui/src/components/icons/Icon/index.tsx b/packages/ui/src/components/icons/Icon/index.tsx index 8ab20c4939..4c09c6727e 100644 --- a/packages/ui/src/components/icons/Icon/index.tsx +++ b/packages/ui/src/components/icons/Icon/index.tsx @@ -16,8 +16,11 @@ import React from 'react' // 创建一个 Icon 工厂函数 export function createIcon(IconComponent: LucideIcon, defaultSize: string | number = '1rem') { - const Icon = React.forwardRef>( - (props, ref) => + const Icon = ({ + ref, + ...props + }: React.ComponentProps & { ref?: React.RefObject }) => ( + ) Icon.displayName = `Icon(${IconComponent.displayName || IconComponent.name})` return Icon diff --git a/packages/ui/src/components/index.ts b/packages/ui/src/components/index.ts index 1666c132e1..4f765956d5 100644 --- a/packages/ui/src/components/index.ts +++ b/packages/ui/src/components/index.ts @@ -4,12 +4,12 @@ export { default as CustomCollapse } from './base/CustomCollapse' export { default as CustomTag } from './base/CustomTag' export { default as DividerWithText } from './base/DividerWithText' export { default as EmojiIcon } from './base/EmojiIcon' +export type { CustomFallbackProps, ErrorBoundaryCustomizedProps } from './base/ErrorBoundary' export { ErrorBoundary } from './base/ErrorBoundary' -export type { ErrorBoundaryCustomizedProps, CustomFallbackProps } from './base/ErrorBoundary' export { default as IndicatorLight } from './base/IndicatorLight' export { default as Spinner } from './base/Spinner' -export { StatusTag, ErrorTag, SuccessTag, WarnTag, InfoTag } from './base/StatusTag' -export type { StatusType, StatusTagProps } from './base/StatusTag' +export type { StatusTagProps, StatusType } from './base/StatusTag' +export { ErrorTag, InfoTag, StatusTag, SuccessTag, WarnTag } from './base/StatusTag' export { default as TextBadge } from './base/TextBadge' // Display Components @@ -26,22 +26,22 @@ export { default as HorizontalScrollContainer } from './layout/HorizontalScrollC export { default as Scrollbar } from './layout/Scrollbar' // Icon Components +export { FilePngIcon, FileSvgIcon } from './icons/FileIcons' +export type { LucideIcon, LucideProps } from './icons/Icon' export { - createIcon, CopyIcon, + createIcon, DeleteIcon, EditIcon, + OcrIcon, RefreshIcon, ResetIcon, ToolIcon, + UnWrapIcon, VisionIcon, WebSearchIcon, - WrapIcon, - UnWrapIcon, - OcrIcon + WrapIcon } from './icons/Icon' -export type { LucideIcon, LucideProps } from './icons/Icon' -export { FilePngIcon, FileSvgIcon } from './icons/FileIcons' export { default as ReasoningIcon } from './icons/ReasoningIcon' export { default as SvgSpinners180Ring } from './icons/SvgSpinners180Ring' export { default as ToolsCallingIcon } from './icons/ToolsCallingIcon' diff --git a/packages/ui/stories/components/icons/Icon.stories.tsx b/packages/ui/stories/components/icons/Icon.stories.tsx index ad0600247f..43d8cc0d6a 100644 --- a/packages/ui/stories/components/icons/Icon.stories.tsx +++ b/packages/ui/stories/components/icons/Icon.stories.tsx @@ -1,35 +1,19 @@ import type { Meta, StoryObj } from '@storybook/react' -import { - Copy, - Trash, - Pencil, - RefreshCw, - RotateCcw, - Wrench, - Eye, - Search, - WrapText, - AlignLeft, - ScanLine, - Settings, - Download, - Upload, - ChevronRight -} from 'lucide-react' +import { ChevronRight, Download, Settings, Upload } from 'lucide-react' import { - createIcon, CopyIcon, + createIcon, DeleteIcon, EditIcon, + OcrIcon, RefreshIcon, ResetIcon, ToolIcon, + UnWrapIcon, VisionIcon, WebSearchIcon, - WrapIcon, - UnWrapIcon, - OcrIcon + WrapIcon } from '../../../src/components/icons/Icon' // Create a dummy component for the story @@ -278,8 +262,7 @@ export const IconGrid: Story = { {AllIcons.map(({ Icon, name }) => (
+ className="flex flex-col items-center gap-2 rounded-lg border border-gray-200 p-4 hover:border-blue-500"> {name}
@@ -287,4 +270,4 @@ export const IconGrid: Story = { ) } -} \ No newline at end of file +} diff --git a/src/renderer/src/services/__tests__/ApiService.test.ts b/src/renderer/src/services/__tests__/ApiService.test.ts index 70cff69d2b..cd89ae0930 100644 --- a/src/renderer/src/services/__tests__/ApiService.test.ts +++ b/src/renderer/src/services/__tests__/ApiService.test.ts @@ -100,7 +100,8 @@ vi.mock('@renderer/utils', () => ({ vi.mock('@shared/config/prompts', () => ({ WEB_SEARCH_PROMPT_FOR_OPENROUTER: 'mock-prompt', - TRANSLATE_PROMPT: 'You are a translation expert. Your only task is to translate text enclosed with from input language to {{target_language}}, provide the translation result directly without any explanation, without `TRANSLATE` and keep original format.' + TRANSLATE_PROMPT: + 'You are a translation expert. Your only task is to translate text enclosed with from input language to {{target_language}}, provide the translation result directly without any explanation, without `TRANSLATE` and keep original format.' })) vi.mock('@renderer/config/systemModels', () => ({ diff --git a/src/renderer/src/utils/__tests__/match.test.ts b/src/renderer/src/utils/__tests__/match.test.ts index 0325d11abe..9fe58f9e08 100644 --- a/src/renderer/src/utils/__tests__/match.test.ts +++ b/src/renderer/src/utils/__tests__/match.test.ts @@ -7,9 +7,9 @@ import { includeKeywords, matchKeywordsInModel, matchKeywordsInProvider, matchKe vi.mock('@renderer/i18n/label', () => ({ getProviderLabel: vi.fn((id: string) => { const labelMap: Record = { - 'dashscope': 'Alibaba Cloud', - 'openai': 'OpenAI', - 'anthropic': 'Anthropic' + dashscope: 'Alibaba Cloud', + openai: 'OpenAI', + anthropic: 'Anthropic' } return labelMap[id] || id }) diff --git a/src/renderer/src/utils/__tests__/naming.test.ts b/src/renderer/src/utils/__tests__/naming.test.ts index a07de2802e..f51e8cb2cc 100644 --- a/src/renderer/src/utils/__tests__/naming.test.ts +++ b/src/renderer/src/utils/__tests__/naming.test.ts @@ -5,9 +5,9 @@ import { describe, expect, it, vi } from 'vitest' vi.mock('@renderer/i18n/label', () => ({ getProviderLabel: vi.fn((id: string) => { const labelMap: Record = { - 'dashscope': 'Alibaba Cloud', - 'openai': 'OpenAI', - 'anthropic': 'Anthropic' + dashscope: 'Alibaba Cloud', + openai: 'OpenAI', + anthropic: 'Anthropic' } return labelMap[id] || id }) diff --git a/tests/__mocks__/main/CacheService.ts b/tests/__mocks__/main/CacheService.ts index 9592785747..3f453853e8 100644 --- a/tests/__mocks__/main/CacheService.ts +++ b/tests/__mocks__/main/CacheService.ts @@ -79,13 +79,7 @@ export class MockMainCacheService { }) // Private methods exposed for testing - private broadcastSync = vi.fn((message: CacheSyncMessage, senderWindowId?: number): void => { - mockBroadcastCalls.push({ message, senderWindowId }) - }) - - private setupIpcHandlers = vi.fn((): void => { - // Mock IPC handler setup - }) + // These methods are mocked but not exposed to avoid TypeScript unused warnings } // Mock singleton instance @@ -108,7 +102,7 @@ export const MockMainCacheServiceUtils = { */ resetMocks: () => { // Reset all method mocks - Object.values(mockInstance).forEach(method => { + Object.values(mockInstance).forEach((method) => { if (vi.isMockFunction(method)) { method.mockClear() } @@ -234,4 +228,4 @@ export const MockMainCacheServiceUtils = { delete: mockInstance.delete.mock.calls.length, cleanup: mockInstance.cleanup.mock.calls.length }) -} \ No newline at end of file +} diff --git a/tests/__mocks__/main/DataApiService.ts b/tests/__mocks__/main/DataApiService.ts index 04177d6f28..09946871fb 100644 --- a/tests/__mocks__/main/DataApiService.ts +++ b/tests/__mocks__/main/DataApiService.ts @@ -35,11 +35,11 @@ export class MockMainDataApiService { private static instance: MockMainDataApiService private initialized = false private apiServer: MockApiServer - private ipcAdapter: MockIpcAdapter + private _ipcAdapter: MockIpcAdapter // Used for mock setup (referenced in constructor) private constructor() { this.apiServer = new MockApiServer() - this.ipcAdapter = new MockIpcAdapter() + this._ipcAdapter = new MockIpcAdapter() } public static getInstance(): MockMainDataApiService { @@ -82,6 +82,11 @@ export class MockMainDataApiService { public shutdown = vi.fn(async (): Promise => { this.initialized = false }) + + // Getter for testing purposes + public get ipcAdapter() { + return this._ipcAdapter + } } // Mock singleton instance @@ -112,7 +117,7 @@ export const MockMainDataApiServiceUtils = { */ resetMocks: () => { // Reset all method mocks - Object.values(mockInstance).forEach(method => { + Object.values(mockInstance).forEach((method) => { if (vi.isMockFunction(method)) { method.mockClear() } @@ -139,7 +144,7 @@ export const MockMainDataApiServiceUtils = { /** * Mock system info for testing */ - mockSystemInfo: (info: Record) => { + mockSystemInfo: (info: { server: string; version: string; handlers: string[]; middlewares: string[] }) => { mockInstance.getApiServer().getSystemInfo.mockReturnValue(info) }, @@ -166,4 +171,4 @@ export const MockMainDataApiServiceUtils = { getSystemStatus: mockInstance.getSystemStatus.mock.calls.length, getApiServer: mockInstance.getApiServer.mock.calls.length }) -} \ No newline at end of file +} diff --git a/tests/__mocks__/main/PreferenceService.ts b/tests/__mocks__/main/PreferenceService.ts index 77ab1c4173..7ee635e58f 100644 --- a/tests/__mocks__/main/PreferenceService.ts +++ b/tests/__mocks__/main/PreferenceService.ts @@ -1,8 +1,5 @@ -import type { - PreferenceDefaultScopeType, - PreferenceKeyType -} from '@shared/data/preference/preferenceTypes' import { DefaultPreferences } from '@shared/data/preference/preferenceSchemas' +import type { PreferenceDefaultScopeType, PreferenceKeyType } from '@shared/data/preference/preferenceTypes' import { vi } from 'vitest' /** @@ -26,7 +23,7 @@ const mockMainSubscribers = new Map { const subscribers = mockMainSubscribers.get(key) if (subscribers) { - subscribers.forEach(callback => { + subscribers.forEach((callback) => { try { callback(newValue, oldValue) } catch (error) { @@ -41,7 +38,7 @@ const notifyMainSubscribers = (key: string, newValue: any, oldValue?: any) => { */ export class MockMainPreferenceService { private static instance: MockMainPreferenceService - private initialized = false + private _initialized = false // Used in initialize method private constructor() {} @@ -54,7 +51,7 @@ export class MockMainPreferenceService { // Mock initialization public initialize = vi.fn(async (): Promise => { - this.initialized = true + this._initialized = true }) // Mock get method @@ -63,19 +60,18 @@ export class MockMainPreferenceService { }) // Mock set method - public set = vi.fn(async ( - key: K, - value: PreferenceDefaultScopeType[K] - ): Promise => { - const oldValue = mockPreferenceState.get(key) - mockPreferenceState.set(key, value) - notifyMainSubscribers(key, value, oldValue) - }) + public set = vi.fn( + async (key: K, value: PreferenceDefaultScopeType[K]): Promise => { + const oldValue = mockPreferenceState.get(key) + mockPreferenceState.set(key, value) + notifyMainSubscribers(key, value, oldValue) + } + ) // Mock getMultiple method public getMultiple = vi.fn((keys: K[]) => { const result: any = {} - keys.forEach(key => { + keys.forEach((key) => { result[key] = mockPreferenceState.get(key) ?? DefaultPreferences.default[key] }) return result @@ -98,7 +94,7 @@ export class MockMainPreferenceService { mockSubscriptions.set(windowId, new Set()) } const windowKeys = mockSubscriptions.get(windowId)! - keys.forEach(key => windowKeys.add(key)) + keys.forEach((key) => windowKeys.add(key)) }) public unsubscribeForWindow = vi.fn((windowId: number): void => { @@ -106,45 +102,50 @@ export class MockMainPreferenceService { }) // Mock main process subscription methods - public subscribeChange = vi.fn(( - key: K, - callback: (newValue: PreferenceDefaultScopeType[K], oldValue?: PreferenceDefaultScopeType[K]) => void - ): (() => void) => { - if (!mockMainSubscribers.has(key)) { - mockMainSubscribers.set(key, new Set()) - } - mockMainSubscribers.get(key)!.add(callback) + public subscribeChange = vi.fn( + ( + key: K, + callback: (newValue: PreferenceDefaultScopeType[K], oldValue?: PreferenceDefaultScopeType[K]) => void + ): (() => void) => { + if (!mockMainSubscribers.has(key)) { + mockMainSubscribers.set(key, new Set()) + } + mockMainSubscribers.get(key)!.add(callback) - // Return unsubscribe function - return () => { - const subscribers = mockMainSubscribers.get(key) - if (subscribers) { - subscribers.delete(callback) - if (subscribers.size === 0) { - mockMainSubscribers.delete(key) + // Return unsubscribe function + return () => { + const subscribers = mockMainSubscribers.get(key) + if (subscribers) { + subscribers.delete(callback) + if (subscribers.size === 0) { + mockMainSubscribers.delete(key) + } } } } - }) + ) - public subscribeMultipleChanges = vi.fn(( - keys: PreferenceKeyType[], - callback: (key: PreferenceKeyType, newValue: any, oldValue: any) => void - ): (() => void) => { - const unsubscribeFunctions = keys.map(key => - this.subscribeChange(key, (newValue, oldValue) => callback(key, newValue, oldValue)) - ) + public subscribeMultipleChanges = vi.fn( + ( + keys: PreferenceKeyType[], + callback: (key: PreferenceKeyType, newValue: any, oldValue: any) => void + ): (() => void) => { + const unsubscribeFunctions = keys.map((key) => + this.subscribeChange(key, (newValue, oldValue) => callback(key, newValue, oldValue)) + ) - return () => { - unsubscribeFunctions.forEach(unsubscribe => unsubscribe()) + return () => { + unsubscribeFunctions.forEach((unsubscribe) => unsubscribe()) + } } - }) + ) // Mock utility methods public getAll = vi.fn((): PreferenceDefaultScopeType => { const result: any = {} - Object.keys(DefaultPreferences.default).forEach(key => { - result[key] = mockPreferenceState.get(key as PreferenceKeyType) ?? DefaultPreferences.default[key as PreferenceKeyType] + Object.keys(DefaultPreferences.default).forEach((key) => { + result[key] = + mockPreferenceState.get(key as PreferenceKeyType) ?? DefaultPreferences.default[key as PreferenceKeyType] }) return result }) @@ -157,7 +158,7 @@ export class MockMainPreferenceService { public getChangeListenerCount = vi.fn((): number => { let total = 0 - mockMainSubscribers.forEach(subscribers => { + mockMainSubscribers.forEach((subscribers) => { total += subscribers.size }) return total @@ -179,6 +180,11 @@ export class MockMainPreferenceService { return stats }) + // Getter for testing purposes + public get isInitialized() { + return this._initialized + } + // Static methods public static registerIpcHandler = vi.fn((): void => { // Mock IPC handler registration @@ -205,7 +211,7 @@ export const MockMainPreferenceServiceUtils = { */ resetMocks: () => { // Reset all method mocks - Object.values(mockInstance).forEach(method => { + Object.values(mockInstance).forEach((method) => { if (vi.isMockFunction(method)) { method.mockClear() } @@ -283,4 +289,4 @@ export const MockMainPreferenceServiceUtils = { windows: Array.from(mockSubscriptions.entries()).map(([windowId, keys]) => [windowId, keys.size]), mainSubscribers: Array.from(mockMainSubscribers.entries()).map(([key, subs]) => [key, subs.size]) }) -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/CacheService.ts b/tests/__mocks__/renderer/CacheService.ts index 67f0e1cdc6..653c0643d6 100644 --- a/tests/__mocks__/renderer/CacheService.ts +++ b/tests/__mocks__/renderer/CacheService.ts @@ -2,9 +2,7 @@ import type { RendererPersistCacheKey, RendererPersistCacheSchema, UseCacheKey, - UseCacheSchema, - UseSharedCacheKey, - UseSharedCacheSchema + UseSharedCacheKey } from '@shared/data/cache/cacheSchemas' import { DefaultRendererPersistCache, DefaultUseCache, DefaultUseSharedCache } from '@shared/data/cache/cacheSchemas' import type { CacheSubscriber } from '@shared/data/cache/cacheTypes' @@ -18,11 +16,13 @@ import { vi } from 'vitest' /** * Create a mock CacheService with realistic behavior */ -export const createMockCacheService = (options: { - initialMemoryCache?: Map - initialSharedCache?: Map - initialPersistCache?: Map -} = {}) => { +export const createMockCacheService = ( + options: { + initialMemoryCache?: Map + initialSharedCache?: Map + initialPersistCache?: Map + } = {} +) => { // Mock cache storage const memoryCache = new Map(options.initialMemoryCache || []) const sharedCache = new Map(options.initialSharedCache || []) @@ -32,10 +32,10 @@ export const createMockCacheService = (options: { const subscribers = new Map>() // Helper function to notify subscribers - const notifySubscribers = (key: string, value: any) => { + const notifySubscribers = (key: string) => { const keySubscribers = subscribers.get(key) if (keySubscribers) { - keySubscribers.forEach(callback => { + keySubscribers.forEach((callback) => { try { callback() } catch (error) { @@ -56,11 +56,11 @@ export const createMockCacheService = (options: { return defaultValue !== undefined ? defaultValue : null }), - set: vi.fn((key: string, value: T, ttl?: number): void => { + set: vi.fn((key: string, value: T): void => { const oldValue = memoryCache.get(key) memoryCache.set(key, value) if (oldValue !== value) { - notifySubscribers(key, value) + notifySubscribers(key) } }), @@ -68,7 +68,7 @@ export const createMockCacheService = (options: { const existed = memoryCache.has(key) memoryCache.delete(key) if (existed) { - notifySubscribers(key, null) + notifySubscribers(key) } return existed }), @@ -76,7 +76,7 @@ export const createMockCacheService = (options: { clear: vi.fn((): void => { const keys = Array.from(memoryCache.keys()) memoryCache.clear() - keys.forEach(key => notifySubscribers(key, null)) + keys.forEach((key) => notifySubscribers(key)) }), has: vi.fn((key: string): boolean => { @@ -96,11 +96,11 @@ export const createMockCacheService = (options: { return defaultValue !== undefined ? defaultValue : null }), - setShared: vi.fn((key: string, value: T, ttl?: number): void => { + setShared: vi.fn((key: string, value: T): void => { const oldValue = sharedCache.get(key) sharedCache.set(key, value) if (oldValue !== value) { - notifySubscribers(`shared:${key}`, value) + notifySubscribers(`shared:${key}`) } }), @@ -108,7 +108,7 @@ export const createMockCacheService = (options: { const existed = sharedCache.has(key) sharedCache.delete(key) if (existed) { - notifySubscribers(`shared:${key}`, null) + notifySubscribers(`shared:${key}`) } return existed }), @@ -116,7 +116,7 @@ export const createMockCacheService = (options: { clearShared: vi.fn((): void => { const keys = Array.from(sharedCache.keys()) sharedCache.clear() - keys.forEach(key => notifySubscribers(`shared:${key}`, null)) + keys.forEach((key) => notifySubscribers(`shared:${key}`)) }), // Persist cache methods @@ -131,7 +131,7 @@ export const createMockCacheService = (options: { const oldValue = persistCache.get(key) persistCache.set(key, value) if (oldValue !== value) { - notifySubscribers(`persist:${key}`, value) + notifySubscribers(`persist:${key}`) } }), @@ -139,7 +139,7 @@ export const createMockCacheService = (options: { const existed = persistCache.has(key) persistCache.delete(key) if (existed) { - notifySubscribers(`persist:${key}`, DefaultRendererPersistCache[key]) + notifySubscribers(`persist:${key}`) } return existed }), @@ -147,7 +147,7 @@ export const createMockCacheService = (options: { clearPersist: vi.fn((): void => { const keys = Array.from(persistCache.keys()) as RendererPersistCacheKey[] persistCache.clear() - keys.forEach(key => notifySubscribers(`persist:${key}`, DefaultRendererPersistCache[key])) + keys.forEach((key) => notifySubscribers(`persist:${key}`)) }), // Subscription methods @@ -184,11 +184,11 @@ export const createMockCacheService = (options: { }), // Hook reference tracking (for advanced cache management) - addHookReference: vi.fn((key: string): void => { + addHookReference: vi.fn((): void => { // Mock implementation - in real service this prevents cache cleanup }), - removeHookReference: vi.fn((key: string): void => { + removeHookReference: vi.fn((): void => { // Mock implementation }), @@ -253,11 +253,11 @@ export const MockCacheService = { // Delegate all methods to the mock get(key: string): T | null { - return mockCacheService.get(key) + return mockCacheService.get(key) as T | null } - set(key: string, value: T, ttl?: number): void { - return mockCacheService.set(key, value, ttl) + set(key: string, value: T): void { + return mockCacheService.set(key, value) } delete(key: string): boolean { @@ -277,11 +277,11 @@ export const MockCacheService = { } getShared(key: string): T | null { - return mockCacheService.getShared(key) + return mockCacheService.getShared(key) as T | null } - setShared(key: string, value: T, ttl?: number): void { - return mockCacheService.setShared(key, value, ttl) + setShared(key: string, value: T): void { + return mockCacheService.setShared(key, value) } deleteShared(key: string): boolean { @@ -316,12 +316,12 @@ export const MockCacheService = { return mockCacheService.unsubscribe(key, callback) } - addHookReference(key: string): void { - return mockCacheService.addHookReference(key) + addHookReference(): void { + return mockCacheService.addHookReference() } - removeHookReference(key: string): void { - return mockCacheService.removeHookReference(key) + removeHookReference(): void { + return mockCacheService.removeHookReference() } getAllKeys(): string[] { @@ -343,7 +343,7 @@ export const MockCacheUtils = { * Reset all mock function call counts and state */ resetMocks: () => { - Object.values(mockCacheService).forEach(method => { + Object.values(mockCacheService).forEach((method) => { if (vi.isMockFunction(method)) { method.mockClear() } @@ -386,4 +386,4 @@ export const MockCacheUtils = { triggerCacheChange: (key: string, value: any) => { mockCacheService.set(key, value) } -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/DataApiService.ts b/tests/__mocks__/renderer/DataApiService.ts index 65c600f8ce..122a2c03d0 100644 --- a/tests/__mocks__/renderer/DataApiService.ts +++ b/tests/__mocks__/renderer/DataApiService.ts @@ -1,14 +1,5 @@ -import type { ConcreteApiPaths } from '@shared/data/api/apiSchemas' -import type { - ApiClient, - BatchRequest, - BatchResponse, - DataRequest, - DataResponse, - SubscriptionCallback, - SubscriptionOptions, - TransactionRequest -} from '@shared/data/api/apiTypes' +import type { ApiClient, ConcreteApiPaths } from '@shared/data/api/apiSchemas' +import type { DataResponse } from '@shared/data/api/apiTypes' import { vi } from 'vitest' /** @@ -18,20 +9,21 @@ import { vi } from 'vitest' // Mock response utilities const createMockResponse = (data: T, success = true): DataResponse => ({ - success, + id: 'mock-id', + status: success ? 200 : 500, data, - timestamp: new Date().toISOString(), - ...(success ? {} : { error: { code: 'MOCK_ERROR', message: 'Mock error', details: {} } }) + ...(success ? {} : { error: { code: 'MOCK_ERROR', message: 'Mock error', details: {}, status: 500 } }) }) const createMockError = (message: string): DataResponse => ({ - success: false, + id: 'mock-error-id', + status: 500, error: { code: 'MOCK_ERROR', message, - details: {} - }, - timestamp: new Date().toISOString() + details: {}, + status: 500 + } }) /** @@ -40,80 +32,25 @@ const createMockError = (message: string): DataResponse => ({ export const createMockDataApiService = (customBehavior: Partial = {}): ApiClient => { const mockService: ApiClient = { // HTTP Methods - get: vi.fn(async (path: ConcreteApiPaths, options?: any) => { - // Default mock behavior - return empty data based on path - const mockData = getMockDataForPath(path, 'GET') - return createMockResponse(mockData) + get: vi.fn(async (path: ConcreteApiPaths) => { + // Default mock behavior - return raw data based on path + return getMockDataForPath(path, 'GET') as any }), - post: vi.fn(async (path: ConcreteApiPaths, options?: any) => { - const mockData = getMockDataForPath(path, 'POST') - return createMockResponse(mockData) + post: vi.fn(async (path: ConcreteApiPaths) => { + return getMockDataForPath(path, 'POST') as any }), - put: vi.fn(async (path: ConcreteApiPaths, options?: any) => { - const mockData = getMockDataForPath(path, 'PUT') - return createMockResponse(mockData) + put: vi.fn(async (path: ConcreteApiPaths) => { + return getMockDataForPath(path, 'PUT') as any }), - patch: vi.fn(async (path: ConcreteApiPaths, options?: any) => { - const mockData = getMockDataForPath(path, 'PATCH') - return createMockResponse(mockData) + patch: vi.fn(async (path: ConcreteApiPaths) => { + return getMockDataForPath(path, 'PATCH') as any }), - delete: vi.fn(async (path: ConcreteApiPaths, options?: any) => { - return createMockResponse({ deleted: true }) - }), - - // Batch operations - batch: vi.fn(async (requests: BatchRequest[]): Promise => { - const responses = requests.map((request, index) => ({ - id: request.id || `batch_${index}`, - success: true, - data: getMockDataForPath(request.path as ConcreteApiPaths, request.method), - timestamp: new Date().toISOString() - })) - - return { - success: true, - responses, - timestamp: new Date().toISOString() - } - }), - - // Transaction support - transaction: vi.fn(async (operations: TransactionRequest[]): Promise> => { - const results = operations.map((op, index) => ({ - operation: op.operation, - result: getMockDataForPath(op.path as ConcreteApiPaths, 'POST'), - success: true - })) - - return createMockResponse(results) - }), - - // Subscription methods - subscribe: vi.fn((path: ConcreteApiPaths, callback: SubscriptionCallback, options?: SubscriptionOptions) => { - // Return a mock unsubscribe function - return vi.fn() - }), - - unsubscribe: vi.fn((path: ConcreteApiPaths) => { - // Mock unsubscribe - }), - - // Connection management - connect: vi.fn(async () => { - return createMockResponse({ connected: true }) - }), - - disconnect: vi.fn(async () => { - return createMockResponse({ disconnected: true }) - }), - - // Health check - ping: vi.fn(async () => { - return createMockResponse({ pong: true, timestamp: new Date().toISOString() }) + delete: vi.fn(async () => { + return { deleted: true } as any }), // Apply custom behavior overrides @@ -229,34 +166,6 @@ export const MockDataApiService = { async delete(path: ConcreteApiPaths, options?: any) { return mockDataApiService.delete(path, options) } - - async batch(requests: BatchRequest[]) { - return mockDataApiService.batch(requests) - } - - async transaction(operations: TransactionRequest[]) { - return mockDataApiService.transaction(operations) - } - - subscribe(path: ConcreteApiPaths, callback: SubscriptionCallback, options?: SubscriptionOptions) { - return mockDataApiService.subscribe(path, callback, options) - } - - unsubscribe(path: ConcreteApiPaths) { - return mockDataApiService.unsubscribe(path) - } - - async connect() { - return mockDataApiService.connect() - } - - async disconnect() { - return mockDataApiService.disconnect() - } - - async ping() { - return mockDataApiService.ping() - } }, dataApiService: mockDataApiService } @@ -269,7 +178,7 @@ export const MockDataApiUtils = { * Reset all mock function call counts and implementations */ resetMocks: () => { - Object.values(mockDataApiService).forEach(method => { + Object.values(mockDataApiService).forEach((method) => { if (vi.isMockFunction(method)) { method.mockClear() } @@ -282,7 +191,7 @@ export const MockDataApiUtils = { setCustomResponse: (path: ConcreteApiPaths, method: string, response: any) => { const methodFn = mockDataApiService[method.toLowerCase() as keyof ApiClient] as any if (vi.isMockFunction(methodFn)) { - methodFn.mockImplementation(async (requestPath: string, options?: any) => { + methodFn.mockImplementation(async (requestPath: string) => { if (requestPath === path) { return createMockResponse(response) } @@ -298,7 +207,7 @@ export const MockDataApiUtils = { setErrorResponse: (path: ConcreteApiPaths, method: string, errorMessage: string) => { const methodFn = mockDataApiService[method.toLowerCase() as keyof ApiClient] as any if (vi.isMockFunction(methodFn)) { - methodFn.mockImplementation(async (requestPath: string, options?: any) => { + methodFn.mockImplementation(async (requestPath: string) => { if (requestPath === path) { return createMockError(errorMessage) } @@ -323,4 +232,4 @@ export const MockDataApiUtils = { const methodFn = mockDataApiService[method] as any return vi.isMockFunction(methodFn) ? methodFn.mock.calls : [] } -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/PreferenceService.ts b/tests/__mocks__/renderer/PreferenceService.ts index f4bdad9234..4471201c14 100644 --- a/tests/__mocks__/renderer/PreferenceService.ts +++ b/tests/__mocks__/renderer/PreferenceService.ts @@ -34,7 +34,7 @@ export const mockPreferenceDefaults: Record = { // App preferences 'app.user.name': 'MockUser', - 'app.language': 'zh-CN', + 'app.language': 'zh-CN' // Add more defaults as needed } @@ -76,14 +76,14 @@ export const createMockPreferenceService = (customDefaults: Record }), clear: vi.fn(() => { - Object.keys(mergedDefaults).forEach(key => delete mergedDefaults[key]) + Object.keys(mergedDefaults).forEach((key) => delete mergedDefaults[key]) return Promise.resolve() }), // Internal state access for testing _getMockState: () => ({ ...mergedDefaults }), _resetMockState: () => { - Object.keys(mergedDefaults).forEach(key => delete mergedDefaults[key]) + Object.keys(mergedDefaults).forEach((key) => delete mergedDefaults[key]) Object.assign(mergedDefaults, mockPreferenceDefaults, customDefaults) } } @@ -95,4 +95,4 @@ export const mockPreferenceService = createMockPreferenceService() // Export for easy mocking in individual tests export const MockPreferenceService = { preferenceService: mockPreferenceService -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/useCache.ts b/tests/__mocks__/renderer/useCache.ts index e19c8be076..33f2f81203 100644 --- a/tests/__mocks__/renderer/useCache.ts +++ b/tests/__mocks__/renderer/useCache.ts @@ -41,7 +41,7 @@ const mockPersistSubscribers = new Map void>> const notifyMemorySubscribers = (key: UseCacheKey) => { const subscribers = mockMemorySubscribers.get(key) if (subscribers) { - subscribers.forEach(callback => { + subscribers.forEach((callback) => { try { callback() } catch (error) { @@ -54,7 +54,7 @@ const notifyMemorySubscribers = (key: UseCacheKey) => { const notifySharedSubscribers = (key: UseSharedCacheKey) => { const subscribers = mockSharedSubscribers.get(key) if (subscribers) { - subscribers.forEach(callback => { + subscribers.forEach((callback) => { try { callback() } catch (error) { @@ -67,7 +67,7 @@ const notifySharedSubscribers = (key: UseSharedCacheKey) => { const notifyPersistSubscribers = (key: RendererPersistCacheKey) => { const subscribers = mockPersistSubscribers.get(key) if (subscribers) { - subscribers.forEach(callback => { + subscribers.forEach((callback) => { try { callback() } catch (error) { @@ -80,77 +80,83 @@ const notifyPersistSubscribers = (key: RendererPersistCacheKey) => { /** * Mock useCache hook (memory cache) */ -export const mockUseCache = vi.fn(( - key: K, - initValue?: UseCacheSchema[K] -): [UseCacheSchema[K], (value: UseCacheSchema[K]) => void] => { - // Get current value - let currentValue = mockMemoryCache.get(key) - if (currentValue === undefined) { - currentValue = initValue ?? DefaultUseCache[key] - if (currentValue !== undefined) { - mockMemoryCache.set(key, currentValue) +export const mockUseCache = vi.fn( + ( + key: K, + initValue?: UseCacheSchema[K] + ): [UseCacheSchema[K], (value: UseCacheSchema[K]) => void] => { + // Get current value + let currentValue = mockMemoryCache.get(key) + if (currentValue === undefined) { + currentValue = initValue ?? DefaultUseCache[key] + if (currentValue !== undefined) { + mockMemoryCache.set(key, currentValue) + } } + + // Mock setValue function + const setValue = vi.fn((value: UseCacheSchema[K]) => { + mockMemoryCache.set(key, value) + notifyMemorySubscribers(key) + }) + + return [currentValue, setValue] } - - // Mock setValue function - const setValue = vi.fn((value: UseCacheSchema[K]) => { - mockMemoryCache.set(key, value) - notifyMemorySubscribers(key) - }) - - return [currentValue, setValue] -}) +) /** * Mock useSharedCache hook (shared cache) */ -export const mockUseSharedCache = vi.fn(( - key: K, - initValue?: UseSharedCacheSchema[K] -): [UseSharedCacheSchema[K], (value: UseSharedCacheSchema[K]) => void] => { - // Get current value - let currentValue = mockSharedCache.get(key) - if (currentValue === undefined) { - currentValue = initValue ?? DefaultUseSharedCache[key] - if (currentValue !== undefined) { - mockSharedCache.set(key, currentValue) +export const mockUseSharedCache = vi.fn( + ( + key: K, + initValue?: UseSharedCacheSchema[K] + ): [UseSharedCacheSchema[K], (value: UseSharedCacheSchema[K]) => void] => { + // Get current value + let currentValue = mockSharedCache.get(key) + if (currentValue === undefined) { + currentValue = initValue ?? DefaultUseSharedCache[key] + if (currentValue !== undefined) { + mockSharedCache.set(key, currentValue) + } } + + // Mock setValue function + const setValue = vi.fn((value: UseSharedCacheSchema[K]) => { + mockSharedCache.set(key, value) + notifySharedSubscribers(key) + }) + + return [currentValue, setValue] } - - // Mock setValue function - const setValue = vi.fn((value: UseSharedCacheSchema[K]) => { - mockSharedCache.set(key, value) - notifySharedSubscribers(key) - }) - - return [currentValue, setValue] -}) +) /** * Mock usePersistCache hook (persistent cache) */ -export const mockUsePersistCache = vi.fn(( - key: K, - initValue?: RendererPersistCacheSchema[K] -): [RendererPersistCacheSchema[K], (value: RendererPersistCacheSchema[K]) => void] => { - // Get current value - let currentValue = mockPersistCache.get(key) - if (currentValue === undefined) { - currentValue = initValue ?? DefaultRendererPersistCache[key] - if (currentValue !== undefined) { - mockPersistCache.set(key, currentValue) +export const mockUsePersistCache = vi.fn( + ( + key: K, + initValue?: RendererPersistCacheSchema[K] + ): [RendererPersistCacheSchema[K], (value: RendererPersistCacheSchema[K]) => void] => { + // Get current value + let currentValue = mockPersistCache.get(key) + if (currentValue === undefined) { + currentValue = initValue ?? DefaultRendererPersistCache[key] + if (currentValue !== undefined) { + mockPersistCache.set(key, currentValue) + } } + + // Mock setValue function + const setValue = vi.fn((value: RendererPersistCacheSchema[K]) => { + mockPersistCache.set(key, value) + notifyPersistSubscribers(key) + }) + + return [currentValue, setValue] } - - // Mock setValue function - const setValue = vi.fn((value: RendererPersistCacheSchema[K]) => { - mockPersistCache.set(key, value) - notifyPersistSubscribers(key) - }) - - return [currentValue, setValue] -}) +) /** * Export all mocks as a unified module @@ -292,18 +298,12 @@ export const MockUseCacheUtils = { ) => { mockUseCache.mockImplementation((cacheKey, initValue) => { if (cacheKey === key) { - return [ - value, - setValue || vi.fn() - ] + return [value, setValue || vi.fn()] } // Default behavior for other keys const defaultValue = mockMemoryCache.get(cacheKey) ?? initValue ?? DefaultUseCache[cacheKey] - return [ - defaultValue, - vi.fn() - ] + return [defaultValue, vi.fn()] }) }, @@ -317,18 +317,12 @@ export const MockUseCacheUtils = { ) => { mockUseSharedCache.mockImplementation((cacheKey, initValue) => { if (cacheKey === key) { - return [ - value, - setValue || vi.fn() - ] + return [value, setValue || vi.fn()] } // Default behavior for other keys const defaultValue = mockSharedCache.get(cacheKey) ?? initValue ?? DefaultUseSharedCache[cacheKey] - return [ - defaultValue, - vi.fn() - ] + return [defaultValue, vi.fn()] }) }, @@ -342,18 +336,12 @@ export const MockUseCacheUtils = { ) => { mockUsePersistCache.mockImplementation((cacheKey, initValue) => { if (cacheKey === key) { - return [ - value, - setValue || vi.fn() - ] + return [value, setValue || vi.fn()] } // Default behavior for other keys const defaultValue = mockPersistCache.get(cacheKey) ?? initValue ?? DefaultRendererPersistCache[cacheKey] - return [ - defaultValue, - vi.fn() - ] + return [defaultValue, vi.fn()] }) }, @@ -425,4 +413,4 @@ export const MockUseCacheUtils = { shared: Array.from(mockSharedSubscribers.entries()).map(([key, subs]) => [key, subs.size]), persist: Array.from(mockPersistSubscribers.entries()).map(([key, subs]) => [key, subs.size]) }) -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/useDataApi.ts b/tests/__mocks__/renderer/useDataApi.ts index 5b748dfea9..9b85d25550 100644 --- a/tests/__mocks__/renderer/useDataApi.ts +++ b/tests/__mocks__/renderer/useDataApi.ts @@ -71,133 +71,134 @@ function createMockDataForPath(path: ConcreteApiPaths): any { /** * Mock useQuery hook */ -export const mockUseQuery = vi.fn(( - path: TPath | null, - query?: any, - options?: any -): MockSWRResponse => { - const isLoading = options?.initialLoading ?? false - const hasError = options?.shouldError ?? false +export const mockUseQuery = vi.fn( + (path: TPath | null, _query?: any, options?: any): MockSWRResponse => { + const isLoading = options?.initialLoading ?? false + const hasError = options?.shouldError ?? false + + if (hasError) { + return { + data: undefined, + error: new Error(`Mock error for ${path}`), + isLoading: false, + isValidating: false, + mutate: vi.fn().mockResolvedValue(undefined) + } + } + + const mockData = path ? createMockDataForPath(path) : undefined - if (hasError) { return { - data: undefined, - error: new Error(`Mock error for ${path}`), - isLoading: false, + data: mockData, + error: undefined, + isLoading, isValidating: false, - mutate: vi.fn().mockResolvedValue(undefined) + mutate: vi.fn().mockResolvedValue(mockData) } } - - const mockData = path ? createMockDataForPath(path) : undefined - - return { - data: mockData, - error: undefined, - isLoading, - isValidating: false, - mutate: vi.fn().mockResolvedValue(mockData) - } -}) +) /** * Mock useMutation hook */ -export const mockUseMutation = vi.fn(( - path: TPath, - method: TMethod, - options?: any -): MockMutationResponse => { - const isMutating = options?.initialMutating ?? false - const hasError = options?.shouldError ?? false +export const mockUseMutation = vi.fn( + ( + path: TPath, + method: TMethod, + options?: any + ): MockMutationResponse => { + const isMutating = options?.initialMutating ?? false + const hasError = options?.shouldError ?? false - const mockTrigger = vi.fn(async (...args: any[]) => { - if (hasError) { - throw new Error(`Mock mutation error for ${method} ${path}`) + const mockTrigger = vi.fn(async (...args: any[]) => { + if (hasError) { + throw new Error(`Mock mutation error for ${method} ${path}`) + } + + // Simulate different responses based on method + switch (method) { + case 'POST': + return { id: 'new_item', created: true, ...args[0] } + case 'PUT': + case 'PATCH': + return { id: 'updated_item', updated: true, ...args[0] } + case 'DELETE': + return { deleted: true } + default: + return { success: true } + } + }) + + return { + data: undefined, + error: undefined, + isMutating, + trigger: mockTrigger, + reset: vi.fn() } - - // Simulate different responses based on method - switch (method) { - case 'POST': - return { id: 'new_item', created: true, ...args[0] } - case 'PUT': - case 'PATCH': - return { id: 'updated_item', updated: true, ...args[0] } - case 'DELETE': - return { deleted: true } - default: - return { success: true } - } - }) - - return { - data: undefined, - error: undefined, - isMutating, - trigger: mockTrigger, - reset: vi.fn() } -}) +) /** * Mock usePaginatedQuery hook */ -export const mockUsePaginatedQuery = vi.fn(( - path: TPath | null, - query?: any, - options?: any -): MockPaginatedResponse => { - const isLoading = options?.initialLoading ?? false - const isLoadingMore = options?.initialLoadingMore ?? false - const hasError = options?.shouldError ?? false +export const mockUsePaginatedQuery = vi.fn( + (path: TPath | null, _query?: any, options?: any): MockPaginatedResponse => { + const isLoading = options?.initialLoading ?? false + const isLoadingMore = options?.initialLoadingMore ?? false + const hasError = options?.shouldError ?? false + + if (hasError) { + return { + data: undefined, + error: new Error(`Mock paginated error for ${path}`), + isLoading: false, + isValidating: false, + mutate: vi.fn().mockResolvedValue(undefined), + loadMore: vi.fn(), + isLoadingMore: false, + hasMore: false, + items: [] + } + } + + const mockItems = path + ? [ + { id: 'item1', name: 'Mock Item 1' }, + { id: 'item2', name: 'Mock Item 2' }, + { id: 'item3', name: 'Mock Item 3' } + ] + : [] + + const mockData: PaginatedResponse = { + items: mockItems, + total: mockItems.length, + page: 1, + pageCount: 1, + hasNext: false, + hasPrev: false + } - if (hasError) { return { - data: undefined, - error: new Error(`Mock paginated error for ${path}`), - isLoading: false, + data: mockData, + error: undefined, + isLoading, isValidating: false, - mutate: vi.fn().mockResolvedValue(undefined), + mutate: vi.fn().mockResolvedValue(mockData), loadMore: vi.fn(), - isLoadingMore: false, - hasMore: false, - items: [] + isLoadingMore, + hasMore: mockData.hasNext, + items: mockItems } } - - const mockItems = path ? [ - { id: 'item1', name: 'Mock Item 1' }, - { id: 'item2', name: 'Mock Item 2' }, - { id: 'item3', name: 'Mock Item 3' } - ] : [] - - const mockData: PaginatedResponse = { - items: mockItems, - total: mockItems.length, - page: 1, - pageSize: 10, - hasMore: false - } - - return { - data: mockData, - error: undefined, - isLoading, - isValidating: false, - mutate: vi.fn().mockResolvedValue(mockData), - loadMore: vi.fn(), - isLoadingMore, - hasMore: mockData.hasMore, - items: mockItems - } -}) +) /** * Mock useInvalidateCache hook */ export const mockUseInvalidateCache = vi.fn(() => { return { - invalidate: vi.fn(async (path?: ConcreteApiPaths) => { + invalidate: vi.fn(async () => { // Mock cache invalidation return Promise.resolve() }), @@ -211,13 +212,9 @@ export const mockUseInvalidateCache = vi.fn(() => { /** * Mock prefetch function */ -export const mockPrefetch = vi.fn(async ( - path: TPath, - query?: any, - options?: any -): Promise => { +export const mockPrefetch = vi.fn(async (_path: TPath): Promise => { // Mock prefetch - return mock data - return createMockDataForPath(path) + return createMockDataForPath(_path) }) /** @@ -261,13 +258,15 @@ export const MockUseDataApiUtils = { } } // Default behavior for other paths - return mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { - data: undefined, - error: undefined, - isLoading: false, - isValidating: false, - mutate: vi.fn().mockResolvedValue(undefined) - } + return ( + mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { + data: undefined, + error: undefined, + isLoading: false, + isValidating: false, + mutate: vi.fn().mockResolvedValue(undefined) + } + ) }) }, @@ -285,13 +284,15 @@ export const MockUseDataApiUtils = { mutate: vi.fn().mockResolvedValue(undefined) } } - return mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { - data: undefined, - error: undefined, - isLoading: false, - isValidating: false, - mutate: vi.fn().mockResolvedValue(undefined) - } + return ( + mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { + data: undefined, + error: undefined, + isLoading: false, + isValidating: false, + mutate: vi.fn().mockResolvedValue(undefined) + } + ) }) }, @@ -309,13 +310,15 @@ export const MockUseDataApiUtils = { mutate: vi.fn().mockResolvedValue(undefined) } } - return mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { - data: undefined, - error: undefined, - isLoading: false, - isValidating: false, - mutate: vi.fn().mockResolvedValue(undefined) - } + return ( + mockUseQuery.getMockImplementation()?.(queryPath, query, options) || { + data: undefined, + error: undefined, + isLoading: false, + isValidating: false, + mutate: vi.fn().mockResolvedValue(undefined) + } + ) }) }, @@ -333,13 +336,15 @@ export const MockUseDataApiUtils = { reset: vi.fn() } } - return mockUseMutation.getMockImplementation()?.(mutationPath, mutationMethod, options) || { - data: undefined, - error: undefined, - isMutating: false, - trigger: vi.fn().mockResolvedValue({}), - reset: vi.fn() - } + return ( + mockUseMutation.getMockImplementation()?.(mutationPath, mutationMethod, options) || { + data: undefined, + error: undefined, + isMutating: false, + trigger: vi.fn().mockResolvedValue({}), + reset: vi.fn() + } + ) }) }, @@ -357,13 +362,15 @@ export const MockUseDataApiUtils = { reset: vi.fn() } } - return mockUseMutation.getMockImplementation()?.(mutationPath, mutationMethod, options) || { - data: undefined, - error: undefined, - isMutating: false, - trigger: vi.fn().mockResolvedValue({}), - reset: vi.fn() - } + return ( + mockUseMutation.getMockImplementation()?.(mutationPath, mutationMethod, options) || { + data: undefined, + error: undefined, + isMutating: false, + trigger: vi.fn().mockResolvedValue({}), + reset: vi.fn() + } + ) }) } -} \ No newline at end of file +} diff --git a/tests/__mocks__/renderer/usePreference.ts b/tests/__mocks__/renderer/usePreference.ts index 343e1b8a81..e222f19445 100644 --- a/tests/__mocks__/renderer/usePreference.ts +++ b/tests/__mocks__/renderer/usePreference.ts @@ -1,8 +1,4 @@ -import type { - PreferenceKeyType, - PreferenceUpdateOptions, - PreferenceValueType -} from '@shared/data/preference/preferenceTypes' +import type { PreferenceKeyType, PreferenceUpdateOptions } from '@shared/data/preference/preferenceTypes' import { vi } from 'vitest' import { mockPreferenceDefaults } from './PreferenceService' @@ -27,7 +23,7 @@ const mockPreferenceSubscribers = new Map void>>() const notifyPreferenceSubscribers = (key: PreferenceKeyType) => { const subscribers = mockPreferenceSubscribers.get(key) if (subscribers) { - subscribers.forEach(callback => { + subscribers.forEach((callback) => { try { callback() } catch (error) { @@ -40,111 +36,109 @@ const notifyPreferenceSubscribers = (key: PreferenceKeyType) => { /** * Mock usePreference hook */ -export const mockUsePreference = vi.fn(( - key: K, - options?: PreferenceUpdateOptions -): [PreferenceValueType, (value: PreferenceValueType) => Promise] => { - // Get current value - const currentValue = mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null +export const mockUsePreference = vi.fn( + (key: K, options?: PreferenceUpdateOptions): [any, (value: any) => Promise] => { + // Get current value + const currentValue = mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null - // Mock setValue function - const setValue = vi.fn(async (value: PreferenceValueType) => { - const oldValue = mockPreferenceState.get(key) + // Mock setValue function + const setValue = vi.fn(async (value: any) => { + const oldValue = mockPreferenceState.get(key) - // Simulate optimistic updates (default behavior) - if (options?.optimistic !== false) { - mockPreferenceState.set(key, value) - notifyPreferenceSubscribers(key) - } - - // Simulate async update delay - await new Promise(resolve => setTimeout(resolve, 10)) - - // For pessimistic updates, update after delay - if (options?.optimistic === false) { - mockPreferenceState.set(key, value) - notifyPreferenceSubscribers(key) - } - - // Simulate error scenarios if configured - if (options?.shouldError) { - // Rollback optimistic update on error - if (options.optimistic !== false) { - mockPreferenceState.set(key, oldValue) + // Simulate optimistic updates (default behavior) + if (options?.optimistic !== false) { + mockPreferenceState.set(key, value) notifyPreferenceSubscribers(key) } - throw new Error(`Mock preference error for key: ${key}`) - } - }) - return [currentValue, setValue] -}) + // Simulate async update delay + await new Promise((resolve) => setTimeout(resolve, 10)) + + // For pessimistic updates, update after delay + if (options?.optimistic === false) { + mockPreferenceState.set(key, value) + notifyPreferenceSubscribers(key) + } + + // Simulate error scenarios if configured + if ((options as any)?.shouldError) { + // Rollback optimistic update on error + if (options?.optimistic !== false) { + mockPreferenceState.set(key, oldValue) + notifyPreferenceSubscribers(key) + } + throw new Error(`Mock preference error for key: ${key}`) + } + }) + + return [currentValue, setValue] + } +) /** * Mock useMultiplePreferences hook */ -export const mockUseMultiplePreferences = vi.fn(>( - keys: T, - options?: PreferenceUpdateOptions -): [ - { [K in keyof T]: PreferenceValueType }, - (values: Partial<{ [K in keyof T]: PreferenceValueType }>) => Promise -] => { - // Get current values for all keys - const currentValues = {} as { [K in keyof T]: PreferenceValueType } - Object.entries(keys).forEach(([alias, key]) => { - currentValues[alias as keyof T] = mockPreferenceState.get(key as PreferenceKeyType) ?? - mockPreferenceDefaults[key as string] ?? null - }) +export const mockUseMultiplePreferences = vi.fn( + >( + keys: T, + options?: PreferenceUpdateOptions + ): [{ [K in keyof T]: any }, (values: Partial<{ [K in keyof T]: any }>) => Promise] => { + // Get current values for all keys + const currentValues = {} as { [K in keyof T]: any } + Object.entries(keys).forEach(([alias, key]) => { + currentValues[alias as keyof T] = + mockPreferenceState.get(key as PreferenceKeyType) ?? mockPreferenceDefaults[key as string] ?? null + }) - // Mock setValues function - const setValues = vi.fn(async (values: Partial<{ [K in keyof T]: PreferenceValueType }>) => { - const oldValues = { ...currentValues } + // Mock setValues function + const setValues = vi.fn(async (values: Partial<{ [K in keyof T]: any }>) => { + const oldValues = { ...currentValues } - // Simulate optimistic updates - if (options?.optimistic !== false) { - Object.entries(values).forEach(([alias, value]) => { - const key = keys[alias as keyof T] as PreferenceKeyType - if (value !== undefined) { - mockPreferenceState.set(key, value) - currentValues[alias as keyof T] = value as any - notifyPreferenceSubscribers(key) - } - }) - } - - // Simulate async update delay - await new Promise(resolve => setTimeout(resolve, 10)) - - // For pessimistic updates, update after delay - if (options?.optimistic === false) { - Object.entries(values).forEach(([alias, value]) => { - const key = keys[alias as keyof T] as PreferenceKeyType - if (value !== undefined) { - mockPreferenceState.set(key, value) - currentValues[alias as keyof T] = value as any - notifyPreferenceSubscribers(key) - } - }) - } - - // Simulate error scenarios - if (options?.shouldError) { - // Rollback optimistic updates on error - if (options.optimistic !== false) { - Object.entries(oldValues).forEach(([alias, value]) => { + // Simulate optimistic updates + if (options?.optimistic !== false) { + Object.entries(values).forEach(([alias, value]) => { const key = keys[alias as keyof T] as PreferenceKeyType - mockPreferenceState.set(key, value) - currentValues[alias as keyof T] = value - notifyPreferenceSubscribers(key) + if (value !== undefined) { + mockPreferenceState.set(key, value) + currentValues[alias as keyof T] = value as any + notifyPreferenceSubscribers(key) + } }) } - throw new Error('Mock multiple preferences error') - } - }) - return [currentValues, setValues] -}) + // Simulate async update delay + await new Promise((resolve) => setTimeout(resolve, 10)) + + // For pessimistic updates, update after delay + if (options?.optimistic === false) { + Object.entries(values).forEach(([alias, value]) => { + const key = keys[alias as keyof T] as PreferenceKeyType + if (value !== undefined) { + mockPreferenceState.set(key, value) + currentValues[alias as keyof T] = value as any + notifyPreferenceSubscribers(key) + } + }) + } + + // Simulate error scenarios + if ((options as any)?.shouldError) { + // Rollback optimistic updates on error + if (options?.optimistic !== false) { + Object.entries(oldValues).forEach(([alias, value]) => { + const key = keys[alias as keyof T] as PreferenceKeyType + mockPreferenceState.set(key, value) + currentValues[alias as keyof T] = value + notifyPreferenceSubscribers(key) + }) + } + throw new Error('Mock multiple preferences error') + } + }) + + return [currentValues, setValues] + } +) /** * Export all mocks as a unified module @@ -178,7 +172,7 @@ export const MockUsePreferenceUtils = { /** * Set a preference value for testing */ - setPreferenceValue: (key: K, value: PreferenceValueType) => { + setPreferenceValue: (key: K, value: any) => { mockPreferenceState.set(key, value) notifyPreferenceSubscribers(key) }, @@ -186,7 +180,7 @@ export const MockUsePreferenceUtils = { /** * Get current preference value */ - getPreferenceValue: (key: K): PreferenceValueType => { + getPreferenceValue: (key: K): any => { return mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null }, @@ -214,7 +208,7 @@ export const MockUsePreferenceUtils = { /** * Simulate preference change from external source */ - simulateExternalPreferenceChange: (key: K, value: PreferenceValueType) => { + simulateExternalPreferenceChange: (key: K, value: any) => { mockPreferenceState.set(key, value) notifyPreferenceSubscribers(key) }, @@ -222,26 +216,15 @@ export const MockUsePreferenceUtils = { /** * Mock preference hook to return specific value for a key */ - mockPreferenceReturn: ( - key: K, - value: PreferenceValueType, - setValue?: (value: PreferenceValueType) => Promise - ) => { - mockUsePreference.mockImplementation((preferenceKey, options) => { + mockPreferenceReturn: (key: K, value: any, setValue?: (value: any) => Promise) => { + mockUsePreference.mockImplementation((preferenceKey) => { if (preferenceKey === key) { - return [ - value, - setValue || vi.fn().mockResolvedValue(undefined) - ] + return [value, setValue || vi.fn().mockResolvedValue(undefined)] } // Default behavior for other keys - const defaultValue = mockPreferenceState.get(preferenceKey) ?? - mockPreferenceDefaults[preferenceKey] ?? null - return [ - defaultValue, - vi.fn().mockResolvedValue(undefined) - ] + const defaultValue = mockPreferenceState.get(preferenceKey) ?? mockPreferenceDefaults[preferenceKey] ?? null + return [defaultValue, vi.fn().mockResolvedValue(undefined)] }) }, @@ -249,7 +232,7 @@ export const MockUsePreferenceUtils = { * Mock preference hook to simulate error for a key */ mockPreferenceError: (key: K, error: Error) => { - mockUsePreference.mockImplementation((preferenceKey, options) => { + mockUsePreference.mockImplementation((preferenceKey) => { if (preferenceKey === key) { const setValue = vi.fn().mockRejectedValue(error) const currentValue = mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null @@ -257,12 +240,8 @@ export const MockUsePreferenceUtils = { } // Default behavior for other keys - const defaultValue = mockPreferenceState.get(preferenceKey) ?? - mockPreferenceDefaults[preferenceKey] ?? null - return [ - defaultValue, - vi.fn().mockResolvedValue(undefined) - ] + const defaultValue = mockPreferenceState.get(preferenceKey) ?? mockPreferenceDefaults[preferenceKey] ?? null + return [defaultValue, vi.fn().mockResolvedValue(undefined)] }) }, @@ -293,4 +272,4 @@ export const MockUsePreferenceUtils = { getSubscriberCount: (key: PreferenceKeyType): number => { return mockPreferenceSubscribers.get(key)?.size ?? 0 } -} \ No newline at end of file +}