Files
sori.studio/tests/useAdminMarkdownPreviewFocus.test.js

145 lines
4.2 KiB
JavaScript

import assert from 'node:assert/strict'
import test from 'node:test'
import { ref } from 'vue'
import { useAdminMarkdownPreviewFocus } from '../composables/useAdminMarkdownPreviewFocus.js'
/**
* 테스트용 source line DOM 대역을 만든다.
* @param {Object} options - 줄 옵션
* @returns {Object} 줄 DOM 대역
*/
const createSourceLineStub = (options) => {
return {
line: options.line,
rect: options.rect,
closest: (selector) => selector === '[data-source-line]' ? options.closestResult ?? null : null,
getAttribute: (name) => name === 'data-source-line' ? String(options.line) : null,
getBoundingClientRect: () => options.rect
}
}
/**
* 테스트용 미리보기 표면 상태를 만든다.
* @param {Object} options - 테스트 옵션
* @returns {Object} 테스트 상태
*/
const createPreviewFocusState = (options = {}) => {
const calls = {
focusEditableAtLine: [],
selectAllLiveDocument: 0
}
const sourceLines = options.sourceLines ?? []
const surface = {
scrollTop: options.scrollTop ?? 80,
contains: (element) => options.containedElements?.includes(element) ?? false,
querySelectorAll: (selector) => selector === '[data-source-line]' ? sourceLines : [],
getBoundingClientRect: () => options.surfaceRect ?? {
top: 10,
bottom: 600,
height: 590
}
}
const previewSurfaceRef = ref({
getPreviewElement: () => surface,
getSourceLineElement: (sourceLine) => sourceLines.find((line) => line.line === sourceLine) ?? null,
focusEditableAtLine: (...args) => {
calls.focusEditableAtLine.push(args)
},
selectAllLiveDocument: () => {
calls.selectAllLiveDocument += 1
}
})
const focusState = useAdminMarkdownPreviewFocus({
previewSurfaceRef,
isClient: true,
getActiveElement: () => options.activeElement ?? null
})
return {
calls,
focusState,
previewSurfaceRef,
sourceLines,
surface
}
}
test('미리보기 표면 함수 호출을 표면 컴포넌트로 위임한다', () => {
const line = createSourceLineStub({
line: 3,
rect: { top: 40, bottom: 70, height: 30 }
})
const state = createPreviewFocusState({
sourceLines: [line]
})
assert.equal(state.focusState.getPreviewSurfaceElement(), state.surface)
assert.equal(state.focusState.getPreviewSourceLineElement(3), line)
state.focusState.focusPreviewEditableAtLine(3, 0, 'start')
state.focusState.selectAllPreviewDocument()
assert.deepEqual(state.calls.focusEditableAtLine, [[3, 0, 'start']])
assert.equal(state.calls.selectAllLiveDocument, 1)
})
test('미리보기 상단 스크롤을 0으로 되돌린다', () => {
const state = createPreviewFocusState()
state.focusState.scrollPreviewToTop()
assert.equal(state.surface.scrollTop, 0)
})
test('현재 포커스가 미리보기 줄 안에 있으면 해당 source line을 반환한다', () => {
const focusedLine = createSourceLineStub({
line: 7,
rect: { top: 240, bottom: 270, height: 30 }
})
const activeElement = {
closest: (selector) => selector === '[data-source-line]' ? focusedLine : null
}
const state = createPreviewFocusState({
activeElement,
containedElements: [activeElement],
sourceLines: [focusedLine]
})
assert.equal(state.focusState.getCurrentPreviewSourceLine(), 7)
})
test('포커스 줄이 없으면 화면 상단 기준으로 가까운 source line을 반환한다', () => {
const firstLine = createSourceLineStub({
line: 1,
rect: { top: 4, bottom: 20, height: 16 }
})
const secondLine = createSourceLineStub({
line: 2,
rect: { top: 40, bottom: 70, height: 30 }
})
const thirdLine = createSourceLineStub({
line: 3,
rect: { top: 120, bottom: 150, height: 30 }
})
const state = createPreviewFocusState({
sourceLines: [thirdLine, firstLine, secondLine],
surfaceRect: {
top: 10,
bottom: 500,
height: 490
}
})
assert.equal(state.focusState.getCurrentPreviewSourceLine(), 2)
})
test('클라이언트가 아니거나 표면이 없으면 현재 줄을 반환하지 않는다', () => {
const previewSurfaceRef = ref(null)
const focusState = useAdminMarkdownPreviewFocus({
previewSurfaceRef,
isClient: false
})
assert.equal(focusState.getCurrentPreviewSourceLine(), null)
})