diff --git a/src/renderer/inbox/components/settings/AutostartSection.tsx b/src/renderer/inbox/components/settings/AutostartSection.tsx index b7c9384..9e27e4e 100644 --- a/src/renderer/inbox/components/settings/AutostartSection.tsx +++ b/src/renderer/inbox/components/settings/AutostartSection.tsx @@ -4,6 +4,7 @@ import { inboxApi } from '../../api.js'; export function AutostartSection(): React.ReactElement { const [data, setData] = useState(null); + const [expanded, setExpanded] = useState(false); useEffect(() => { void (async () => { @@ -21,12 +22,58 @@ export function AutostartSection(): React.ReactElement { return
로딩 중...
; } + const d = data.diagnostic; + // v0.2.7 F12 deeper fix — withArgs vs noArgs 의 openAtLogin 불일치, 또는 + // executableWillLaunchAtLogin = false 면 mismatch 로 간주 (등록은 됐지만 실제론 + // 로그인 시 실행되지 않을 수 있는 상태). + const mismatch = d.withArgs.openAtLogin !== d.noArgs.openAtLogin + || (data.openAtLogin && !d.withArgs.executableWillLaunchAtLogin); + return (
+ {mismatch && ( +
+ ⚠️ 등록 상태 불일치 감지 — 진단 정보 확인 후 재등록을 시도하세요. +
+ )} + + {expanded && ( +
+
표준 (--hidden 인자): openAtLogin={String(d.withArgs.openAtLogin)}, willLaunch={String(d.withArgs.executableWillLaunchAtLogin)}
+
비교 (인자 없이): openAtLogin={String(d.noArgs.openAtLogin)}, willLaunch={String(d.noArgs.executableWillLaunchAtLogin)}
+
실행 파일 경로: {d.execPath}
+ {d.registryPath !== undefined &&
registry 경로: {d.registryPath}
} + {d.registryValue !== undefined &&
registry 값: {d.registryValue ?? '(없음)'}
} +
+ )}
); } diff --git a/tests/unit/AutostartSection.test.tsx b/tests/unit/AutostartSection.test.tsx index 78c2429..234143b 100644 --- a/tests/unit/AutostartSection.test.tsx +++ b/tests/unit/AutostartSection.test.tsx @@ -43,4 +43,57 @@ describe('AutostartSection', () => { fireEvent.click(toggle); await waitFor(() => expect(inboxApi.setAutostart).toHaveBeenCalledWith(false)); }); + + it('renders diagnostic panel when expanded, shows mismatch warning + execPath', async () => { + const { inboxApi } = await import('../../src/renderer/inbox/api.js'); + vi.mocked(inboxApi.getAutostart).mockResolvedValueOnce({ + openAtLogin: true, + diagnostic: { + withArgs: { openAtLogin: true, executableWillLaunchAtLogin: true }, + noArgs: { openAtLogin: false, executableWillLaunchAtLogin: true }, + execPath: '/path/to/Inkling.exe' + } + }); + render(); + await screen.findByRole('checkbox'); + fireEvent.click(screen.getByRole('button', { name: /진단 정보/ })); + expect(await screen.findByText(/⚠️/)).toBeInTheDocument(); + expect(screen.getByText(/path\/to\/Inkling\.exe/)).toBeInTheDocument(); + expect(screen.getByText(/표준 \(--hidden 인자\)/)).toBeInTheDocument(); + expect(screen.getByText(/비교 \(인자 없이\)/)).toBeInTheDocument(); + }); + + it('shows registry info when present (Win)', async () => { + const { inboxApi } = await import('../../src/renderer/inbox/api.js'); + vi.mocked(inboxApi.getAutostart).mockResolvedValueOnce({ + openAtLogin: true, + diagnostic: { + withArgs: { openAtLogin: true, executableWillLaunchAtLogin: true }, + noArgs: { openAtLogin: true, executableWillLaunchAtLogin: true }, + execPath: 'C:\\app.exe', + registryPath: 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Inkling', + registryValue: '"C:\\app.exe" --hidden' + } + }); + render(); + await screen.findByRole('checkbox'); + fireEvent.click(screen.getByRole('button', { name: /진단 정보/ })); + expect(screen.getByText(/registry 경로/)).toBeInTheDocument(); + expect(screen.getByText(/registry 값/)).toBeInTheDocument(); + }); + + it('no mismatch warning when withArgs == noArgs and willLaunch=true', async () => { + const { inboxApi } = await import('../../src/renderer/inbox/api.js'); + vi.mocked(inboxApi.getAutostart).mockResolvedValueOnce({ + openAtLogin: true, + diagnostic: { + withArgs: { openAtLogin: true, executableWillLaunchAtLogin: true }, + noArgs: { openAtLogin: true, executableWillLaunchAtLogin: true }, + execPath: '/p' + } + }); + render(); + await screen.findByRole('checkbox'); + expect(screen.queryByText(/⚠️/)).not.toBeInTheDocument(); + }); });