두 macOS 한정 버그 묶음: 1. autostart --hidden 으로 spawn 시 quickCapture (NSPanel) 만 떠 있어 dock running indicator (점) 가 표출 안 됨 — NSPanel 은 NSApp main window 로 register 안 됨. inboxWindow 를 hidden 상태로 미리 create + ready-to-show 시점에 showInactive → hide trick 으로 NSApp 에 register, 사용자 화면 깜빡임 없이 dock 점 켜짐. 2. SettingsPage 의 자동실행 mismatch 경고가 macOS 에서 false positive. macOS 13+ 의 SMAppService API 가 args 옵션 무시 + unsigned/Electron 앱에 대해 executableWillLaunchAtLogin 을 자주 false 로 반환 → 정상 등록 상태에서도 경고 떠 있음. AutostartDiagnostic 결과에 platform 필드 추가, willLaunch 신호는 win32 에서만 mismatch 판정에 사용. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
98 lines
3.7 KiB
TypeScript
98 lines
3.7 KiB
TypeScript
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
|
|
const { mockApp, mockExecFile } = vi.hoisted(() => ({
|
|
mockApp: { getLoginItemSettings: vi.fn() },
|
|
mockExecFile: vi.fn()
|
|
}));
|
|
|
|
vi.mock('electron', () => ({
|
|
default: { app: mockApp }
|
|
}));
|
|
|
|
vi.mock('node:child_process', () => ({
|
|
execFile: mockExecFile
|
|
}));
|
|
|
|
import { collectAutostartState } from '../../src/main/services/AutostartDiagnostic';
|
|
|
|
const ORIGINAL_PLATFORM = process.platform;
|
|
|
|
function setPlatform(p: NodeJS.Platform): void {
|
|
Object.defineProperty(process, 'platform', { value: p, configurable: true });
|
|
}
|
|
|
|
describe('AutostartDiagnostic — collectAutostartState', () => {
|
|
beforeEach(() => {
|
|
mockApp.getLoginItemSettings.mockReset();
|
|
mockExecFile.mockReset();
|
|
});
|
|
|
|
afterEach(() => {
|
|
setPlatform(ORIGINAL_PLATFORM);
|
|
});
|
|
|
|
it('returns withArgs / noArgs / execPath structure', async () => {
|
|
setPlatform('darwin');
|
|
mockApp.getLoginItemSettings
|
|
.mockReturnValueOnce({ openAtLogin: true, executableWillLaunchAtLogin: true })
|
|
.mockReturnValueOnce({ openAtLogin: false, executableWillLaunchAtLogin: true });
|
|
|
|
const state = await collectAutostartState();
|
|
|
|
expect(state.withArgs).toEqual({ openAtLogin: true, executableWillLaunchAtLogin: true });
|
|
expect(state.noArgs).toEqual({ openAtLogin: false, executableWillLaunchAtLogin: true });
|
|
expect(state.execPath).toBe(process.execPath);
|
|
expect(state.platform).toBe('darwin');
|
|
});
|
|
|
|
it('passes args=["--hidden"] for the first call, no args for the second', async () => {
|
|
setPlatform('darwin');
|
|
mockApp.getLoginItemSettings
|
|
.mockReturnValueOnce({ openAtLogin: true, executableWillLaunchAtLogin: true })
|
|
.mockReturnValueOnce({ openAtLogin: true, executableWillLaunchAtLogin: true });
|
|
|
|
await collectAutostartState();
|
|
|
|
expect(mockApp.getLoginItemSettings).toHaveBeenNthCalledWith(1, { args: ['--hidden'] });
|
|
expect(mockApp.getLoginItemSettings).toHaveBeenNthCalledWith(2);
|
|
});
|
|
|
|
it('non-win32: does not set registryPath/registryValue', async () => {
|
|
setPlatform('darwin');
|
|
mockApp.getLoginItemSettings.mockReturnValue({ openAtLogin: true, executableWillLaunchAtLogin: true });
|
|
|
|
const state = await collectAutostartState();
|
|
|
|
expect(state.registryPath).toBeUndefined();
|
|
expect(state.registryValue).toBeUndefined();
|
|
expect(mockExecFile).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it('Windows: returns registryPath + registryValue when reg.exe succeeds', async () => {
|
|
setPlatform('win32');
|
|
mockApp.getLoginItemSettings.mockReturnValue({ openAtLogin: true, executableWillLaunchAtLogin: true });
|
|
mockExecFile.mockImplementation((_cmd: string, _args: string[], cb: (err: Error | null, stdout: string, stderr: string) => void) => {
|
|
cb(null, '\r\nHKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\r\n Inkling REG_SZ "C:\\Users\\u\\Inkling.exe" --hidden\r\n', '');
|
|
});
|
|
|
|
const state = await collectAutostartState();
|
|
|
|
expect(state.registryPath).toBe('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Inkling');
|
|
expect(state.registryValue).toContain('Inkling.exe');
|
|
expect(state.registryValue).toContain('--hidden');
|
|
});
|
|
|
|
it('Windows: silent fallback on reg.exe error', async () => {
|
|
setPlatform('win32');
|
|
mockApp.getLoginItemSettings.mockReturnValue({ openAtLogin: true, executableWillLaunchAtLogin: true });
|
|
mockExecFile.mockImplementation((_cmd: string, _args: string[], cb: (err: Error | null, stdout: string, stderr: string) => void) => {
|
|
cb(new Error('not found'), '', '');
|
|
});
|
|
|
|
const state = await collectAutostartState();
|
|
|
|
expect(state.registryPath).toBe('HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Inkling');
|
|
expect(state.registryValue).toBeNull();
|
|
});
|
|
});
|