import '@testing-library/jest-dom/vitest' import { createRequire } from 'node:module' import { beforeAll, expect, vi } from 'vitest' const require = createRequire(import.meta.url) const bufferModule = require('buffer') if (!bufferModule.SlowBuffer) { bufferModule.SlowBuffer = bufferModule.Buffer } // i18n now initializes lazily via initI18n() instead of a module-level side effect, // so seed it once per test file for components that render real translations. // The whole body is guarded: files that vi.mock('@renderer/i18n') make the dynamic // import invoke their mock factory (which may throw), and files that // vi.mock('react-i18next') without initReactI18next make initI18n() reject. Neither // needs real initialization, so swallow both the import error and the init rejection. beforeAll(async () => { try { const mod = await import('@renderer/i18n') await mod.initI18n?.() } catch { // Intentionally ignored — mocked-i18n test files don't need real init. } }) // Mock LoggerService globally for renderer tests vi.mock('@logger', async () => { const { MockRendererLoggerService, mockRendererLoggerService } = await import('./__mocks__/RendererLoggerService') return { LoggerService: MockRendererLoggerService, loggerService: mockRendererLoggerService } }) // Mock PreferenceService globally for renderer tests vi.mock('@data/PreferenceService', async () => { const { MockPreferenceService } = await import('./__mocks__/renderer/PreferenceService') return MockPreferenceService }) // Mock DataApiService globally for renderer tests vi.mock('@data/DataApiService', async () => { const { MockDataApiService } = await import('./__mocks__/renderer/DataApiService') return MockDataApiService }) // Mock CacheService globally for renderer tests vi.mock('@data/CacheService', async () => { const { MockCacheService } = await import('./__mocks__/renderer/CacheService') return MockCacheService }) // Mock useDataApi hooks globally for renderer tests vi.mock('@data/hooks/useDataApi', async () => { const { MockUseDataApi } = await import('./__mocks__/renderer/useDataApi') return MockUseDataApi }) // Mock usePreference hooks globally for renderer tests vi.mock('@data/hooks/usePreference', async () => { const { MockUsePreference } = await import('./__mocks__/renderer/usePreference') return MockUsePreference }) // Mock useCache hooks globally for renderer tests vi.mock('@data/hooks/useCache', async () => { const { MockUseCache } = await import('./__mocks__/renderer/useCache') return MockUseCache }) // Mock PreferenceService globally for renderer tests vi.mock('@data/PreferenceService', async () => { const { MockPreferenceService } = await import('./__mocks__/renderer/PreferenceService') return MockPreferenceService }) // Mock DataApiService globally for renderer tests vi.mock('@data/DataApiService', async () => { const { MockDataApiService } = await import('./__mocks__/renderer/DataApiService') return MockDataApiService }) // Mock CacheService globally for renderer tests vi.mock('@data/CacheService', async () => { const { MockCacheService } = await import('./__mocks__/renderer/CacheService') return MockCacheService }) // Mock useDataApi hooks globally for renderer tests vi.mock('@data/hooks/useDataApi', async () => { const { MockUseDataApi } = await import('./__mocks__/renderer/useDataApi') return MockUseDataApi }) // Mock usePreference hooks globally for renderer tests vi.mock('@data/hooks/usePreference', async () => { const { MockUsePreference } = await import('./__mocks__/renderer/usePreference') return MockUsePreference }) // Mock useCache hooks globally for renderer tests vi.mock('@data/hooks/useCache', async () => { const { MockUseCache } = await import('./__mocks__/renderer/useCache') return MockUseCache }) // Mock uuid globally for renderer tests let uuidCounter = 0 vi.mock('uuid', () => ({ v4: () => 'test-uuid-' + ++uuidCounter })) vi.mock('@iconify/react', () => { const React = require('react') return { Icon: ({ icon, ...props }: { icon?: string }) => React.createElement('span', { ...props, 'data-icon': icon, 'data-testid': 'iconify-icon' }) } }) vi.mock('axios', () => { const defaultAxiosMock = { get: vi.fn().mockResolvedValue({ data: {} }), // Mocking axios GET request post: vi.fn().mockResolvedValue({ data: {} }) // Mocking axios POST request // You can add other axios methods like put, delete etc. as needed } const isAxiosError = (error: unknown): error is { isAxiosError?: boolean } => Boolean((error as { isAxiosError?: boolean } | undefined)?.isAxiosError) return { default: defaultAxiosMock, isAxiosError } }) // Mock ResizeObserver for jsdom environment vi.stubGlobal( 'ResizeObserver', class ResizeObserver { observe() {} unobserve() {} disconnect() {} } ) vi.stubGlobal('electron', { ipcRenderer: { on: vi.fn(), send: vi.fn(), invoke: vi.fn().mockResolvedValue(undefined) } }) vi.stubGlobal('api', { file: { read: vi.fn().mockResolvedValue('[]'), writeWithId: vi.fn().mockResolvedValue(undefined) } }) // Markdown stylesheet import is a side-effect no-op in tests vi.mock('@cherrystudio/ui/components/composites/markdown/styles', () => ({})) // Mock @cherrystudio/ui globally for renderer tests vi.mock('@cherrystudio/ui', () => { const React = require('react') const SelectContext = React.createContext({ value: undefined, onValueChange: undefined }) const PopoverContext = React.createContext({ open: false, onOpenChange: undefined }) const ContextMenuContext = React.createContext({ open: false, onOpenChange: undefined }) const DropdownMenuOpenContext = React.createContext(null) return { // Markdown — `@cherrystudio/ui` barrel re-exports composites/markdown (#16228). // Lightweight stand-ins so tests mounting real ChatMarkdown still surface text. Markdown: ({ children }) => React.createElement('div', null, children), StreamingMarkdown: ({ children }) => React.createElement('div', null, children), withChatPlugins: () => [], withMath: (plugins) => plugins ?? [], withMermaid: (plugins) => plugins ?? [], withFullMarkdown: (plugins) => plugins ?? [], defaultMarkdownPlugins: [], useMarkdownBlockContext: () => ({ content: '' }), createSlugger: () => ({ slug: (value) => String(value ?? '') }), extractTextFromNode: () => '', ReorderableList: ({ items, renderItem, getId }) => React.createElement( React.Fragment, null, items.map((item, index) => React.createElement('div', { key: getId(item) }, renderItem(item, index, { dragging: false })) ) ), Sortable: ({ items, itemKey, renderItem, className }) => { const getKey = typeof itemKey === 'function' ? itemKey : (item) => item[itemKey] return React.createElement( 'div', { className }, items.map((item) => React.createElement('div', { key: getKey(item) }, renderItem(item, { dragging: false, overlay: false })) ) ) }, NormalTooltip: ({ children }) => children, Button: ({ children, onPress, disabled, isDisabled, loading, startContent, asChild, ...props }) => { const buttonProps = { ...props, onClick: onPress ?? props.onClick, disabled: disabled || isDisabled || loading } if (asChild && React.isValidElement(children)) { const childProps = children.props || {} return React.cloneElement(children, { ...buttonProps, ...childProps, className: [buttonProps.className, childProps.className].filter(Boolean).join(' ') || undefined, style: { ...buttonProps.style, ...childProps.style }, onClick: (...args) => { buttonProps.onClick?.(...args) childProps.onClick?.(...args) }, onKeyDown: (...args) => { buttonProps.onKeyDown?.(...args) childProps.onKeyDown?.(...args) } }) } return React.createElement('button', buttonProps, startContent, children) }, Input: ({ hasError, 'aria-invalid': ariaInvalid, className, list, ...props }) => React.createElement('input', { ...props, list, 'aria-invalid': ariaInvalid, className: [ className, hasError || ariaInvalid ? 'ant-input-status-error' : undefined, list && ariaInvalid ? 'ant-select-status-error' : undefined ] .filter(Boolean) .join(' ') }), Textarea: { Input: ({ hasError, 'aria-invalid': ariaInvalid, className, onValueChange, onChange, ...props }) => React.createElement('textarea', { ...props, 'aria-invalid': ariaInvalid, className: [className, hasError || ariaInvalid ? 'ant-input-status-error' : undefined] .filter(Boolean) .join(' '), onChange: (event: React.ChangeEvent) => { onChange?.(event) onValueChange?.(event.target.value) } }) }, Accordion: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'accordion' }, children), AccordionItem: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'accordion-item' }, children), AccordionTrigger: ({ children, disabled, ...props }) => React.createElement( 'button', { ...props, type: 'button', disabled, 'data-testid': 'accordion-trigger' }, children ), AccordionContent: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'accordion-content' }, children), DropdownMenu: ({ children, onOpenChange }) => React.createElement( DropdownMenuOpenContext.Provider, { value: onOpenChange ?? null }, React.createElement('div', null, children) ), DropdownMenuTrigger: ({ children }) => { const onOpenChange = React.use(DropdownMenuOpenContext) return React.createElement('span', { onClick: () => onOpenChange?.(true) }, children) }, DropdownMenuContent: ({ children }) => React.createElement('div', null, children), DropdownMenuSeparator: () => React.createElement('hr'), DropdownMenuSub: ({ children }) => React.createElement('div', null, children), DropdownMenuSubContent: ({ children }) => React.createElement('div', null, children), DropdownMenuSubTrigger: ({ children }) => React.createElement('div', null, children), DropdownMenuCheckboxItem: ({ children, disabled, onCheckedChange }) => React.createElement('button', { type: 'button', disabled, onClick: onCheckedChange }, children), DropdownMenuItem: ({ children, disabled, onSelect }) => React.createElement('button', { type: 'button', disabled, onClick: onSelect }, children), ContextMenu: ({ children, defaultOpen = false, open: controlledOpen, onOpenChange, ...props }) => { const [uncontrolledOpen, setUncontrolledOpen] = React.useState(defaultOpen) const open = controlledOpen ?? uncontrolledOpen const handleOpenChange = (nextOpen: boolean) => { if (controlledOpen === undefined) { setUncontrolledOpen(nextOpen) } onOpenChange?.(nextOpen) } return React.createElement( ContextMenuContext.Provider, { value: { open, onOpenChange: handleOpenChange } }, React.createElement('div', { ...props, 'data-testid': 'context-menu' }, children) ) }, ContextMenuTrigger: ({ children, asChild, ...props }) => { const context = React.useContext(ContextMenuContext) const triggerProps = { ...props, 'data-testid': 'context-menu-trigger', onContextMenu: (event: React.MouseEvent) => { props.onContextMenu?.(event) if (!event.defaultPrevented && !props.disabled) { context.onOpenChange?.(true) event.preventDefault() } } } if (asChild && React.isValidElement(children)) { const childProps = children.props || {} return React.cloneElement(children, { ...triggerProps, ...childProps, onContextMenu: (event: React.MouseEvent) => { childProps.onContextMenu?.(event) if (!event.defaultPrevented) { triggerProps.onContextMenu(event) } } }) } return React.createElement('div', triggerProps, children) }, ContextMenuContent: ({ children, ...props }) => { const context = React.useContext(ContextMenuContext) return context.open ? React.createElement('div', { ...props, 'data-testid': 'context-menu-content' }, children) : null }, ContextMenuItem: ({ children, onSelect, ...props }) => { const context = React.useContext(ContextMenuContext) return React.createElement( 'button', { ...props, type: 'button', onClick: (event: React.MouseEvent) => { onSelect?.(event) context.onOpenChange?.(false) }, 'data-testid': 'context-menu-item' }, children ) }, ContextMenuItemContent: ({ badge, children, icon, shortcut, ...props }) => React.createElement( React.Fragment, null, React.createElement('span', { ...props }, icon, children), badge, shortcut ? React.createElement('span', null, shortcut) : null ), ContextMenuSeparator: (props) => React.createElement('div', { ...props, 'data-testid': 'context-menu-separator' }), ContextMenuSub: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'context-menu-sub' }, children), ContextMenuSubTrigger: ({ children, ...props }) => React.createElement('button', { ...props, type: 'button', 'data-testid': 'context-menu-sub-trigger' }, children), ContextMenuSubContent: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'context-menu-sub-content' }, children), ImagePreviewContextMenu: ({ actions = [], children, context, item }) => React.createElement( 'div', { 'data-testid': 'image-preview-context-menu' }, children, actions.map((action) => React.createElement( 'button', { disabled: action.disabled, key: action.id, onClick: () => action.onSelect?.(item, context), type: 'button' }, action.icon, action.label ) ) ), ImagePreviewDialog: ({ activeIndex = 0, items = [], labels = {}, onOpenChange, open, toolbarActions = [] }) => open ? React.createElement( 'div', { 'data-testid': 'image-preview-dialog' }, items[activeIndex] ? React.createElement('img', { alt: items[activeIndex].alt, src: items[activeIndex].src }) : null, toolbarActions.map((action) => React.createElement( 'button', { disabled: action.disabled, key: action.id, onClick: () => action.onSelect?.(items[activeIndex], { close: () => onOpenChange?.(false), index: activeIndex, items, resetTransform: vi.fn(), transform: { flipX: false, flipY: false, rotate: 0, scale: 1 } }), type: 'button' }, action.icon, action.label ) ), React.createElement( 'button', { 'aria-label': labels.close, onClick: () => onOpenChange?.(false), type: 'button' }, labels.close ) ) : null, ImagePreviewImage: ({ item, ...props }) => React.createElement('img', { ...props, alt: item?.alt, src: item?.src, 'data-testid': 'image-preview-image' }), ImagePreviewToolbar: ({ actions = [], context, item, labels = {}, onClose }) => React.createElement( 'div', { 'data-testid': 'image-preview-toolbar' }, actions.map((action) => React.createElement( 'button', { disabled: action.disabled, key: action.id, onClick: () => action.onSelect?.(item, context), type: 'button' }, action.icon, action.label ) ), React.createElement('button', { 'aria-label': labels.close, onClick: onClose, type: 'button' }, labels.close) ), ImagePreviewTrigger: ({ alt, dialogProps: _dialogProps, item, items: _items, ...props }) => React.createElement('img', { ...props, alt: alt ?? item?.alt, src: item?.src }), Dialog: ({ children, onOpenChange: _onOpenChange, open, ...props }) => open ? React.createElement('div', { ...props, role: 'dialog', 'data-testid': 'dialog' }, children) : null, DialogContent: ({ children, closeOnOverlayClick: _closeOnOverlayClick, ...props }) => React.createElement('div', { ...props, 'data-testid': 'dialog-content' }, children), DialogHeader: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'dialog-header' }, children), DialogTitle: ({ children, ...props }) => React.createElement('h2', { ...props, 'data-testid': 'dialog-title' }, children), DialogDescription: ({ children, ...props }) => React.createElement('p', { ...props, 'data-testid': 'dialog-description' }, children), DialogFooter: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'dialog-footer' }, children), Form: ({ children }) => React.createElement(React.Fragment, null, children), Label: ({ children, ...props }) => React.createElement('label', props, children), FieldError: ({ children, errors, ...props }) => { const errorMessage = children ?? errors?.find((error) => error?.message)?.message return errorMessage ? React.createElement('div', { ...props, role: 'alert' }, errorMessage) : null }, Popover: ({ children, open = false, onOpenChange, ...props }) => React.createElement( PopoverContext.Provider, { value: { open, onOpenChange } }, React.createElement('div', { ...props, 'data-testid': 'popover' }, children) ), PopoverAnchor: ({ children, asChild, ...props }) => { if (asChild && React.isValidElement(children)) { return React.cloneElement(children, { ...props, ...children.props }) } return React.createElement('div', props, children) }, PopoverTrigger: ({ children, asChild, ...props }) => { const context = React.useContext(PopoverContext) const triggerProps = { ...props, 'data-testid': 'popover-trigger', onClick: (event: React.MouseEvent) => { props.onClick?.(event) context.onOpenChange?.(!context.open) } } if (asChild && React.isValidElement(children)) { return React.cloneElement(children, { ...triggerProps, ...children.props }) } return React.createElement('div', triggerProps, children) }, PopoverContent: ({ children, align, side, sideOffset, ...props }) => { const context = React.useContext(PopoverContext) return context.open ? React.createElement('div', { ...props, 'data-testid': 'popover-content' }, children) : null }, MenuList: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'menu-list' }, children), MenuDivider: (props) => React.createElement('div', { ...props, 'data-testid': 'menu-divider' }), MenuItem: ({ children, icon, label, onClick, ...props }) => React.createElement( 'button', { ...props, type: 'button', onClick, 'data-testid': 'menu-item' }, icon, label, children ), Badge: ({ children, ...props }) => React.createElement('span', { ...props, 'data-testid': 'badge' }, children), Separator: (props) => React.createElement('hr', { ...props, 'data-testid': 'separator' }), Scrollbar: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'scrollbar' }, children), Dropzone: ({ children, getFilesFromEvent: _getFilesFromEvent, onDrop: _onDrop, maxFiles: _maxFiles, ...props }) => React.createElement('div', { ...props, 'data-testid': 'dropzone' }, children), DropzoneEmptyState: ({ children }) => React.createElement(React.Fragment, null, children), Kbd: ({ children, ...props }) => React.createElement('kbd', { ...props }, children), Checkbox: ({ checked, onCheckedChange, ...props }) => React.createElement('input', { ...props, checked, type: 'checkbox', 'data-slot': 'checkbox', onChange: (event: React.ChangeEvent) => onCheckedChange?.(event.target.checked) }), RadioGroup: ({ children, value, onValueChange, ...props }) => React.createElement('div', { ...props, 'data-testid': 'radio-group', 'data-value': value }, children), RadioGroupItem: ({ value, ...props }) => React.createElement('input', { ...props, type: 'radio', value, 'data-testid': 'radio-group-item' }), Slider: ({ value, defaultValue, onValueChange, onValueCommit, ...props }) => React.createElement('input', { ...props, type: 'range', value: value?.[0] ?? defaultValue?.[0] ?? 0, 'data-testid': 'slider', onChange: (event: React.ChangeEvent) => onValueChange?.([Number(event.target.value)]), onMouseUp: (event: React.MouseEvent) => onValueCommit?.([Number((event.target as HTMLInputElement).value)]) }), SegmentedControl: ({ options = [], value, onValueChange, ...props }) => React.createElement( 'div', { ...props, 'data-testid': 'segmented-control', 'data-value': value }, options.map((option) => React.createElement( 'button', { key: option.value, type: 'button', disabled: option.disabled, onClick: () => onValueChange?.(option.value) }, option.label ) ) ), Select: ({ children, value, onValueChange, ...props }) => { return React.createElement( SelectContext.Provider, { value: { value, onValueChange } }, React.createElement('div', { ...props, 'data-testid': 'select', 'data-value': value }, children) ) }, SelectTrigger: ({ children, ...props }) => React.createElement('button', { ...props, type: 'button', 'data-testid': 'select-trigger' }, children), SelectValue: ({ children, placeholder, ...props }) => React.createElement('span', { ...props, 'data-testid': 'select-value' }, children ?? placeholder), SelectContent: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'select-content' }, children), SelectItem: ({ children, value, ...props }) => { const context = React.useContext(SelectContext) return React.createElement( 'button', { ...props, type: 'button', 'data-testid': 'select-item', 'data-value': value, onClick: () => context.onValueChange?.(value) }, children ) }, Combobox: ({ options = [], value, onChange, onValueChange, placeholder, disabled, ...props }) => React.createElement( 'select', { ...props, disabled, value: value ?? '', 'data-testid': 'combobox', onChange: (event: React.ChangeEvent) => { onChange?.(event.target.value) onValueChange?.(event.target.value) } }, React.createElement('option', { value: '' }, placeholder), options.map((option) => React.createElement( 'option', { key: option.value, value: option.value, disabled: option.disabled }, option.label ) ) ), Tooltip: ({ children, title, content, mouseEnterDelay, classNames, className, ...props }) => { // Support both old (title) and new (content) API const tooltipText = content || title // Mirror the real Tooltip: the trigger wrapper carries classNames.placeholder. const wrapperClassName = [className, classNames?.placeholder].filter(Boolean).join(' ') || undefined return React.createElement( 'div', { ...props, ...(wrapperClassName && { className: wrapperClassName }), 'data-testid': 'tooltip', ...(tooltipText && { 'data-title': tooltipText }), 'data-mouse-enter-delay': mouseEnterDelay, className: classNames?.placeholder }, children, tooltipText ? React.createElement('div', { 'data-testid': 'tooltip-content' }, tooltipText) : null ) }, CircularProgress: ({ value, renderLabel, showLabel, ...props }) => React.createElement( 'div', { ...props, 'data-testid': 'circular-progress', 'data-value': value }, showLabel ? (renderLabel ? renderLabel(value) : value) : null ), CustomTag: ({ children, icon, color, size = 12, style, tooltip, closable, onClose, onClick, onContextMenu, disabled, inactive, className, ...props }) => { const actualColor = inactive ? '#aaaaaa' : color const tag = React.createElement( 'div', { ...props, className, style: { padding: `${size / 3}px ${closable ? size * 1.8 : size * 0.8}px ${size / 3}px ${size * 0.8}px`, color: actualColor, backgroundColor: actualColor + '20', fontSize: `${size}px`, lineHeight: 1, cursor: disabled ? 'not-allowed' : onClick ? 'pointer' : 'auto', ...style }, onClick: disabled ? undefined : onClick, onContextMenu: disabled ? undefined : onContextMenu }, icon, children, closable ? React.createElement( 'button', { type: 'button', onClick: (event) => { event.stopPropagation() onClose?.() } }, 'x' ) : null ) return tooltip ? React.createElement( 'div', { 'data-testid': 'tooltip', 'data-title': tooltip }, tag, React.createElement('div', { 'data-testid': 'tooltip-content' }, tooltip) ) : tag }, Spinner: ({ text, ...props }) => React.createElement('div', { ...props, 'data-testid': 'spinner' }, text), CodeEditor: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'code-editor' }, children), Flex: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'flex' }, children), ExpandableText: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'expandable-text' }, children), // Add other commonly used UI components Box: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'box' }, children), Center: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'center' }, children), ColFlex: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'col-flex' }, children), RowFlex: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'row-flex' }, children), SpaceBetweenRowFlex: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'space-between-row-flex' }, children), Ellipsis: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'ellipsis' }, children), TextBadge: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'text-badge' }, children), Badge: ({ children, ...props }) => React.createElement('span', { ...props, 'data-testid': 'badge' }, children), EmptyState: ({ title, description, actionLabel, onAction, secondaryLabel, onSecondary, ...props }) => React.createElement( 'div', { ...props, 'data-testid': 'empty-state' }, title ? React.createElement('div', {}, title) : null, description ? React.createElement('div', {}, description) : null, actionLabel && onAction ? React.createElement('button', { type: 'button', onClick: onAction }, actionLabel) : null, secondaryLabel && onSecondary ? React.createElement('button', { type: 'button', onClick: onSecondary }, secondaryLabel) : null ), Alert: ({ children, message, description, type, ...props }) => React.createElement( 'div', { ...props, role: 'alert', 'data-testid': 'alert', 'data-type': type }, message, description, children ), EditableNumber: ({ value, onChange, disabled, ...props }) => React.createElement('input', { ...props, type: 'number', value: value ?? '', disabled, 'data-testid': 'editable-number', onChange: (event: React.ChangeEvent) => onChange?.(event.target.value === '' ? null : event.target.valueAsNumber) }), Skeleton: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'skeleton' }, children), EmptyState: ({ children, title, description, preset, ...props }) => React.createElement( 'div', { ...props, 'data-testid': 'empty-state', 'data-preset': preset }, title ? React.createElement('div', {}, title) : null, description ? React.createElement('div', {}, description) : null, children ), HelpTooltip: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'help-tooltip' }, children), InfoTooltip: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'info-tooltip' }, children), Scrollbar: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'scrollbar' }, children), Avatar: ({ children, src, ...props }) => React.createElement('div', { ...props, 'data-testid': 'avatar' }, src ? null : children), AvatarImage: ({ src, ...props }) => React.createElement('img', { ...props, src, alt: '', 'data-testid': 'avatar-image' }), AvatarFallback: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'avatar-fallback' }, children), EmojiAvatar: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'emoji-avatar' }, children), EmojiIcon: ({ emoji, className, fluid, fontSize }) => React.createElement( 'div', { className, 'data-testid': 'emoji-icon', ...(fluid !== undefined ? { 'data-fluid': String(fluid) } : {}), ...(fontSize !== undefined ? { 'data-font-size': String(fontSize) } : {}) }, React.createElement('span', { 'aria-hidden': 'true', 'data-testid': 'emoji-icon-background' }, emoji || '⭐️'), emoji ), Switch: ({ isSelected, onValueChange, ...props }) => React.createElement('input', { ...props, type: 'checkbox', checked: isSelected, onChange: (e) => onValueChange?.(e.target.checked), 'data-testid': 'switch' }), // Popover primitives — Radix-style trigger / content split Popover: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'popover' }, children), PopoverTrigger: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'popover-trigger' }, children), PopoverContent: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'popover-content' }, children), Skeleton: ({ children, ...props }) => React.createElement('div', { ...props, 'data-testid': 'skeleton' }, children), // Icon registry stubs PROVIDER_ICON_CATALOG: {}, MODEL_ICON_CATALOG: {}, resolveProviderIcon: () => undefined, resolveModelIcon: () => undefined, resolveModelToProviderIcon: () => undefined, resolveIcon: () => undefined } }) if (typeof globalThis.localStorage === 'undefined' || typeof (globalThis.localStorage as any).getItem !== 'function') { let store = new Map() const localStorageMock = { getItem: (key: string) => store.get(key) ?? null, setItem: (key: string, value: string) => { store.set(key, String(value)) }, removeItem: (key: string) => { store.delete(key) }, clear: () => { store.clear() }, key: (index: number) => Array.from(store.keys())[index] ?? null, get length() { return store.size } } vi.stubGlobal('localStorage', localStorageMock) if (typeof window !== 'undefined') { Object.defineProperty(window, 'localStorage', { value: localStorageMock }) } }