feat(setttings): support auto launch config (#415)

Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Co-authored-by: Haze <hazeone@users.noreply.github.com>
This commit is contained in:
Haze
2026-03-11 18:41:18 +08:00
committed by GitHub
Unverified
parent baa551b30c
commit 53a51642ce
14 changed files with 275 additions and 7 deletions

View File

@@ -0,0 +1,91 @@
import { access, readFile, rm } from 'node:fs/promises';
import { join } from 'node:path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
const originalPlatform = process.platform;
const {
testHome,
electronAppMock,
setLoginItemSettingsMock,
} = vi.hoisted(() => {
const suffix = Math.random().toString(36).slice(2);
const setLoginItemSettingsMock = vi.fn();
const electronAppMock = {
isPackaged: true,
getPath: (name: string) => (name === 'home' ? `/tmp/clawx-launch-startup-${suffix}` : '/tmp'),
setLoginItemSettings: setLoginItemSettingsMock,
};
return {
testHome: `/tmp/clawx-launch-startup-${suffix}`,
electronAppMock,
setLoginItemSettingsMock,
};
});
vi.mock('electron', () => ({
app: electronAppMock,
}));
function setPlatform(platform: string): void {
Object.defineProperty(process, 'platform', { value: platform, writable: true });
}
describe('launch-at-startup integration', () => {
beforeEach(async () => {
vi.resetModules();
vi.clearAllMocks();
electronAppMock.isPackaged = true;
await rm(testHome, { recursive: true, force: true });
});
afterEach(() => {
Object.defineProperty(process, 'platform', { value: originalPlatform, writable: true });
});
it('uses login item settings on Windows', async () => {
setPlatform('win32');
const { applyLaunchAtStartupSetting } = await import('@electron/main/launch-at-startup');
await applyLaunchAtStartupSetting(true);
expect(setLoginItemSettingsMock).toHaveBeenCalledWith({
openAtLogin: true,
openAsHidden: false,
});
});
it('uses login item settings on macOS', async () => {
setPlatform('darwin');
const { applyLaunchAtStartupSetting } = await import('@electron/main/launch-at-startup');
await applyLaunchAtStartupSetting(false);
expect(setLoginItemSettingsMock).toHaveBeenCalledWith({
openAtLogin: false,
openAsHidden: false,
});
});
it('creates and removes Linux autostart desktop entry', async () => {
setPlatform('linux');
const { applyLaunchAtStartupSetting } = await import('@electron/main/launch-at-startup');
const autostartPath = join(testHome, '.config', 'autostart', 'clawx.desktop');
await applyLaunchAtStartupSetting(true);
const content = await readFile(autostartPath, 'utf8');
expect(content).toContain('[Desktop Entry]');
expect(content).toContain('Name=ClawX');
expect(content).toContain('Exec=');
await applyLaunchAtStartupSetting(false);
await expect(access(autostartPath)).rejects.toThrow();
});
it('does not throw on unsupported platforms', async () => {
setPlatform('freebsd');
const { applyLaunchAtStartupSetting } = await import('@electron/main/launch-at-startup');
await expect(applyLaunchAtStartupSetting(true)).resolves.toBeUndefined();
});
});

View File

@@ -47,6 +47,30 @@ describe('Settings Store', () => {
setDevModeUnlocked(true);
expect(useSettingsStore.getState().devModeUnlocked).toBe(true);
});
it('should persist launch-at-startup setting through host api', () => {
const invoke = vi.mocked(window.electron.ipcRenderer.invoke);
invoke.mockResolvedValueOnce({
ok: true,
data: {
status: 200,
ok: true,
json: { success: true },
},
});
const { setLaunchAtStartup } = useSettingsStore.getState();
setLaunchAtStartup(true);
expect(useSettingsStore.getState().launchAtStartup).toBe(true);
expect(invoke).toHaveBeenCalledWith(
'hostapi:fetch',
expect.objectContaining({
path: '/api/settings/launchAtStartup',
method: 'PUT',
}),
);
});
});
describe('Gateway Store', () => {