import assert from 'node:assert/strict' import test from 'node:test' import { nextTick, ref } from 'vue' import { useAdminMarkdownEditorFocusActions } from '../composables/useAdminMarkdownEditorFocusActions.js' /** * 테스트용 에디터 포커스 액션 상태를 만든다. * @param {Object} [options] - 테스트 옵션 * @returns {Object} 테스트 상태 */ const createEditorFocusActionsState = (options = {}) => { const activeMode = ref(options.activeMode ?? 'write') const value = ref(options.value ?? '첫 줄\n둘째 줄') const activeLogicalLineIndex = ref(options.activeLogicalLineIndex ?? 0) const calls = { focusPreview: [], focusTextareaAtLine: [], refreshCaret: 0, scrollPreviewToTop: 0, setTextareaSelection: [] } const textarea = options.textarea ?? { focused: false, scrollTop: 48, selection: null, focus() { this.focused = true }, setSelectionRange(start, end) { this.selection = { start, end } } } const actions = useAdminMarkdownEditorFocusActions({ activeMode, value, activeLogicalLineIndex, getWriteTextareaElement: () => textarea, getLineIndexAtOffset: (offset) => String(value.value).slice(0, offset).split('\n').length - 1, getLineStartOffset: (lineIndex) => { const lines = String(value.value).split('\n') return lines.slice(0, lineIndex).join('\n').length + (lineIndex > 0 ? 1 : 0) }, setTextareaSelection: (start, end, selectionOptions) => { calls.setTextareaSelection.push({ start, end, options: selectionOptions }) }, focusTextareaAtLine: (lineIndex) => calls.focusTextareaAtLine.push(lineIndex), refreshCaretLogicalLine: () => { calls.refreshCaret += 1 }, scrollPreviewToTop: () => { calls.scrollPreviewToTop += 1 }, focusPreviewEditableAtLine: (...args) => calls.focusPreview.push(args) }) return { actions, activeLogicalLineIndex, activeMode, calls, textarea, value } } test('관리자 Markdown 첫 포커스 줄은 첫 줄 제목 다음 줄을 선택한다', () => { const state = createEditorFocusActionsState({ value: '# 제목' }) assert.equal(state.actions.getInitialContentFocusLineIndex(), 1) assert.equal(state.actions.ensureContentFocusLineExists(1), 1) assert.equal(state.value.value, '# 제목\n') }) test('관리자 Markdown 첫 블록 포커스는 작성 모드 textarea를 문서 상단으로 맞춘다', async () => { const state = createEditorFocusActionsState({ value: '# 제목', activeMode: 'write' }) state.actions.focusFirstBlock() await nextTick() assert.equal(state.value.value, '# 제목\n') assert.deepEqual(state.textarea.selection, { start: 5, end: 5 }) assert.equal(state.textarea.scrollTop, 0) assert.equal(state.textarea.focused, true) assert.equal(state.activeLogicalLineIndex.value, 1) assert.equal(state.calls.refreshCaret, 1) }) test('관리자 Markdown 첫 블록 포커스는 라이브 모드에서 상단 이동 후 편집 줄을 선택한다', async () => { const state = createEditorFocusActionsState({ value: '# 제목\n본문', activeMode: 'preview' }) state.actions.focusFirstBlock() await nextTick() await nextTick() assert.equal(state.calls.scrollPreviewToTop, 1) assert.deepEqual(state.calls.focusPreview, [[1, 0, 'start']]) }) test('관리자 Markdown 히스토리 복원 포커스는 작성 모드 선택 범위를 보존 스크롤로 복원한다', () => { const state = createEditorFocusActionsState({ activeMode: 'write' }) state.actions.restoreEditorFocusAfterHistory({ start: 3, end: 5 }) assert.deepEqual(state.calls.setTextareaSelection, [{ start: 3, end: 5, options: { preserveScroll: true } }]) assert.deepEqual(state.calls.focusTextareaAtLine, []) }) test('관리자 Markdown 히스토리 복원 포커스는 라이브 모드 줄과 오프셋을 복원한다', async () => { const state = createEditorFocusActionsState({ value: '첫 줄\n둘째 줄', activeMode: 'preview' }) state.actions.restoreEditorFocusAfterHistory({ start: 6, end: 6 }) await nextTick() assert.deepEqual(state.calls.focusPreview, [[1, 0, 'auto', 2, 'center']]) }) test('관리자 Markdown 히스토리 복원 선택이 없으면 현재 논리 줄로 작성 포커스를 보낸다', () => { const state = createEditorFocusActionsState({ activeMode: 'write', activeLogicalLineIndex: 2 }) state.actions.restoreEditorFocusAfterHistory() assert.deepEqual(state.calls.focusTextareaAtLine, [2]) })