두 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>
154 lines
6.1 KiB
TypeScript
154 lines
6.1 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
import '@testing-library/jest-dom/vitest';
|
|
import { render, screen, fireEvent, waitFor, cleanup } from '@testing-library/react';
|
|
|
|
function makeDiag(open: boolean, platform: NodeJS.Platform = 'win32'): {
|
|
withArgs: { openAtLogin: boolean; executableWillLaunchAtLogin: boolean };
|
|
noArgs: { openAtLogin: boolean; executableWillLaunchAtLogin: boolean };
|
|
execPath: string;
|
|
platform: NodeJS.Platform;
|
|
} {
|
|
return {
|
|
withArgs: { openAtLogin: open, executableWillLaunchAtLogin: open },
|
|
noArgs: { openAtLogin: open, executableWillLaunchAtLogin: open },
|
|
execPath: '/path/to/exe',
|
|
platform
|
|
};
|
|
}
|
|
|
|
vi.mock('../../src/renderer/inbox/api.js', () => ({
|
|
inboxApi: {
|
|
getAutostart: vi.fn(async () => ({ openAtLogin: true, diagnostic: makeDiag(true) })),
|
|
setAutostart: vi.fn(async (open: boolean) => ({ openAtLogin: open, diagnostic: makeDiag(open) }))
|
|
}
|
|
}));
|
|
|
|
import { AutostartSection } from '../../src/renderer/inbox/components/settings/AutostartSection';
|
|
|
|
describe('AutostartSection', () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
cleanup();
|
|
});
|
|
|
|
it('renders toggle reflecting current state', async () => {
|
|
render(<AutostartSection />);
|
|
const toggle = await screen.findByRole('checkbox');
|
|
expect(toggle).toBeChecked();
|
|
});
|
|
|
|
it('clicking toggle calls setAutostart', async () => {
|
|
const { inboxApi } = await import('../../src/renderer/inbox/api.js');
|
|
render(<AutostartSection />);
|
|
const toggle = await screen.findByRole('checkbox');
|
|
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',
|
|
platform: 'win32'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
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',
|
|
platform: 'win32',
|
|
registryPath: 'HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run\\Inkling',
|
|
registryValue: '"C:\\app.exe" --hidden'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
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',
|
|
platform: 'win32'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
await screen.findByRole('checkbox');
|
|
expect(screen.queryByText(/⚠️/)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('macOS: no false-positive mismatch when willLaunch=false (SMAppService 한계)', async () => {
|
|
const { inboxApi } = await import('../../src/renderer/inbox/api.js');
|
|
vi.mocked(inboxApi.getAutostart).mockResolvedValueOnce({
|
|
openAtLogin: true,
|
|
diagnostic: {
|
|
withArgs: { openAtLogin: true, executableWillLaunchAtLogin: false },
|
|
noArgs: { openAtLogin: true, executableWillLaunchAtLogin: false },
|
|
execPath: '/Applications/Inkling.app',
|
|
platform: 'darwin'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
await screen.findByRole('checkbox');
|
|
expect(screen.queryByText(/⚠️/)).not.toBeInTheDocument();
|
|
});
|
|
|
|
it('Win: mismatch warning when openAtLogin=true but willLaunch=false', async () => {
|
|
const { inboxApi } = await import('../../src/renderer/inbox/api.js');
|
|
vi.mocked(inboxApi.getAutostart).mockResolvedValueOnce({
|
|
openAtLogin: true,
|
|
diagnostic: {
|
|
withArgs: { openAtLogin: true, executableWillLaunchAtLogin: false },
|
|
noArgs: { openAtLogin: true, executableWillLaunchAtLogin: false },
|
|
execPath: 'C:\\app.exe',
|
|
platform: 'win32'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
await screen.findByRole('checkbox');
|
|
expect(await screen.findByText(/⚠️/)).toBeInTheDocument();
|
|
});
|
|
|
|
it('"재등록" button calls setAutostart with current openAtLogin value', 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',
|
|
platform: 'win32'
|
|
}
|
|
});
|
|
render(<AutostartSection />);
|
|
await screen.findByRole('checkbox');
|
|
fireEvent.click(screen.getByRole('button', { name: /재등록/ }));
|
|
await waitFor(() => expect(inboxApi.setAutostart).toHaveBeenCalledWith(true));
|
|
});
|
|
});
|