mirror of
https://github.com/hanzo-studio/studio-desktop.git
synced 2026-10-30 18:54:12 +00:00
183 lines
7.4 KiB
TypeScript
183 lines
7.4 KiB
TypeScript
import log from 'electron-log/main';
|
|
import fsPromises from 'node:fs/promises';
|
|
import path from 'node:path';
|
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
|
|
import { ComfySettings, type ComfySettingsData, DEFAULT_SETTINGS, useComfySettings } from '@/config/comfySettings';
|
|
|
|
vi.mock('node:fs/promises', () => ({
|
|
default: {
|
|
access: vi.fn(),
|
|
readFile: vi.fn(),
|
|
writeFile: vi.fn(),
|
|
},
|
|
access: vi.fn(),
|
|
readFile: vi.fn(),
|
|
writeFile: vi.fn(),
|
|
}));
|
|
|
|
describe('ComfySettings', () => {
|
|
const basePath = path.join('test', 'base', 'path');
|
|
const expectedFilePath = path.join(basePath, 'user', 'default', 'comfy.settings.json');
|
|
let settings: ComfySettings;
|
|
|
|
beforeEach(async () => {
|
|
// Reset writeLocked state
|
|
// @ts-expect-error accessing private static
|
|
ComfySettings.writeLocked = false;
|
|
|
|
// Reset fs mocks with default behaviors
|
|
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
vi.mocked(fsPromises.readFile).mockResolvedValue('{}');
|
|
vi.mocked(fsPromises.writeFile).mockResolvedValue(undefined);
|
|
|
|
settings = await ComfySettings.load(basePath);
|
|
});
|
|
|
|
describe('write locking', () => {
|
|
it('should allow writes before being locked', async () => {
|
|
await settings.saveSettings();
|
|
expect(fsPromises.writeFile).toHaveBeenCalledWith(expectedFilePath, JSON.stringify(DEFAULT_SETTINGS, null, 2));
|
|
});
|
|
|
|
it('should prevent writes after being locked', async () => {
|
|
ComfySettings.lockWrites();
|
|
await expect(settings.saveSettings()).rejects.toThrow('Settings are locked');
|
|
expect(fsPromises.writeFile).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('should prevent modifications after being locked', () => {
|
|
ComfySettings.lockWrites();
|
|
expect(() => settings.set('Comfy-Desktop.AutoUpdate', false)).toThrow('Settings are locked');
|
|
});
|
|
|
|
it('should allow reads after being locked', () => {
|
|
ComfySettings.lockWrites();
|
|
expect(() => settings.get('Comfy-Desktop.AutoUpdate')).not.toThrow();
|
|
});
|
|
|
|
it('should share lock state across references', async () => {
|
|
const settings1 = settings;
|
|
const settings2 = await ComfySettings.load(basePath);
|
|
|
|
ComfySettings.lockWrites();
|
|
|
|
expect(() => settings1.set('Comfy-Desktop.AutoUpdate', false)).toThrow('Settings are locked');
|
|
expect(() => settings2.set('Comfy-Desktop.AutoUpdate', false)).toThrow('Settings are locked');
|
|
});
|
|
|
|
it('should throw error when saving locked settings', async () => {
|
|
ComfySettings.lockWrites();
|
|
await expect(settings.saveSettings()).rejects.toThrow('Settings are locked');
|
|
});
|
|
});
|
|
|
|
describe('file operations', () => {
|
|
it('should use correct file path', async () => {
|
|
await settings.saveSettings();
|
|
expect(fsPromises.writeFile).toHaveBeenCalledWith(expectedFilePath, JSON.stringify(DEFAULT_SETTINGS, null, 2));
|
|
});
|
|
|
|
it('should load settings from file when available', async () => {
|
|
const mockSettings: ComfySettingsData = {
|
|
'Comfy-Desktop.AutoUpdate': false,
|
|
'Comfy-Desktop.SendStatistics': false,
|
|
'Comfy.ColorPalette': 'dark',
|
|
'Comfy.UseNewMenu': 'Top',
|
|
'Comfy.Workflow.WorkflowTabsPosition': 'Topbar',
|
|
'Comfy.Workflow.ShowMissingModelsWarning': true,
|
|
'Comfy.Server.LaunchArgs': { test: 'value' },
|
|
'Comfy-Desktop.UV.PythonInstallMirror': '',
|
|
'Comfy-Desktop.UV.PypiInstallMirror': '',
|
|
'Comfy-Desktop.UV.TorchInstallMirror': '',
|
|
};
|
|
|
|
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
vi.mocked(fsPromises.readFile).mockResolvedValue(JSON.stringify(mockSettings));
|
|
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(settings.get('Comfy-Desktop.AutoUpdate')).toBe(false);
|
|
expect(settings.get('Comfy.Server.LaunchArgs')).toEqual({ test: 'value' });
|
|
expect(settings.get('Comfy-Desktop.SendStatistics')).toBe(false);
|
|
});
|
|
|
|
it('should use default settings when file does not exist', async () => {
|
|
vi.mocked(fsPromises.access).mockRejectedValue(new Error('ENOENT'));
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(settings.get('Comfy-Desktop.AutoUpdate')).toBe(DEFAULT_SETTINGS['Comfy-Desktop.AutoUpdate']);
|
|
});
|
|
|
|
it('should save settings to correct path with proper formatting', async () => {
|
|
settings.set('Comfy-Desktop.AutoUpdate', false);
|
|
await settings.saveSettings();
|
|
|
|
const writeCall = vi.mocked(fsPromises.writeFile).mock.calls.at(-1);
|
|
if (!writeCall) throw new Error('No write calls recorded');
|
|
const savedJson = JSON.parse(writeCall[1] as string);
|
|
|
|
expect(writeCall[0]).toBe(expectedFilePath);
|
|
expect(savedJson['Comfy-Desktop.AutoUpdate']).toBe(false);
|
|
});
|
|
|
|
it('should fall back to defaults on file read error', async () => {
|
|
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
vi.mocked(fsPromises.readFile).mockRejectedValue(new Error('Permission denied'));
|
|
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(settings.get('Comfy-Desktop.AutoUpdate')).toBe(DEFAULT_SETTINGS['Comfy-Desktop.AutoUpdate']);
|
|
expect(log.error).toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
describe('settings operations', () => {
|
|
it('should handle nested objects correctly', () => {
|
|
const customLaunchArgs = { '--port': '8188', '--listen': '0.0.0.0' };
|
|
settings.set('Comfy.Server.LaunchArgs', customLaunchArgs);
|
|
expect(settings.get('Comfy.Server.LaunchArgs')).toEqual(customLaunchArgs);
|
|
});
|
|
|
|
it('should preserve primitive and object types when getting/setting values', () => {
|
|
settings.set('Comfy-Desktop.SendStatistics', false);
|
|
expect(typeof settings.get('Comfy-Desktop.SendStatistics')).toBe('boolean');
|
|
|
|
const serverArgs = { test: 'value' };
|
|
settings.set('Comfy.Server.LaunchArgs', serverArgs);
|
|
expect(typeof settings.get('Comfy.Server.LaunchArgs')).toBe('object');
|
|
});
|
|
|
|
it('should fall back to defaults for null/undefined values in settings file', async () => {
|
|
const invalidSettings = {
|
|
'Comfy-Desktop.AutoUpdate': undefined,
|
|
'Comfy.Server.LaunchArgs': null,
|
|
};
|
|
|
|
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
vi.mocked(fsPromises.readFile).mockResolvedValue(JSON.stringify(invalidSettings));
|
|
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(settings.get('Comfy-Desktop.AutoUpdate')).toBe(DEFAULT_SETTINGS['Comfy-Desktop.AutoUpdate']);
|
|
expect(settings.get('Comfy.Server.LaunchArgs')).toEqual(DEFAULT_SETTINGS['Comfy.Server.LaunchArgs']);
|
|
});
|
|
|
|
it('should fall back to defaults when settings file contains invalid JSON', async () => {
|
|
vi.mocked(fsPromises.access).mockResolvedValue(undefined);
|
|
vi.mocked(fsPromises.readFile).mockRejectedValue(new Error('Invalid JSON'));
|
|
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(settings.get('Comfy-Desktop.AutoUpdate')).toBe(DEFAULT_SETTINGS['Comfy-Desktop.AutoUpdate']);
|
|
});
|
|
|
|
it('should throw error on write error during saveSettings', async () => {
|
|
vi.mocked(fsPromises.writeFile).mockRejectedValue(new Error('Permission denied'));
|
|
await expect(settings.saveSettings()).rejects.toThrow('Permission denied');
|
|
});
|
|
});
|
|
|
|
describe('useComfySettings', () => {
|
|
it('should return the current instance after initialization', async () => {
|
|
settings = await ComfySettings.load(basePath);
|
|
expect(useComfySettings()).toBe(settings);
|
|
});
|
|
});
|
|
});
|