diff --git a/tests-ui/platform/settings/settingStore.test.ts b/tests-ui/platform/settings/settingStore.test.ts deleted file mode 100644 index 2aac02ba9..000000000 --- a/tests-ui/platform/settings/settingStore.test.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest' -import { setActivePinia, createPinia } from 'pinia' - -const hoisted = vi.hoisted(() => ({ - trackSettingChanged: vi.fn(), - storeSetting: vi.fn().mockResolvedValue(undefined) -})) - -let isSettingsDialogOpen = false - -vi.mock('@/platform/telemetry', () => { - return { - useTelemetry: () => ({ - trackSettingChanged: hoisted.trackSettingChanged - }) - } -}) - -vi.mock('@/stores/dialogStore', () => { - return { - useDialogStore: () => ({ - isDialogOpen: (key: string) => - isSettingsDialogOpen && key === 'global-settings' - }) - } -}) - -vi.mock('@/scripts/api', () => { - return { - api: { - storeSetting: hoisted.storeSetting, - getSettings: vi.fn().mockResolvedValue({}) - } - } -}) - -vi.mock('@/scripts/app', () => { - return { - app: { - ui: { - settings: { - dispatchChange: vi.fn() - } - } - } - } -}) - -import { useSettingStore } from '@/platform/settings/settingStore' - -describe('useSettingStore telemetry', () => { - beforeEach(() => { - setActivePinia(createPinia()) - hoisted.trackSettingChanged.mockReset() - hoisted.storeSetting.mockReset().mockResolvedValue(undefined) - isSettingsDialogOpen = false - }) - - it('tracks telemetry when settings dialog is open', async () => { - isSettingsDialogOpen = true - - const store = useSettingStore() - store.addSetting({ - id: 'main.sub.setting.name', - name: 'Test Setting', - type: 'text', - defaultValue: 'old' - }) - - await store.set('main.sub.setting.name', 'new') - - expect(hoisted.trackSettingChanged).toHaveBeenCalledTimes(1) - expect(hoisted.trackSettingChanged).toHaveBeenCalledWith({ - setting_id: 'main.sub.setting.name', - input_type: 'text', - category: 'main', - sub_category: 'sub', - previous_value: 'old', - new_value: 'new' - }) - }) - - it('does not track telemetry when settings dialog is closed', async () => { - isSettingsDialogOpen = false - - const store = useSettingStore() - store.addSetting({ - id: 'single.setting', - name: 'Another Setting', - type: 'text', - defaultValue: 'x' - }) - - await store.set('single.setting', 'y') - - expect(hoisted.trackSettingChanged).not.toHaveBeenCalled() - }) -}) diff --git a/tests-ui/tests/store/settingStore.test.ts b/tests-ui/tests/store/settingStore.test.ts index 60d7acd1c..45ffa578f 100644 --- a/tests-ui/tests/store/settingStore.test.ts +++ b/tests-ui/tests/store/settingStore.test.ts @@ -1,559 +1,98 @@ import { createPinia, setActivePinia } from 'pinia' import { beforeEach, describe, expect, it, vi } from 'vitest' -import { - getSettingInfo, - useSettingStore -} from '@/platform/settings/settingStore' -import type { SettingParams } from '@/platform/settings/types' -import { api } from '@/scripts/api' -import { app } from '@/scripts/app' +import { useSettingStore } from '@/platform/settings/settingStore' -// Mock the api -vi.mock('@/scripts/api', () => ({ - api: { - getSettings: vi.fn(), - storeSetting: vi.fn() - } +const hoisted = vi.hoisted(() => ({ + trackSettingChanged: vi.fn(), + storeSetting: vi.fn().mockResolvedValue(undefined) })) -// Mock the app -vi.mock('@/scripts/app', () => ({ - app: { - ui: { - settings: { - dispatchChange: vi.fn() +let isSettingsDialogOpen = false + +vi.mock('@/platform/telemetry', () => { + return { + useTelemetry: () => ({ + trackSettingChanged: hoisted.trackSettingChanged + }) + } +}) + +vi.mock('@/stores/dialogStore', () => { + return { + useDialogStore: () => ({ + isDialogOpen: (key: string) => + isSettingsDialogOpen && key === 'global-settings' + }) + } +}) + +vi.mock('@/scripts/api', () => { + return { + api: { + storeSetting: hoisted.storeSetting, + getSettings: vi.fn().mockResolvedValue({}) + } + } +}) + +vi.mock('@/scripts/app', () => { + return { + app: { + ui: { + settings: { + dispatchChange: vi.fn() + } } } } -})) - -describe('useSettingStore', () => { - let store: ReturnType +}) +describe('useSettingStore telemetry', () => { beforeEach(() => { setActivePinia(createPinia()) - store = useSettingStore() - vi.clearAllMocks() + hoisted.trackSettingChanged.mockReset() + hoisted.storeSetting.mockReset().mockResolvedValue(undefined) + isSettingsDialogOpen = false }) - it('should initialize with empty settings', () => { - expect(store.settingValues).toEqual({}) - expect(store.settingsById).toEqual({}) - }) + it('tracks telemetry when settings dialog is open', async () => { + isSettingsDialogOpen = true - describe('loadSettingValues', () => { - it('should load settings from API', async () => { - const mockSettings = { 'test.setting': 'value' } - vi.mocked(api.getSettings).mockResolvedValue(mockSettings as any) - - await store.loadSettingValues() - - expect(store.settingValues).toEqual(mockSettings) - expect(api.getSettings).toHaveBeenCalled() + const store = useSettingStore() + store.addSetting({ + id: 'main.sub.setting.name', + name: 'Test Setting', + type: 'text', + defaultValue: 'old' }) - it('should throw error if settings are loaded after registration', async () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default' - } - store.addSetting(setting) + await store.set('main.sub.setting.name', 'new') - await expect(store.loadSettingValues()).rejects.toThrow( - 'Setting values must be loaded before any setting is registered.' - ) - }) - }) - - describe('addSetting', () => { - it('should register a new setting', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default' - } - - store.addSetting(setting) - - expect(store.settingsById['test.setting']).toEqual(setting) - }) - - it('should throw error for duplicate setting ID', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default' - } - - store.addSetting(setting) - expect(() => store.addSetting(setting)).toThrow( - 'Setting test.setting must have a unique ID.' - ) - }) - - it('should migrate deprecated values', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default', - migrateDeprecatedValue: (value: string) => value.toUpperCase() - } - - store.settingValues['test.setting'] = 'oldvalue' - store.addSetting(setting) - - expect(store.settingValues['test.setting']).toBe('OLDVALUE') - }) - }) - - describe('getDefaultValue', () => { - beforeEach(() => { - // Set up installed version for most tests - store.settingValues['Comfy.InstalledVersion'] = '1.30.0' - }) - - it('should return regular default value when no defaultsByInstallVersion', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default' - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - expect(result).toBe('regular-default') - }) - - it('should return versioned default when user version matches', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // installedVersion is 1.30.0, so should get 1.21.3 default - expect(result).toBe('version-1.21.3-default') - }) - - it('should return latest versioned default when user version is higher', () => { - store.settingValues['Comfy.InstalledVersion'] = '1.50.0' - - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // installedVersion is 1.50.0, so should get 1.40.3 default - expect(result).toBe('version-1.40.3-default') - }) - - it('should return regular default when user version is lower than all versioned defaults', () => { - store.settingValues['Comfy.InstalledVersion'] = '1.10.0' - - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // installedVersion is 1.10.0, lower than all versioned defaults - expect(result).toBe('regular-default') - }) - - it('should return regular default when no installed version (existing users)', () => { - // Clear installed version to simulate existing user - delete store.settingValues['Comfy.InstalledVersion'] - - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // No installed version, should use backward compatibility - expect(result).toBe('regular-default') - }) - - it('should handle function-based versioned defaults', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': () => 'dynamic-version-1.21.3-default', - '1.40.3': () => 'dynamic-version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // installedVersion is 1.30.0, so should get 1.21.3 default (executed) - expect(result).toBe('dynamic-version-1.21.3-default') - }) - - it('should handle function-based regular defaults with versioned defaults', () => { - store.settingValues['Comfy.InstalledVersion'] = '1.10.0' - - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: () => 'dynamic-regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - const result = store.getDefaultValue('test.setting') - // installedVersion is 1.10.0, should fallback to function-based regular default - expect(result).toBe('dynamic-regular-default') - }) - - it('should handle complex version comparison correctly', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.21.10': 'version-1.21.10-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - // Test with 1.21.5 - should get 1.21.3 default - store.settingValues['Comfy.InstalledVersion'] = '1.21.5' - expect(store.getDefaultValue('test.setting')).toBe( - 'version-1.21.3-default' - ) - - // Test with 1.21.15 - should get 1.21.10 default - store.settingValues['Comfy.InstalledVersion'] = '1.21.15' - expect(store.getDefaultValue('test.setting')).toBe( - 'version-1.21.10-default' - ) - - // Test with 1.21.3 exactly - should get 1.21.3 default - store.settingValues['Comfy.InstalledVersion'] = '1.21.3' - expect(store.getDefaultValue('test.setting')).toBe( - 'version-1.21.3-default' - ) - }) - - it('should work with get() method using versioned defaults', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': 'version-1.21.3-default', - '1.40.3': 'version-1.40.3-default' - } - } - store.addSetting(setting) - - // get() should use getDefaultValue internally - const result = store.get('test.setting') - expect(result).toBe('version-1.21.3-default') - }) - - it('should handle mixed function and static versioned defaults', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.21.3': () => 'dynamic-1.21.3-default', - '1.40.3': 'static-1.40.3-default' - } - } - store.addSetting(setting) - - // Test with 1.30.0 - should get dynamic 1.21.3 default - store.settingValues['Comfy.InstalledVersion'] = '1.30.0' - expect(store.getDefaultValue('test.setting')).toBe( - 'dynamic-1.21.3-default' - ) - - // Test with 1.50.0 - should get static 1.40.3 default - store.settingValues['Comfy.InstalledVersion'] = '1.50.0' - expect(store.getDefaultValue('test.setting')).toBe( - 'static-1.40.3-default' - ) - }) - - it('should handle version sorting correctly', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test Setting', - type: 'text', - defaultValue: 'regular-default', - defaultsByInstallVersion: { - '1.40.3': 'version-1.40.3-default', - '1.21.3': 'version-1.21.3-default', // Unsorted order - '1.35.0': 'version-1.35.0-default' - } - } - store.addSetting(setting) - - // Test with 1.37.0 - should get 1.35.0 default (highest version <= 1.37.0) - store.settingValues['Comfy.InstalledVersion'] = '1.37.0' - expect(store.getDefaultValue('test.setting')).toBe( - 'version-1.35.0-default' - ) - }) - }) - - describe('get and set', () => { - it('should get default value when setting not exists', () => { - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default' - } - store.addSetting(setting) - - expect(store.get('test.setting')).toBe('default') - }) - - it('should set value and trigger onChange', async () => { - const onChangeMock = vi.fn() - const dispatchChangeMock = vi.mocked(app.ui.settings.dispatchChange) - const setting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default', - onChange: onChangeMock - } - store.addSetting(setting) - // Adding the new setting should trigger onChange - expect(onChangeMock).toHaveBeenCalledTimes(1) - expect(dispatchChangeMock).toHaveBeenCalledTimes(1) - - await store.set('test.setting', 'newvalue') - - expect(store.get('test.setting')).toBe('newvalue') - expect(onChangeMock).toHaveBeenCalledWith('newvalue', 'default') - expect(onChangeMock).toHaveBeenCalledTimes(2) - expect(dispatchChangeMock).toHaveBeenCalledTimes(2) - expect(api.storeSetting).toHaveBeenCalledWith('test.setting', 'newvalue') - - // Set the same value again, it should not trigger onChange - await store.set('test.setting', 'newvalue') - expect(onChangeMock).toHaveBeenCalledTimes(2) - expect(dispatchChangeMock).toHaveBeenCalledTimes(2) - - // Set a different value, it should trigger onChange - await store.set('test.setting', 'differentvalue') - expect(onChangeMock).toHaveBeenCalledWith('differentvalue', 'newvalue') - expect(onChangeMock).toHaveBeenCalledTimes(3) - expect(dispatchChangeMock).toHaveBeenCalledTimes(3) - expect(api.storeSetting).toHaveBeenCalledWith( - 'test.setting', - 'differentvalue' - ) - }) - - describe('object mutation prevention', () => { - beforeEach(() => { - const setting: SettingParams = { - id: 'test.setting', - name: 'Test setting', - type: 'hidden', - defaultValue: {} - } - store.addSetting(setting) - }) - - it('should prevent mutations of objects after set', async () => { - const originalObject = { foo: 'bar', nested: { value: 123 } } - - await store.set('test.setting', originalObject) - - // Attempt to mutate the original object - originalObject.foo = 'changed' - originalObject.nested.value = 456 - - // Get the stored value - const storedValue = store.get('test.setting') - - // Verify the stored value wasn't affected by the mutation - expect(storedValue).toEqual({ foo: 'bar', nested: { value: 123 } }) - }) - - it('should prevent mutations of retrieved objects', async () => { - const initialValue = { foo: 'bar', nested: { value: 123 } } - - // Set initial value - await store.set('test.setting', initialValue) - - // Get the value and try to mutate it - const retrievedValue = store.get('test.setting') - retrievedValue.foo = 'changed' - if (retrievedValue.nested) { - retrievedValue.nested.value = 456 - } - - // Get the value again - const newRetrievedValue = store.get('test.setting') - - // Verify the stored value wasn't affected by the mutation - expect(newRetrievedValue).toEqual({ - foo: 'bar', - nested: { value: 123 } - }) - }) - - it('should prevent mutations of arrays after set', async () => { - const originalArray = [1, 2, { value: 3 }] - - await store.set('test.setting', originalArray) - - // Attempt to mutate the original array - originalArray.push(4) - if (typeof originalArray[2] === 'object') { - originalArray[2].value = 999 - } - - // Get the stored value - const storedValue = store.get('test.setting') - - // Verify the stored value wasn't affected by the mutation - expect(storedValue).toEqual([1, 2, { value: 3 }]) - }) - - it('should prevent mutations of retrieved arrays', async () => { - const initialArray = [1, 2, { value: 3 }] - - // Set initial value - await store.set('test.setting', initialArray) - - // Get the value and try to mutate it - const retrievedArray = store.get('test.setting') - retrievedArray.push(4) - if (typeof retrievedArray[2] === 'object') { - retrievedArray[2].value = 999 - } - - // Get the value again - const newRetrievedValue = store.get('test.setting') - - // Verify the stored value wasn't affected by the mutation - expect(newRetrievedValue).toEqual([1, 2, { value: 3 }]) - }) - }) - }) -}) - -describe('getSettingInfo', () => { - const baseSetting: SettingParams = { - id: 'test.setting', - name: 'test.setting', - type: 'text', - defaultValue: 'default' - } - - it('should handle settings with explicit category array', () => { - const setting: SettingParams = { - ...baseSetting, - id: 'test.setting', - category: ['Main', 'Sub', 'Detail'] - } - - const result = getSettingInfo(setting) - - expect(result).toEqual({ - category: 'Main', - subCategory: 'Sub' - }) - }) - - it('should handle settings with id-based categorization', () => { - const setting: SettingParams = { - ...baseSetting, - id: 'main.sub.setting.name' - } - - const result = getSettingInfo(setting) - - expect(result).toEqual({ + expect(hoisted.trackSettingChanged).toHaveBeenCalledTimes(1) + expect(hoisted.trackSettingChanged).toHaveBeenCalledWith({ + setting_id: 'main.sub.setting.name', + input_type: 'text', category: 'main', - subCategory: 'sub' + sub_category: 'sub', + previous_value: 'old', + new_value: 'new' }) }) - it('should use "Other" as default subCategory when missing', () => { - const setting: SettingParams = { - ...baseSetting, + it('does not track telemetry when settings dialog is closed', async () => { + isSettingsDialogOpen = false + + const store = useSettingStore() + store.addSetting({ id: 'single.setting', - category: ['single'] - } - - const result = getSettingInfo(setting) - - expect(result).toEqual({ - category: 'single', - subCategory: 'Other' + name: 'Another Setting', + type: 'text', + defaultValue: 'x' }) - }) - it('should use "Other" as default category when missing', () => { - const setting: SettingParams = { - ...baseSetting, - id: 'single.setting', - category: [] - } + await store.set('single.setting', 'y') - const result = getSettingInfo(setting) - - expect(result).toEqual({ - category: 'Other', - subCategory: 'Other' - }) + expect(hoisted.trackSettingChanged).not.toHaveBeenCalled() }) })