feat(v029): NoteCard 이동 메뉴 (status 4분기 dropdown)
Cut B Task 6 — 모든 view 공통 "이동 ▾" dropdown. - 기존 휴지통/삭제 버튼 위치에 dropdown 추가 (모든 mode 공통) - 현재 status 외 3개 목적지만 표시 (active 노트 → 완료/보관/휴지통) - 메뉴 항목 클릭 → MoveStatusModal(initialTarget) 열기 - onMoved → local 상태 갱신 + onUpdated + (status 변경 시) onDeleted (list 제거) - trash mode 의 영구 삭제/복구 버튼은 보존 (휴지통 단독 액션) - 사용되지 않게 된 handleDelete 제거 (deleteNote 는 capture path 만) - NoteCard 메뉴 단위 테스트 2건 (메뉴 표시 / 클릭 → modal → setStatus)
This commit is contained in:
@@ -1,11 +1,16 @@
|
||||
// @vitest-environment jsdom
|
||||
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
||||
import '@testing-library/jest-dom/vitest';
|
||||
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
|
||||
import { render, screen, fireEvent, cleanup, waitFor } from '@testing-library/react';
|
||||
import type { Note } from '@shared/types';
|
||||
|
||||
const { mockOpenMedia } = vi.hoisted(() => ({
|
||||
mockOpenMedia: vi.fn(async () => ({ ok: true }))
|
||||
const { mockOpenMedia, mockSetStatus, mockClassify } = vi.hoisted(() => ({
|
||||
mockOpenMedia: vi.fn(async () => ({ ok: true })),
|
||||
mockSetStatus: vi.fn(async () => ({ ok: true as const })),
|
||||
mockClassify: vi.fn(async () => ({
|
||||
recommended: 'archived' as const,
|
||||
rationale: 'stub'
|
||||
}))
|
||||
}));
|
||||
|
||||
vi.mock('../../src/renderer/inbox/api.js', () => ({
|
||||
@@ -17,7 +22,9 @@ vi.mock('../../src/renderer/inbox/api.js', () => ({
|
||||
updateAiFields: vi.fn(),
|
||||
setDueDate: vi.fn(),
|
||||
setIntent: vi.fn(),
|
||||
dismissIntent: vi.fn()
|
||||
dismissIntent: vi.fn(),
|
||||
setStatus: mockSetStatus,
|
||||
classifyStatus: mockClassify
|
||||
}
|
||||
}));
|
||||
|
||||
@@ -82,3 +89,35 @@ describe('NoteCard — image rendering', () => {
|
||||
expect(mockOpenMedia).toHaveBeenCalledWith('media/n1/img1.png');
|
||||
});
|
||||
});
|
||||
|
||||
describe('NoteCard — 이동 메뉴 (v0.2.9 Cut B Task 6)', () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
cleanup();
|
||||
});
|
||||
|
||||
it('이동 ▾ 클릭 → 현재 status 외 3개 목적지 메뉴 표시', () => {
|
||||
// baseNote.status = 'active' → 완료/보관/휴지통 만 표시
|
||||
render(<NoteCard note={baseNote} onUpdated={() => {}} mode="inbox" />);
|
||||
fireEvent.click(screen.getByRole('button', { name: '이동' }));
|
||||
expect(screen.getByRole('button', { name: '완료로 이동' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '보관로 이동' })).toBeInTheDocument();
|
||||
expect(screen.getByRole('button', { name: '휴지통로 이동' })).toBeInTheDocument();
|
||||
expect(screen.queryByRole('button', { name: '활성로 이동' })).toBeNull();
|
||||
});
|
||||
|
||||
it('메뉴 항목 클릭 → MoveStatusModal 열림 + 확정 시 setStatus 호출', async () => {
|
||||
const onUpdated = vi.fn();
|
||||
render(<NoteCard note={baseNote} onUpdated={onUpdated} mode="inbox" />);
|
||||
fireEvent.click(screen.getByRole('button', { name: '이동' }));
|
||||
fireEvent.click(screen.getByRole('button', { name: '완료로 이동' }));
|
||||
// Modal 의 dialog role 등장
|
||||
expect(screen.getByRole('dialog', { name: '이동' })).toBeInTheDocument();
|
||||
// Modal 내부의 "완료" 버튼 클릭 → setStatus
|
||||
fireEvent.click(screen.getByRole('button', { name: '완료' }));
|
||||
await waitFor(() => {
|
||||
expect(mockSetStatus).toHaveBeenCalledWith('n1', 'completed', null);
|
||||
expect(onUpdated).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user