mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-26 03:31:24 +08:00
fix: typecheck/test:lint/format:check
feat: add data related test
This commit is contained in:
parent
8353f331f1
commit
d397a43806
@ -98,4 +98,4 @@ const ErrorContainer = styled.div`
|
||||
`
|
||||
|
||||
export { ErrorBoundaryCustomized as ErrorBoundary }
|
||||
export type { ErrorBoundaryCustomizedProps, CustomFallbackProps }
|
||||
export type { CustomFallbackProps, ErrorBoundaryCustomizedProps }
|
||||
|
||||
@ -5,4 +5,4 @@ export function formatErrorMessage(error: Error): string {
|
||||
return error.message
|
||||
}
|
||||
return error.toString()
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,8 +16,11 @@ import React from 'react'
|
||||
|
||||
// 创建一个 Icon 工厂函数
|
||||
export function createIcon(IconComponent: LucideIcon, defaultSize: string | number = '1rem') {
|
||||
const Icon = React.forwardRef<SVGSVGElement, React.ComponentProps<typeof IconComponent>>(
|
||||
(props, ref) => <IconComponent ref={ref} size={defaultSize} {...props} />
|
||||
const Icon = ({
|
||||
ref,
|
||||
...props
|
||||
}: React.ComponentProps<typeof IconComponent> & { ref?: React.RefObject<SVGSVGElement | null> }) => (
|
||||
<IconComponent ref={ref} size={defaultSize} {...props} />
|
||||
)
|
||||
Icon.displayName = `Icon(${IconComponent.displayName || IconComponent.name})`
|
||||
return Icon
|
||||
|
||||
@ -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'
|
||||
|
||||
@ -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 }) => (
|
||||
<div
|
||||
key={name}
|
||||
className="flex flex-col items-center gap-2 rounded-lg border border-gray-200 p-4 hover:border-blue-500"
|
||||
>
|
||||
className="flex flex-col items-center gap-2 rounded-lg border border-gray-200 p-4 hover:border-blue-500">
|
||||
<Icon size={24} />
|
||||
<span className="text-xs">{name}</span>
|
||||
</div>
|
||||
@ -287,4 +270,4 @@ export const IconGrid: Story = {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 <translate_input> 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 <translate_input> 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', () => ({
|
||||
|
||||
@ -7,9 +7,9 @@ import { includeKeywords, matchKeywordsInModel, matchKeywordsInProvider, matchKe
|
||||
vi.mock('@renderer/i18n/label', () => ({
|
||||
getProviderLabel: vi.fn((id: string) => {
|
||||
const labelMap: Record<string, string> = {
|
||||
'dashscope': 'Alibaba Cloud',
|
||||
'openai': 'OpenAI',
|
||||
'anthropic': 'Anthropic'
|
||||
dashscope: 'Alibaba Cloud',
|
||||
openai: 'OpenAI',
|
||||
anthropic: 'Anthropic'
|
||||
}
|
||||
return labelMap[id] || id
|
||||
})
|
||||
|
||||
@ -5,9 +5,9 @@ import { describe, expect, it, vi } from 'vitest'
|
||||
vi.mock('@renderer/i18n/label', () => ({
|
||||
getProviderLabel: vi.fn((id: string) => {
|
||||
const labelMap: Record<string, string> = {
|
||||
'dashscope': 'Alibaba Cloud',
|
||||
'openai': 'OpenAI',
|
||||
'anthropic': 'Anthropic'
|
||||
dashscope: 'Alibaba Cloud',
|
||||
openai: 'OpenAI',
|
||||
anthropic: 'Anthropic'
|
||||
}
|
||||
return labelMap[id] || id
|
||||
})
|
||||
|
||||
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<void> => {
|
||||
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<string, any>) => {
|
||||
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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<string, Set<(newValue: any, oldValue?: any)
|
||||
const notifyMainSubscribers = (key: string, newValue: any, oldValue?: any) => {
|
||||
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<void> => {
|
||||
this.initialized = true
|
||||
this._initialized = true
|
||||
})
|
||||
|
||||
// Mock get method
|
||||
@ -63,19 +60,18 @@ export class MockMainPreferenceService {
|
||||
})
|
||||
|
||||
// Mock set method
|
||||
public set = vi.fn(async <K extends PreferenceKeyType>(
|
||||
key: K,
|
||||
value: PreferenceDefaultScopeType[K]
|
||||
): Promise<void> => {
|
||||
const oldValue = mockPreferenceState.get(key)
|
||||
mockPreferenceState.set(key, value)
|
||||
notifyMainSubscribers(key, value, oldValue)
|
||||
})
|
||||
public set = vi.fn(
|
||||
async <K extends PreferenceKeyType>(key: K, value: PreferenceDefaultScopeType[K]): Promise<void> => {
|
||||
const oldValue = mockPreferenceState.get(key)
|
||||
mockPreferenceState.set(key, value)
|
||||
notifyMainSubscribers(key, value, oldValue)
|
||||
}
|
||||
)
|
||||
|
||||
// Mock getMultiple method
|
||||
public getMultiple = vi.fn(<K extends PreferenceKeyType>(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(<K extends PreferenceKeyType>(
|
||||
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(
|
||||
<K extends PreferenceKeyType>(
|
||||
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])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<string, any>
|
||||
initialSharedCache?: Map<string, any>
|
||||
initialPersistCache?: Map<RendererPersistCacheKey, any>
|
||||
} = {}) => {
|
||||
export const createMockCacheService = (
|
||||
options: {
|
||||
initialMemoryCache?: Map<string, any>
|
||||
initialSharedCache?: Map<string, any>
|
||||
initialPersistCache?: Map<RendererPersistCacheKey, any>
|
||||
} = {}
|
||||
) => {
|
||||
// Mock cache storage
|
||||
const memoryCache = new Map<string, any>(options.initialMemoryCache || [])
|
||||
const sharedCache = new Map<string, any>(options.initialSharedCache || [])
|
||||
@ -32,10 +32,10 @@ export const createMockCacheService = (options: {
|
||||
const subscribers = new Map<string, Set<CacheSubscriber>>()
|
||||
|
||||
// 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(<T>(key: string, value: T, ttl?: number): void => {
|
||||
set: vi.fn(<T>(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(<T>(key: string, value: T, ttl?: number): void => {
|
||||
setShared: vi.fn(<T>(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<T>(key: string): T | null {
|
||||
return mockCacheService.get<T>(key)
|
||||
return mockCacheService.get(key) as T | null
|
||||
}
|
||||
|
||||
set<T>(key: string, value: T, ttl?: number): void {
|
||||
return mockCacheService.set(key, value, ttl)
|
||||
set<T>(key: string, value: T): void {
|
||||
return mockCacheService.set(key, value)
|
||||
}
|
||||
|
||||
delete(key: string): boolean {
|
||||
@ -277,11 +277,11 @@ export const MockCacheService = {
|
||||
}
|
||||
|
||||
getShared<T>(key: string): T | null {
|
||||
return mockCacheService.getShared<T>(key)
|
||||
return mockCacheService.getShared(key) as T | null
|
||||
}
|
||||
|
||||
setShared<T>(key: string, value: T, ttl?: number): void {
|
||||
return mockCacheService.setShared(key, value, ttl)
|
||||
setShared<T>(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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 = <T>(data: T, success = true): DataResponse<T> => ({
|
||||
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<never> => ({
|
||||
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<never> => ({
|
||||
export const createMockDataApiService = (customBehavior: Partial<ApiClient> = {}): 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<BatchResponse> => {
|
||||
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<DataResponse<any[]>> => {
|
||||
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 : []
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,7 +34,7 @@ export const mockPreferenceDefaults: Record<string, any> = {
|
||||
|
||||
// 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<string, any>
|
||||
}),
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ const mockPersistSubscribers = new Map<RendererPersistCacheKey, Set<() => 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(<K extends UseCacheKey>(
|
||||
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(
|
||||
<K extends UseCacheKey>(
|
||||
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(<K extends UseSharedCacheKey>(
|
||||
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(
|
||||
<K extends UseSharedCacheKey>(
|
||||
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(<K extends RendererPersistCacheKey>(
|
||||
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(
|
||||
<K extends RendererPersistCacheKey>(
|
||||
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])
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -71,133 +71,134 @@ function createMockDataForPath(path: ConcreteApiPaths): any {
|
||||
/**
|
||||
* Mock useQuery hook
|
||||
*/
|
||||
export const mockUseQuery = vi.fn(<TPath extends ConcreteApiPaths>(
|
||||
path: TPath | null,
|
||||
query?: any,
|
||||
options?: any
|
||||
): MockSWRResponse<any> => {
|
||||
const isLoading = options?.initialLoading ?? false
|
||||
const hasError = options?.shouldError ?? false
|
||||
export const mockUseQuery = vi.fn(
|
||||
<TPath extends ConcreteApiPaths>(path: TPath | null, _query?: any, options?: any): MockSWRResponse<any> => {
|
||||
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(<TPath extends ConcreteApiPaths, TMethod extends 'POST' | 'PUT' | 'DELETE' | 'PATCH'>(
|
||||
path: TPath,
|
||||
method: TMethod,
|
||||
options?: any
|
||||
): MockMutationResponse<any> => {
|
||||
const isMutating = options?.initialMutating ?? false
|
||||
const hasError = options?.shouldError ?? false
|
||||
export const mockUseMutation = vi.fn(
|
||||
<TPath extends ConcreteApiPaths, TMethod extends 'POST' | 'PUT' | 'DELETE' | 'PATCH'>(
|
||||
path: TPath,
|
||||
method: TMethod,
|
||||
options?: any
|
||||
): MockMutationResponse<any> => {
|
||||
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(<TPath extends ConcreteApiPaths>(
|
||||
path: TPath | null,
|
||||
query?: any,
|
||||
options?: any
|
||||
): MockPaginatedResponse<any> => {
|
||||
const isLoading = options?.initialLoading ?? false
|
||||
const isLoadingMore = options?.initialLoadingMore ?? false
|
||||
const hasError = options?.shouldError ?? false
|
||||
export const mockUsePaginatedQuery = vi.fn(
|
||||
<TPath extends ConcreteApiPaths>(path: TPath | null, _query?: any, options?: any): MockPaginatedResponse<any> => {
|
||||
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<any> = {
|
||||
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<any> = {
|
||||
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 <TPath extends ConcreteApiPaths>(
|
||||
path: TPath,
|
||||
query?: any,
|
||||
options?: any
|
||||
): Promise<any> => {
|
||||
export const mockPrefetch = vi.fn(async <TPath extends ConcreteApiPaths>(_path: TPath): Promise<any> => {
|
||||
// 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()
|
||||
}
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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<PreferenceKeyType, Set<() => 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(<K extends PreferenceKeyType>(
|
||||
key: K,
|
||||
options?: PreferenceUpdateOptions
|
||||
): [PreferenceValueType<K>, (value: PreferenceValueType<K>) => Promise<void>] => {
|
||||
// Get current value
|
||||
const currentValue = mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null
|
||||
export const mockUsePreference = vi.fn(
|
||||
<K extends PreferenceKeyType>(key: K, options?: PreferenceUpdateOptions): [any, (value: any) => Promise<void>] => {
|
||||
// Get current value
|
||||
const currentValue = mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null
|
||||
|
||||
// Mock setValue function
|
||||
const setValue = vi.fn(async (value: PreferenceValueType<K>) => {
|
||||
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(<T extends Record<string, PreferenceKeyType>>(
|
||||
keys: T,
|
||||
options?: PreferenceUpdateOptions
|
||||
): [
|
||||
{ [K in keyof T]: PreferenceValueType<T[K]> },
|
||||
(values: Partial<{ [K in keyof T]: PreferenceValueType<T[K]> }>) => Promise<void>
|
||||
] => {
|
||||
// Get current values for all keys
|
||||
const currentValues = {} as { [K in keyof T]: PreferenceValueType<T[K]> }
|
||||
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(
|
||||
<T extends Record<string, PreferenceKeyType>>(
|
||||
keys: T,
|
||||
options?: PreferenceUpdateOptions
|
||||
): [{ [K in keyof T]: any }, (values: Partial<{ [K in keyof T]: any }>) => Promise<void>] => {
|
||||
// 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<T[K]> }>) => {
|
||||
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: <K extends PreferenceKeyType>(key: K, value: PreferenceValueType<K>) => {
|
||||
setPreferenceValue: <K extends PreferenceKeyType>(key: K, value: any) => {
|
||||
mockPreferenceState.set(key, value)
|
||||
notifyPreferenceSubscribers(key)
|
||||
},
|
||||
@ -186,7 +180,7 @@ export const MockUsePreferenceUtils = {
|
||||
/**
|
||||
* Get current preference value
|
||||
*/
|
||||
getPreferenceValue: <K extends PreferenceKeyType>(key: K): PreferenceValueType<K> => {
|
||||
getPreferenceValue: <K extends PreferenceKeyType>(key: K): any => {
|
||||
return mockPreferenceState.get(key) ?? mockPreferenceDefaults[key] ?? null
|
||||
},
|
||||
|
||||
@ -214,7 +208,7 @@ export const MockUsePreferenceUtils = {
|
||||
/**
|
||||
* Simulate preference change from external source
|
||||
*/
|
||||
simulateExternalPreferenceChange: <K extends PreferenceKeyType>(key: K, value: PreferenceValueType<K>) => {
|
||||
simulateExternalPreferenceChange: <K extends PreferenceKeyType>(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: <K extends PreferenceKeyType>(
|
||||
key: K,
|
||||
value: PreferenceValueType<K>,
|
||||
setValue?: (value: PreferenceValueType<K>) => Promise<void>
|
||||
) => {
|
||||
mockUsePreference.mockImplementation((preferenceKey, options) => {
|
||||
mockPreferenceReturn: <K extends PreferenceKeyType>(key: K, value: any, setValue?: (value: any) => Promise<void>) => {
|
||||
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: <K extends PreferenceKeyType>(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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user