mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-01-26 19:09:52 +00:00
* refactor: move settingStore to platform/settings Move src/stores/settingStore.ts to src/platform/settings/settingStore.ts to separate platform infrastructure from domain logic following DDD principles. Updates all import references across ~70 files to maintain compatibility. * fix: update remaining settingStore imports after rebase * fix: complete remaining settingStore import updates * fix: update vi.mock paths for settingStore in tests Update all test files to mock the new settingStore location at @/platform/settings/settingStore instead of @/stores/settingStore * fix: resolve remaining settingStore imports and unused imports after rebase * fix: update settingStore mock path in SelectionToolbox test Fix vi.mock path from @/stores/settingStore to @/platform/settings/settingStore to resolve failing Load3D viewer button test. * refactor: complete comprehensive settings migration to platform layer This commit completes the migration of all settings-related code to the platform layer as part of the Domain-Driven Design (DDD) architecture refactoring. - constants/coreSettings.ts → platform/settings/constants/coreSettings.ts - types/settingTypes.ts → platform/settings/types.ts - stores/settingStore.ts → platform/settings/settingStore.ts (already moved) - composables/setting/useSettingUI.ts → platform/settings/composables/useSettingUI.ts - composables/setting/useSettingSearch.ts → platform/settings/composables/useSettingSearch.ts - composables/useLitegraphSettings.ts → platform/settings/composables/useLitegraphSettings.ts - components/dialog/content/SettingDialogContent.vue → platform/settings/components/SettingDialogContent.vue - components/dialog/content/setting/SettingItem.vue → platform/settings/components/SettingItem.vue - components/dialog/content/setting/SettingGroup.vue → platform/settings/components/SettingGroup.vue - components/dialog/content/setting/SettingsPanel.vue → platform/settings/components/SettingsPanel.vue - components/dialog/content/setting/ColorPaletteMessage.vue → platform/settings/components/ColorPaletteMessage.vue - components/dialog/content/setting/ExtensionPanel.vue → platform/settings/components/ExtensionPanel.vue - components/dialog/content/setting/ServerConfigPanel.vue → platform/settings/components/ServerConfigPanel.vue - ~100+ import statements updated across the codebase - Test file imports corrected - Component imports fixed in dialog service and command menubar - Composable imports updated in GraphCanvas.vue ``` src/platform/settings/ ├── components/ # All settings UI components ├── composables/ # Settings-related composables ├── constants/ # Core settings definitions ├── types.ts # Settings type definitions └── settingStore.ts # Central settings state management ``` ✅ TypeScript compilation successful ✅ All tests passing (settings store, search functionality, UI components) ✅ Production build successful ✅ Domain boundaries properly established This migration consolidates all settings functionality into a cohesive platform domain, improving maintainability and following DDD principles for better code organization. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> * fix: format and lint after rebase conflict resolution * fix: update remaining import paths to platform settings - Fix browser test import: extensionAPI.spec.ts - Fix script import: collect-i18n-general.ts - Complete settings migration import path updates 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com> --------- Co-authored-by: Claude <noreply@anthropic.com>
429 lines
12 KiB
TypeScript
429 lines
12 KiB
TypeScript
import { createPinia, setActivePinia } from 'pinia'
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest'
|
|
import { nextTick } from 'vue'
|
|
|
|
import { st } from '@/i18n'
|
|
import { useSettingSearch } from '@/platform/settings/composables/useSettingSearch'
|
|
import {
|
|
getSettingInfo,
|
|
useSettingStore
|
|
} from '@/platform/settings/settingStore'
|
|
|
|
// Mock dependencies
|
|
vi.mock('@/i18n', () => ({
|
|
st: vi.fn((_: string, fallback: string) => fallback)
|
|
}))
|
|
|
|
vi.mock('@/platform/settings/settingStore', () => ({
|
|
useSettingStore: vi.fn(),
|
|
getSettingInfo: vi.fn()
|
|
}))
|
|
|
|
describe('useSettingSearch', () => {
|
|
let mockSettingStore: any
|
|
let mockSettings: any
|
|
|
|
beforeEach(() => {
|
|
setActivePinia(createPinia())
|
|
vi.clearAllMocks()
|
|
|
|
// Mock settings data
|
|
mockSettings = {
|
|
'Category.Setting1': {
|
|
id: 'Category.Setting1',
|
|
name: 'Setting One',
|
|
type: 'text',
|
|
defaultValue: 'default',
|
|
category: ['Category', 'Basic']
|
|
},
|
|
'Category.Setting2': {
|
|
id: 'Category.Setting2',
|
|
name: 'Setting Two',
|
|
type: 'boolean',
|
|
defaultValue: false,
|
|
category: ['Category', 'Advanced']
|
|
},
|
|
'Category.HiddenSetting': {
|
|
id: 'Category.HiddenSetting',
|
|
name: 'Hidden Setting',
|
|
type: 'hidden',
|
|
defaultValue: 'hidden',
|
|
category: ['Category', 'Basic']
|
|
},
|
|
'Category.DeprecatedSetting': {
|
|
id: 'Category.DeprecatedSetting',
|
|
name: 'Deprecated Setting',
|
|
type: 'text',
|
|
defaultValue: 'deprecated',
|
|
deprecated: true,
|
|
category: ['Category', 'Advanced']
|
|
},
|
|
'Other.Setting3': {
|
|
id: 'Other.Setting3',
|
|
name: 'Other Setting',
|
|
type: 'select',
|
|
defaultValue: 'option1',
|
|
category: ['Other', 'SubCategory']
|
|
}
|
|
}
|
|
|
|
// Mock setting store
|
|
mockSettingStore = {
|
|
settingsById: mockSettings
|
|
}
|
|
vi.mocked(useSettingStore).mockReturnValue(mockSettingStore)
|
|
|
|
// Mock getSettingInfo function
|
|
vi.mocked(getSettingInfo).mockImplementation((setting: any) => {
|
|
const parts = setting.category || setting.id.split('.')
|
|
return {
|
|
category: parts[0] ?? 'Other',
|
|
subCategory: parts[1] ?? 'Other'
|
|
}
|
|
})
|
|
|
|
// Mock st function to return fallback value
|
|
vi.mocked(st).mockImplementation((_: string, fallback: string) => fallback)
|
|
})
|
|
|
|
describe('initialization', () => {
|
|
it('initializes with default state', () => {
|
|
const search = useSettingSearch()
|
|
|
|
expect(search.searchQuery.value).toBe('')
|
|
expect(search.filteredSettingIds.value).toEqual([])
|
|
expect(search.searchInProgress.value).toBe(false)
|
|
expect(search.queryIsEmpty.value).toBe(true)
|
|
expect(search.inSearch.value).toBe(false)
|
|
expect(search.searchResultsCategories.value).toEqual(new Set())
|
|
})
|
|
})
|
|
|
|
describe('reactive properties', () => {
|
|
it('queryIsEmpty computed property works correctly', () => {
|
|
const search = useSettingSearch()
|
|
|
|
expect(search.queryIsEmpty.value).toBe(true)
|
|
|
|
search.searchQuery.value = 'test'
|
|
expect(search.queryIsEmpty.value).toBe(false)
|
|
|
|
search.searchQuery.value = ''
|
|
expect(search.queryIsEmpty.value).toBe(true)
|
|
})
|
|
|
|
it('inSearch computed property works correctly', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// Empty query, not in search
|
|
expect(search.inSearch.value).toBe(false)
|
|
|
|
// Has query but search in progress
|
|
search.searchQuery.value = 'test'
|
|
search.searchInProgress.value = true
|
|
expect(search.inSearch.value).toBe(false)
|
|
|
|
// Has query and search complete
|
|
search.searchInProgress.value = false
|
|
expect(search.inSearch.value).toBe(true)
|
|
})
|
|
|
|
it('searchResultsCategories computed property works correctly', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// No results
|
|
expect(search.searchResultsCategories.value).toEqual(new Set())
|
|
|
|
// Add some filtered results
|
|
search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3']
|
|
expect(search.searchResultsCategories.value).toEqual(
|
|
new Set(['Category', 'Other'])
|
|
)
|
|
})
|
|
|
|
it('watches searchQuery and sets searchInProgress to true', async () => {
|
|
const search = useSettingSearch()
|
|
|
|
expect(search.searchInProgress.value).toBe(false)
|
|
|
|
search.searchQuery.value = 'test'
|
|
await nextTick()
|
|
|
|
expect(search.searchInProgress.value).toBe(true)
|
|
})
|
|
})
|
|
|
|
describe('handleSearch', () => {
|
|
it('clears results when query is empty', () => {
|
|
const search = useSettingSearch()
|
|
search.filteredSettingIds.value = ['Category.Setting1']
|
|
|
|
search.handleSearch('')
|
|
|
|
expect(search.filteredSettingIds.value).toEqual([])
|
|
})
|
|
|
|
it('filters settings by ID (case insensitive)', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('category.setting1')
|
|
|
|
expect(search.filteredSettingIds.value).toContain('Category.Setting1')
|
|
expect(search.filteredSettingIds.value).not.toContain('Other.Setting3')
|
|
})
|
|
|
|
it('filters settings by name (case insensitive)', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('setting one')
|
|
|
|
expect(search.filteredSettingIds.value).toContain('Category.Setting1')
|
|
expect(search.filteredSettingIds.value).not.toContain('Category.Setting2')
|
|
})
|
|
|
|
it('filters settings by category', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('other')
|
|
|
|
expect(search.filteredSettingIds.value).toContain('Other.Setting3')
|
|
expect(search.filteredSettingIds.value).not.toContain('Category.Setting1')
|
|
})
|
|
|
|
it('excludes hidden settings from results', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('hidden')
|
|
|
|
expect(search.filteredSettingIds.value).not.toContain(
|
|
'Category.HiddenSetting'
|
|
)
|
|
})
|
|
|
|
it('excludes deprecated settings from results', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('deprecated')
|
|
|
|
expect(search.filteredSettingIds.value).not.toContain(
|
|
'Category.DeprecatedSetting'
|
|
)
|
|
})
|
|
|
|
it('sets searchInProgress to false after search', () => {
|
|
const search = useSettingSearch()
|
|
search.searchInProgress.value = true
|
|
|
|
search.handleSearch('test')
|
|
|
|
expect(search.searchInProgress.value).toBe(false)
|
|
})
|
|
|
|
it('includes visible settings in results', () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('setting')
|
|
|
|
expect(search.filteredSettingIds.value).toEqual(
|
|
expect.arrayContaining([
|
|
'Category.Setting1',
|
|
'Category.Setting2',
|
|
'Other.Setting3'
|
|
])
|
|
)
|
|
expect(search.filteredSettingIds.value).not.toContain(
|
|
'Category.HiddenSetting'
|
|
)
|
|
expect(search.filteredSettingIds.value).not.toContain(
|
|
'Category.DeprecatedSetting'
|
|
)
|
|
})
|
|
|
|
it('includes all visible settings in comprehensive search', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// Search for a partial match that should include multiple settings
|
|
search.handleSearch('setting')
|
|
|
|
// Should find all visible settings (not hidden/deprecated)
|
|
expect(search.filteredSettingIds.value.length).toBeGreaterThan(0)
|
|
expect(search.filteredSettingIds.value).toEqual(
|
|
expect.arrayContaining([
|
|
'Category.Setting1',
|
|
'Category.Setting2',
|
|
'Other.Setting3'
|
|
])
|
|
)
|
|
})
|
|
|
|
it('uses translated categories for search', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// Mock st to return translated category names
|
|
vi.mocked(st).mockImplementation((key: string, fallback: string) => {
|
|
if (key === 'settingsCategories.Category') {
|
|
return 'Translated Category'
|
|
}
|
|
return fallback
|
|
})
|
|
|
|
search.handleSearch('translated category')
|
|
|
|
expect(search.filteredSettingIds.value).toEqual(
|
|
expect.arrayContaining(['Category.Setting1', 'Category.Setting2'])
|
|
)
|
|
})
|
|
})
|
|
|
|
describe('getSearchResults', () => {
|
|
it('groups results by subcategory', () => {
|
|
const search = useSettingSearch()
|
|
search.filteredSettingIds.value = [
|
|
'Category.Setting1',
|
|
'Category.Setting2'
|
|
]
|
|
|
|
const results = search.getSearchResults(null)
|
|
|
|
expect(results).toEqual([
|
|
{
|
|
label: 'Basic',
|
|
settings: [mockSettings['Category.Setting1']]
|
|
},
|
|
{
|
|
label: 'Advanced',
|
|
settings: [mockSettings['Category.Setting2']]
|
|
}
|
|
])
|
|
})
|
|
|
|
it('filters results by active category', () => {
|
|
const search = useSettingSearch()
|
|
search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3']
|
|
|
|
const activeCategory = { label: 'Category' } as any
|
|
const results = search.getSearchResults(activeCategory)
|
|
|
|
expect(results).toEqual([
|
|
{
|
|
label: 'Basic',
|
|
settings: [mockSettings['Category.Setting1']]
|
|
}
|
|
])
|
|
})
|
|
|
|
it('returns all results when no active category', () => {
|
|
const search = useSettingSearch()
|
|
search.filteredSettingIds.value = ['Category.Setting1', 'Other.Setting3']
|
|
|
|
const results = search.getSearchResults(null)
|
|
|
|
expect(results).toEqual([
|
|
{
|
|
label: 'Basic',
|
|
settings: [mockSettings['Category.Setting1']]
|
|
},
|
|
{
|
|
label: 'SubCategory',
|
|
settings: [mockSettings['Other.Setting3']]
|
|
}
|
|
])
|
|
})
|
|
|
|
it('returns empty array when no filtered results', () => {
|
|
const search = useSettingSearch()
|
|
search.filteredSettingIds.value = []
|
|
|
|
const results = search.getSearchResults(null)
|
|
|
|
expect(results).toEqual([])
|
|
})
|
|
|
|
it('handles multiple settings in same subcategory', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// Add another setting to Basic subcategory
|
|
mockSettings['Category.Setting4'] = {
|
|
id: 'Category.Setting4',
|
|
name: 'Setting Four',
|
|
type: 'text',
|
|
defaultValue: 'default',
|
|
category: ['Category', 'Basic']
|
|
}
|
|
|
|
search.filteredSettingIds.value = [
|
|
'Category.Setting1',
|
|
'Category.Setting4'
|
|
]
|
|
|
|
const results = search.getSearchResults(null)
|
|
|
|
expect(results).toEqual([
|
|
{
|
|
label: 'Basic',
|
|
settings: [
|
|
mockSettings['Category.Setting1'],
|
|
mockSettings['Category.Setting4']
|
|
]
|
|
}
|
|
])
|
|
})
|
|
})
|
|
|
|
describe('edge cases', () => {
|
|
it('handles empty settings store', () => {
|
|
mockSettingStore.settingsById = {}
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('test')
|
|
|
|
expect(search.filteredSettingIds.value).toEqual([])
|
|
})
|
|
|
|
it('handles settings with undefined category', () => {
|
|
mockSettings['NoCategorySetting'] = {
|
|
id: 'NoCategorySetting',
|
|
name: 'No Category',
|
|
type: 'text',
|
|
defaultValue: 'default'
|
|
}
|
|
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('category')
|
|
|
|
expect(search.filteredSettingIds.value).toContain('NoCategorySetting')
|
|
})
|
|
|
|
it('handles special characters in search query', () => {
|
|
const search = useSettingSearch()
|
|
|
|
// Search for part of the ID that contains a dot
|
|
search.handleSearch('category.setting')
|
|
|
|
expect(search.filteredSettingIds.value).toContain('Category.Setting1')
|
|
})
|
|
|
|
it('handles very long search queries', () => {
|
|
const search = useSettingSearch()
|
|
const longQuery = 'a'.repeat(1000)
|
|
|
|
search.handleSearch(longQuery)
|
|
|
|
expect(search.filteredSettingIds.value).toEqual([])
|
|
})
|
|
|
|
it('handles rapid consecutive searches', async () => {
|
|
const search = useSettingSearch()
|
|
|
|
search.handleSearch('setting')
|
|
search.handleSearch('other')
|
|
search.handleSearch('category')
|
|
|
|
expect(search.filteredSettingIds.value).toEqual(
|
|
expect.arrayContaining(['Category.Setting1', 'Category.Setting2'])
|
|
)
|
|
})
|
|
})
|
|
})
|