chore(release): v0.3.6 — 이동 modal 복원 (v0.3.5 의도 정정)
v0.3.5 의 이동 dropdown 단순화가 사용자 의도와 어긋남. 사용자는 dropdown 의 목적지 중복 (modal 도 목적지 묻기) 만 거슬렸지, 사유 입력 + AI 자동 분류 + 수동 status 선택을 한 곳에서 처리하는 modal 은 보존해야 하는 핵심 UX 였음. 단일 "이동" 버튼 → MoveStatusModal path 로 정정. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
98
tests/unit/MoveStatusModal.test.tsx
Normal file
98
tests/unit/MoveStatusModal.test.tsx
Normal file
@@ -0,0 +1,98 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import { render, screen, fireEvent, cleanup, waitFor } from '@testing-library/react';
|
||||
|
||||
const { mockSetStatus, mockClassify } = vi.hoisted(() => ({
|
||||
mockSetStatus: vi.fn(async () => ({ ok: true as const })),
|
||||
mockClassify: vi.fn(async () => ({
|
||||
recommended: 'completed' as const,
|
||||
rationale: '결재 끝'
|
||||
}))
|
||||
}));
|
||||
|
||||
vi.mock('../../src/renderer/inbox/api.js', () => ({
|
||||
inboxApi: {
|
||||
setStatus: mockSetStatus,
|
||||
classifyStatus: mockClassify
|
||||
}
|
||||
}));
|
||||
|
||||
import { MoveStatusModal } from '../../src/renderer/inbox/components/MoveStatusModal';
|
||||
|
||||
describe('MoveStatusModal', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('renders reason textarea + 4 buttons + AI classify button', () => {
|
||||
render(
|
||||
<MoveStatusModal
|
||||
noteId="n1"
|
||||
rawText="t"
|
||||
summary=""
|
||||
onClose={vi.fn()}
|
||||
onMoved={vi.fn()}
|
||||
/>
|
||||
);
|
||||
expect(screen.getByRole('textbox')).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '완료' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '보관' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '휴지통' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: /AI 자동 분류/ })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('clicking 완료 calls setStatus with reason', async () => {
|
||||
const onMoved = vi.fn();
|
||||
render(
|
||||
<MoveStatusModal
|
||||
noteId="n1"
|
||||
rawText="t"
|
||||
summary=""
|
||||
onClose={vi.fn()}
|
||||
onMoved={onMoved}
|
||||
/>
|
||||
);
|
||||
fireEvent.change(screen.getByRole('textbox'), { target: { value: '결재 끝' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: '완료' }));
|
||||
await waitFor(() => {
|
||||
expect(mockSetStatus).toHaveBeenCalledWith('n1', 'completed', '결재 끝');
|
||||
expect(onMoved).toHaveBeenCalledWith('completed', '결재 끝');
|
||||
});
|
||||
});
|
||||
|
||||
it('AI 자동 분류 → recommendation 표시 + 확정 → setStatus', async () => {
|
||||
const onMoved = vi.fn();
|
||||
render(
|
||||
<MoveStatusModal
|
||||
noteId="n1"
|
||||
rawText="t"
|
||||
summary=""
|
||||
onClose={vi.fn()}
|
||||
onMoved={onMoved}
|
||||
/>
|
||||
);
|
||||
fireEvent.change(screen.getByRole('textbox'), { target: { value: '결재 끝' } });
|
||||
fireEvent.click(screen.getByRole('button', { name: /AI 자동 분류/ }));
|
||||
await screen.findByText(/AI 추천/);
|
||||
expect(screen.getByText(/이유: 결재 끝/)).toBeInTheDocument();
|
||||
fireEvent.click(screen.getByRole('button', { name: /확정/ }));
|
||||
await waitFor(() => expect(onMoved).toHaveBeenCalledWith('completed', '결재 끝'));
|
||||
});
|
||||
|
||||
it('빈 사유 → null reason 전달', async () => {
|
||||
const onMoved = vi.fn();
|
||||
render(
|
||||
<MoveStatusModal
|
||||
noteId="n1"
|
||||
rawText="t"
|
||||
summary=""
|
||||
onClose={vi.fn()}
|
||||
onMoved={onMoved}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(screen.getByRole('button', { name: '보관' }));
|
||||
await waitFor(() => expect(mockSetStatus).toHaveBeenCalledWith('n1', 'archived', null));
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user