v0.3.4 까지 누적된 dogfood UX 결함 hotfix. 사용자 직접 보고 3건 (inbox 재진입, 회고 탈출, 이동 modal 중복) + 동반 갭 4건 (count stale, 필터 잔류, 초기 로드 불일치, 배너 컨텍스트 누수). 데이터/마이그레이션 변경 없음 (스키마 v8). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
94 lines
4.1 KiB
TypeScript
94 lines
4.1 KiB
TypeScript
// @vitest-environment jsdom
|
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
import '@testing-library/jest-dom/vitest';
|
|
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
|
|
|
|
// inboxApi 는 window.inkling.inbox 를 참조하므로 jsdom 환경에서 import 자체가 throw.
|
|
// SettingsPage 가 마운트하는 AiProviderSection 의 useEffect 가 loadOllamaSettings 를 호출하므로
|
|
// 빈 객체 대신 필요한 메서드를 stub 한다.
|
|
vi.mock('../../src/renderer/inbox/api.js', () => ({
|
|
inboxApi: {
|
|
// setShowSettings(false) → setView('inbox') → loadByView('inbox') 가 listByStatus 호출.
|
|
listByStatus: vi.fn(async () => []),
|
|
loadOllamaSettings: vi.fn(async () => null),
|
|
saveOllamaSettings: vi.fn(async () => ({ ok: true })),
|
|
ollamaRecheck: vi.fn(async () => ({ ok: true })),
|
|
getAutostart: vi.fn(async () => ({
|
|
openAtLogin: false,
|
|
diagnostic: {
|
|
withArgs: { openAtLogin: false, executableWillLaunchAtLogin: false },
|
|
noArgs: { openAtLogin: false, executableWillLaunchAtLogin: false },
|
|
execPath: '/p'
|
|
}
|
|
})),
|
|
setAutostart: vi.fn(async (open: boolean) => ({
|
|
openAtLogin: open,
|
|
diagnostic: {
|
|
withArgs: { openAtLogin: open, executableWillLaunchAtLogin: open },
|
|
noArgs: { openAtLogin: open, executableWillLaunchAtLogin: open },
|
|
execPath: '/p'
|
|
}
|
|
})),
|
|
runBackup: vi.fn(async () => ({ ok: true })),
|
|
runExport: vi.fn(async () => ({ ok: true })),
|
|
runImport: vi.fn(async () => ({ ok: true })),
|
|
runSync: vi.fn(async () => ({ ok: true })),
|
|
runExportTelemetry: vi.fn(async () => ({ ok: true })),
|
|
getAppInfo: vi.fn(async () => ({
|
|
version: '0.2.7',
|
|
electron: '41.3.0',
|
|
node: '22.x',
|
|
os: 'darwin 23.6.0',
|
|
profileDir: '/tmp/Inkling'
|
|
})),
|
|
openProfileDir: vi.fn(async () => undefined),
|
|
copyAppInfo: vi.fn(async () => undefined),
|
|
// v0.2.9 Cut B Task 15-16 — AiProviderSection 의 토글 + disabled 메모 prompt.
|
|
getSettings: vi.fn(async () => ({ ai_enabled: true, onboarding_completed: true })),
|
|
setAiEnabled: vi.fn(async () => ({ ok: true as const })),
|
|
setOnboardingCompleted: vi.fn(async () => ({ ok: true as const })),
|
|
getDisabledCount: vi.fn(async () => 0),
|
|
enqueueDisabled: vi.fn(async () => ({ count: 0 })),
|
|
// v0.3.0 Cut E — SyncSection 이 SettingsPage 에 마운트되어 호출.
|
|
getSyncStatus: vi.fn(async () => ({ lastAt: null, lastResult: null, nextAt: null })),
|
|
setSyncAutoEnabled: vi.fn(async () => ({ ok: true as const })),
|
|
setSyncIntervalMin: vi.fn(async () => ({ ok: true as const })),
|
|
configureSync: vi.fn(async () => ({ ok: true as const })),
|
|
testSyncConnection: vi.fn(async () => ({ ok: true as const })),
|
|
// v0.3.1 Cut F — VisionSection 이 AiProviderSection 에 마운트되어 호출.
|
|
getVisionModels: vi.fn(async () => ({ models: [], at: null, selected: null })),
|
|
setVisionModel: vi.fn(async () => ({ ok: true as const })),
|
|
refreshVisionCache: vi.fn(async () => ({ ok: true as const, models: [] }))
|
|
}
|
|
}));
|
|
|
|
import { SettingsPage } from '../../src/renderer/inbox/components/SettingsPage';
|
|
import { useInbox } from '../../src/renderer/inbox/store';
|
|
|
|
describe('SettingsPage', () => {
|
|
beforeEach(() => {
|
|
cleanup();
|
|
useInbox.setState({ showSettings: true });
|
|
});
|
|
|
|
it('renders header with "← 돌아가기" button', () => {
|
|
render(<SettingsPage />);
|
|
expect(screen.getByRole('button', { name: /돌아가기/ })).toBeInTheDocument();
|
|
});
|
|
|
|
it('renders 5 section headings', () => {
|
|
render(<SettingsPage />);
|
|
expect(screen.getByText('AI 제공자')).toBeInTheDocument();
|
|
expect(screen.getByText('자동 실행')).toBeInTheDocument();
|
|
expect(screen.getByText('백업 / 복원')).toBeInTheDocument();
|
|
expect(screen.getByText('정보')).toBeInTheDocument();
|
|
expect(screen.getByText('동기화')).toBeInTheDocument();
|
|
});
|
|
|
|
it('clicking "← 돌아가기" sets showSettings to false', () => {
|
|
render(<SettingsPage />);
|
|
fireEvent.click(screen.getByRole('button', { name: /돌아가기/ }));
|
|
expect(useInbox.getState().showSettings).toBe(false);
|
|
});
|
|
});
|