에디터 블록 패널 상태 분리
This commit is contained in:
154
tests/useAdminMarkdownBlockPanel.test.js
Normal file
154
tests/useAdminMarkdownBlockPanel.test.js
Normal file
@@ -0,0 +1,154 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import test from 'node:test'
|
||||
import { effectScope, nextTick, ref } from 'vue'
|
||||
import { useAdminMarkdownBlockPanel } from '../composables/useAdminMarkdownBlockPanel.js'
|
||||
|
||||
globalThis.window ??= {
|
||||
setTimeout,
|
||||
clearTimeout
|
||||
}
|
||||
|
||||
/**
|
||||
* 테스트용 블록 패널 상태를 만든다.
|
||||
* @param {Object} options - 테스트 옵션
|
||||
* @returns {Object} 테스트 상태
|
||||
*/
|
||||
const createBlockPanelState = (options = {}) => {
|
||||
const scope = effectScope()
|
||||
const activeMode = ref(options.activeMode ?? 'write')
|
||||
const value = ref(options.value ?? '')
|
||||
const writeModeContextValue = ref(null)
|
||||
const activeLogicalLineIndex = ref(options.activeLogicalLineIndex ?? 0)
|
||||
const isMediaPickerOpen = ref(false)
|
||||
const currentBlock = ref(options.block ?? {
|
||||
kind: 'image',
|
||||
startLine: 0,
|
||||
endLine: 0
|
||||
})
|
||||
const inlineContext = ref(null)
|
||||
const emitted = []
|
||||
let panel
|
||||
|
||||
scope.run(() => {
|
||||
panel = useAdminMarkdownBlockPanel({
|
||||
activeMode,
|
||||
value,
|
||||
writeModeContextValue,
|
||||
activeLogicalLineIndex,
|
||||
isMediaPickerOpen,
|
||||
resolveBlockContext: () => currentBlock.value,
|
||||
getInlineColorSelectionContext: () => inlineContext.value,
|
||||
emitBlockPanel: (payload) => {
|
||||
emitted.push(payload)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
return {
|
||||
activeLogicalLineIndex,
|
||||
currentBlock,
|
||||
emitted,
|
||||
inlineContext,
|
||||
isMediaPickerOpen,
|
||||
panel,
|
||||
stop: () => scope.stop()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 패널 watch와 내부 nextTick을 비운다.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const flushBlockPanelTicks = async () => {
|
||||
await nextTick()
|
||||
await nextTick()
|
||||
}
|
||||
|
||||
test('textarea 포커스가 있으면 활성 블록 패널을 연다', () => {
|
||||
const state = createBlockPanelState()
|
||||
|
||||
state.panel.handleTextareaFocusIn()
|
||||
state.panel.syncBlockPanelState()
|
||||
|
||||
assert.equal(state.panel.isBlockPanelVisible.value, true)
|
||||
assert.deepEqual(state.emitted.at(-1), {
|
||||
open: true,
|
||||
panel: {
|
||||
kind: 'image',
|
||||
startLine: 0,
|
||||
endLine: 0
|
||||
}
|
||||
})
|
||||
state.stop()
|
||||
})
|
||||
|
||||
test('인라인 색상 선택 컨텍스트는 일반 블록보다 우선 표시된다', () => {
|
||||
const state = createBlockPanelState()
|
||||
|
||||
state.inlineContext.value = {
|
||||
kind: 'inline-color',
|
||||
mode: 'source',
|
||||
start: 0,
|
||||
end: 2,
|
||||
text: '색상'
|
||||
}
|
||||
state.panel.syncInlineColorSelectionContext()
|
||||
state.panel.syncBlockPanelState()
|
||||
|
||||
assert.equal(state.panel.isBlockPanelEngaged.value, true)
|
||||
assert.equal(state.panel.activePanelContext.value.kind, 'inline-color')
|
||||
assert.deepEqual(state.emitted.at(-1).panel, state.inlineContext.value)
|
||||
state.stop()
|
||||
})
|
||||
|
||||
test('IME 조합 중 활성 블록이 잠시 비어도 직전 블록 패널을 유지한다', async () => {
|
||||
const state = createBlockPanelState()
|
||||
|
||||
state.panel.handleTextareaFocusIn()
|
||||
state.panel.handleTextareaCompositionStart()
|
||||
state.currentBlock.value = null
|
||||
state.activeLogicalLineIndex.value = 0
|
||||
await flushBlockPanelTicks()
|
||||
|
||||
assert.equal(state.panel.activePanelContext.value.kind, 'image')
|
||||
state.stop()
|
||||
})
|
||||
|
||||
test('라이브 줄 포커스는 해당 줄 블록 패널을 편집 중 상태로 연다', async () => {
|
||||
const state = createBlockPanelState({
|
||||
activeMode: 'preview',
|
||||
block: {
|
||||
kind: 'callout',
|
||||
startLine: 2,
|
||||
endLine: 4
|
||||
}
|
||||
})
|
||||
|
||||
await state.panel.handleLiveLineFocus(3)
|
||||
await flushBlockPanelTicks()
|
||||
|
||||
assert.equal(state.activeLogicalLineIndex.value, 3)
|
||||
assert.equal(state.panel.isBlockPanelEngaged.value, true)
|
||||
assert.equal(state.panel.activePanelContext.value.kind, 'callout')
|
||||
assert.equal(state.emitted.at(-1).open, true)
|
||||
state.stop()
|
||||
})
|
||||
|
||||
test('패널 닫기는 편집 상태와 인라인 색상 컨텍스트를 초기화한다', () => {
|
||||
const state = createBlockPanelState()
|
||||
|
||||
state.inlineContext.value = {
|
||||
kind: 'inline-color',
|
||||
mode: 'source',
|
||||
start: 0,
|
||||
end: 2,
|
||||
text: '색상'
|
||||
}
|
||||
state.panel.syncInlineColorSelectionContext()
|
||||
state.panel.closeBlockPanel()
|
||||
|
||||
assert.equal(state.panel.isBlockPanelEngaged.value, false)
|
||||
assert.equal(state.panel.inlineColorSelectionContext.value, null)
|
||||
assert.equal(state.emitted.at(-1).open, false)
|
||||
state.stop()
|
||||
})
|
||||
Reference in New Issue
Block a user