219 lines
6.0 KiB
JavaScript
219 lines
6.0 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import { ref } from 'vue'
|
|
import {
|
|
LIVE_IMAGE_DRAG_MIME,
|
|
getContentBlockInsertBeforeLine,
|
|
toContentImageDragPayload,
|
|
useContentMarkdownImageDrag
|
|
} from '../composables/useContentMarkdownImageDrag.js'
|
|
|
|
/**
|
|
* 테스트용 드래그 이벤트를 만든다.
|
|
* @returns {Object} 드래그 이벤트 대역 객체
|
|
*/
|
|
const createDragEvent = () => {
|
|
const data = new Map()
|
|
|
|
return {
|
|
dataTransfer: {
|
|
dropEffect: '',
|
|
effectAllowed: '',
|
|
setData: (type, value) => data.set(type, value),
|
|
getData: (type) => data.get(type) || ''
|
|
},
|
|
target: null,
|
|
relatedTarget: null,
|
|
currentTarget: {
|
|
contains: () => false
|
|
},
|
|
defaultPrevented: false,
|
|
preventDefault() {
|
|
this.defaultPrevented = true
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* 테스트용 이미지 블록을 만든다.
|
|
* @param {Object} options - 블록 옵션
|
|
* @returns {Object} 이미지 블록
|
|
*/
|
|
const createImageBlock = (options) => ({
|
|
id: options.id,
|
|
type: 'image',
|
|
url: options.url,
|
|
caption: options.caption || '',
|
|
width: options.width,
|
|
useAlt: Boolean(options.useAlt),
|
|
legacyBracketLabel: Boolean(options.legacyBracketLabel),
|
|
meta: {
|
|
startLine: options.startLine
|
|
}
|
|
})
|
|
|
|
/**
|
|
* 테스트용 갤러리 블록을 만든다.
|
|
* @returns {Object} 갤러리 블록
|
|
*/
|
|
const createGalleryBlock = () => ({
|
|
id: 'gallery-a',
|
|
type: 'gallery',
|
|
images: [
|
|
{ url: '/a.jpg', caption: 'A' },
|
|
{ url: '/b.jpg', caption: 'B' },
|
|
{ url: '/c.jpg', caption: 'C' }
|
|
],
|
|
meta: {
|
|
startLine: 10,
|
|
endLine: 14
|
|
}
|
|
})
|
|
|
|
/**
|
|
* 테스트용 드래그 상태를 만든다.
|
|
* @param {Object} calls - 이벤트 기록 객체
|
|
* @returns {Object} 이미지 드래그 상태
|
|
*/
|
|
const createImageDragState = (calls = {}) => useContentMarkdownImageDrag({
|
|
interactive: ref(true),
|
|
tailInsertBeforeLine: ref(99),
|
|
onMergeImagesToGallery: (payload) => {
|
|
calls.merge = payload
|
|
},
|
|
onInsertImageToGallery: (payload) => {
|
|
calls.insert = payload
|
|
},
|
|
onExtractGalleryImage: (payload) => {
|
|
calls.extract = payload
|
|
},
|
|
onGalleryReorder: (payload) => {
|
|
calls.reorder = payload
|
|
}
|
|
})
|
|
|
|
test('라이브 이미지 드래그 payload는 단일 이미지 블록 데이터를 보존한다', () => {
|
|
const block = createImageBlock({
|
|
id: 'image-a',
|
|
url: '/uploads/a.jpg',
|
|
caption: '캡션',
|
|
width: 360,
|
|
useAlt: true,
|
|
legacyBracketLabel: true,
|
|
startLine: 3
|
|
})
|
|
|
|
assert.deepEqual(toContentImageDragPayload(block), {
|
|
url: '/uploads/a.jpg',
|
|
caption: '캡션',
|
|
width: 360,
|
|
useAlt: true,
|
|
legacyBracketLabel: true
|
|
})
|
|
assert.equal(getContentBlockInsertBeforeLine(block), 3)
|
|
assert.equal(getContentBlockInsertBeforeLine({}), null)
|
|
})
|
|
|
|
test('단일 이미지를 다른 단일 이미지에 드롭하면 갤러리 병합 이벤트를 보낸다', () => {
|
|
const calls = {}
|
|
const drag = createImageDragState(calls)
|
|
const source = createImageBlock({ id: 'image-a', url: '/a.jpg', startLine: 2 })
|
|
const target = createImageBlock({ id: 'image-b', url: '/b.jpg', startLine: 8 })
|
|
const event = createDragEvent()
|
|
|
|
drag.onImageBlockDragStart(event, source)
|
|
assert.equal(event.dataTransfer.effectAllowed, 'move')
|
|
assert.equal(JSON.parse(event.dataTransfer.getData(LIVE_IMAGE_DRAG_MIME)).sourceLine, 2)
|
|
|
|
drag.onImageBlockDragOver(event, target)
|
|
assert.equal(event.defaultPrevented, true)
|
|
assert.deepEqual(drag.imageBlockDropTarget.value, { blockId: 'image-b' })
|
|
|
|
drag.onImageBlockDrop(event, target)
|
|
|
|
assert.deepEqual(calls.merge, { sourceLine: 2, targetLine: 8 })
|
|
assert.equal(drag.liveImageDragState.value, null)
|
|
})
|
|
|
|
test('단일 이미지를 갤러리 이미지 위에 드롭하면 갤러리 내부 삽입 이벤트를 보낸다', () => {
|
|
const calls = {}
|
|
const drag = createImageDragState(calls)
|
|
const source = createImageBlock({ id: 'image-a', url: '/a.jpg', startLine: 2 })
|
|
const gallery = createGalleryBlock()
|
|
const event = createDragEvent()
|
|
|
|
drag.onImageBlockDragStart(event, source)
|
|
drag.onGalleryDragOverItem(event, gallery, 1)
|
|
drag.onGalleryDrop(event, gallery, 1)
|
|
|
|
assert.deepEqual(calls.insert, {
|
|
sourceLine: 2,
|
|
startLine: 10,
|
|
endLine: 14,
|
|
targetIndex: 2,
|
|
image: {
|
|
url: '/a.jpg',
|
|
caption: '',
|
|
width: undefined,
|
|
useAlt: false,
|
|
legacyBracketLabel: false
|
|
}
|
|
})
|
|
assert.equal(drag.liveImageDragState.value, null)
|
|
})
|
|
|
|
test('갤러리 이미지를 같은 갤러리 안에서 드롭하면 이미지 순서 변경 이벤트를 보낸다', () => {
|
|
const calls = {}
|
|
const drag = createImageDragState(calls)
|
|
const gallery = createGalleryBlock()
|
|
const event = createDragEvent()
|
|
|
|
drag.onGalleryDragStart(event, gallery, 0)
|
|
drag.onGalleryDragOverItem(event, gallery, 2)
|
|
drag.onGalleryDrop(event, gallery, 2)
|
|
|
|
assert.deepEqual(calls.reorder, {
|
|
startLine: 10,
|
|
endLine: 14,
|
|
images: [
|
|
{ url: '/b.jpg', caption: 'B' },
|
|
{ url: '/c.jpg', caption: 'C' },
|
|
{ url: '/a.jpg', caption: 'A' }
|
|
]
|
|
})
|
|
assert.equal(drag.liveImageDragState.value, null)
|
|
})
|
|
|
|
test('갤러리 이미지를 블록 사이와 문서 하단에 드롭하면 단일 이미지 분리 이벤트를 보낸다', () => {
|
|
const calls = {}
|
|
const drag = createImageDragState(calls)
|
|
const gallery = createGalleryBlock()
|
|
const insertTarget = { id: 'paragraph-a', meta: { startLine: 30 } }
|
|
const event = createDragEvent()
|
|
|
|
drag.onGalleryDragStart(event, gallery, 1)
|
|
drag.onBlockInsertDragOver(event, insertTarget)
|
|
assert.deepEqual(drag.blockInsertDropTarget.value, { insertBeforeLine: 30 })
|
|
|
|
drag.onBlockInsertDrop(event, insertTarget)
|
|
assert.deepEqual(calls.extract, {
|
|
startLine: 10,
|
|
endLine: 14,
|
|
imageIndex: 1,
|
|
insertBeforeLine: 30,
|
|
image: { url: '/b.jpg', caption: 'B' }
|
|
})
|
|
|
|
drag.onGalleryDragStart(event, gallery, 2)
|
|
drag.onTailInsertDragOver(event)
|
|
drag.onTailInsertDrop(event)
|
|
|
|
assert.deepEqual(calls.extract, {
|
|
startLine: 10,
|
|
endLine: 14,
|
|
imageIndex: 2,
|
|
insertBeforeLine: 99,
|
|
image: { url: '/c.jpg', caption: 'C' }
|
|
})
|
|
})
|