116 lines
3.3 KiB
JavaScript
116 lines
3.3 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { nextTick, ref } from 'vue'
|
|
import { useContentMarkdownLiveSelection } from '../composables/useContentMarkdownLiveSelection.js'
|
|
|
|
/**
|
|
* 테스트용 라이브 선택 상태를 만든다.
|
|
* @param {Object} calls - 콜백 기록 객체
|
|
* @returns {{ content: import('vue').Ref<string>, state: Object }} 상태
|
|
*/
|
|
const createLiveSelectionState = (calls = {}) => {
|
|
const content = ref('첫 줄\n둘째 줄')
|
|
const state = useContentMarkdownLiveSelection({
|
|
content,
|
|
interactive: ref(true),
|
|
onLineFocus: (line) => {
|
|
calls.focus = line
|
|
},
|
|
onLineBlur: () => {
|
|
calls.blur = true
|
|
},
|
|
onContentReplace: (payload) => {
|
|
calls.replace = payload
|
|
},
|
|
provideBridge: false
|
|
})
|
|
|
|
return { content, state }
|
|
}
|
|
|
|
test('라이브 선택 상태는 자식 편집기 포커스 요청과 원문 모드 표시를 관리한다', () => {
|
|
const calls = {}
|
|
const { state } = createLiveSelectionState(calls)
|
|
|
|
state.onEditorFocusLine({ line: 3, position: 'end', offset: 2 })
|
|
|
|
assert.equal(state.pendingFocusLine.value, 3)
|
|
assert.equal(state.pendingFocusPosition.value, 'end')
|
|
assert.equal(state.pendingFocusOffset.value, 2)
|
|
|
|
state.onInlineRawMode({ sourceLine: 7, active: true })
|
|
assert.equal(state.rawEditingSourceLines.value.has(7), true)
|
|
|
|
state.onInlineRawMode({ sourceLine: 7, active: false })
|
|
assert.equal(state.rawEditingSourceLines.value.has(7), false)
|
|
|
|
state.emitEditorFocusedLine(5)
|
|
assert.equal(calls.focus, 5)
|
|
})
|
|
|
|
test('라이브 선택 상태는 본문 변경 후 예약된 포커스 값을 초기화한다', async () => {
|
|
const { content, state } = createLiveSelectionState()
|
|
|
|
state.onEditorFocusLine({ line: 1, position: 'start' })
|
|
content.value = '바뀐 줄'
|
|
await nextTick()
|
|
|
|
assert.equal(state.pendingFocusLine.value, null)
|
|
assert.equal(state.pendingFocusPosition.value, 'auto')
|
|
assert.equal(state.pendingFocusOffset.value, null)
|
|
})
|
|
|
|
test('라이브 줄 포커스와 블러 이벤트를 상위 콜백으로 전달한다', () => {
|
|
class FakeElement {
|
|
/**
|
|
* @param {number} line - 원본 줄 번호
|
|
*/
|
|
constructor(line) {
|
|
this.line = line
|
|
}
|
|
|
|
/**
|
|
* 가장 가까운 데이터 줄 요소를 반환한다.
|
|
* @returns {FakeElement} 자기 자신
|
|
*/
|
|
closest() {
|
|
return this
|
|
}
|
|
|
|
/**
|
|
* 속성 값을 반환한다.
|
|
* @param {string} name - 속성명
|
|
* @returns {string|null} 속성 값
|
|
*/
|
|
getAttribute(name) {
|
|
return name === 'data-source-line' ? String(this.line) : null
|
|
}
|
|
}
|
|
|
|
const previousElement = globalThis.Element
|
|
const previousNode = globalThis.Node
|
|
globalThis.Element = FakeElement
|
|
globalThis.Node = FakeElement
|
|
|
|
try {
|
|
const calls = {}
|
|
const { state } = createLiveSelectionState(calls)
|
|
const target = new FakeElement(4)
|
|
|
|
state.emitLiveLineFocus({ target })
|
|
assert.equal(calls.focus, 4)
|
|
|
|
state.rendererRootRef.value = {
|
|
contains: (node) => node === target
|
|
}
|
|
state.emitLiveLineBlur({ relatedTarget: target })
|
|
assert.equal(calls.blur, undefined)
|
|
|
|
state.emitLiveLineBlur({ relatedTarget: new FakeElement(9) })
|
|
assert.equal(calls.blur, true)
|
|
} finally {
|
|
globalThis.Element = previousElement
|
|
globalThis.Node = previousNode
|
|
}
|
|
})
|