163 lines
5.5 KiB
JavaScript
163 lines
5.5 KiB
JavaScript
import assert from 'node:assert/strict'
|
|
import test from 'node:test'
|
|
import {
|
|
addSlashSuppressedLine,
|
|
clampSlashHighlightedIndex,
|
|
getMediaPickerKindFromSlashAction,
|
|
getNextSlashHighlightedIndex,
|
|
getSlashCommandFocusTarget,
|
|
getSlashCommandTextareaSelection,
|
|
getSlashMenuKeyboardAction,
|
|
insertMarkdownLinesAtSlashTarget,
|
|
isMediaSlashAction,
|
|
parseSlashInput,
|
|
removeSlashSuppressedLine,
|
|
resolveSlashCommand,
|
|
shouldIgnorePendingMediaSlashCommit
|
|
} from '../lib/markdown-slash-commands.js'
|
|
|
|
test('슬래시 입력은 단일 줄 명령만 파싱한다', () => {
|
|
assert.deepEqual(parseSlashInput('/image'), {
|
|
query: 'image',
|
|
raw: '/image'
|
|
})
|
|
assert.equal(parseSlashInput(' /image'), null)
|
|
assert.equal(parseSlashInput('/image\n다음 줄'), null)
|
|
})
|
|
|
|
test('정확한 슬래시 명령과 미디어 액션을 판별한다', () => {
|
|
assert.equal(resolveSlashCommand('image')?.action, 'media-image')
|
|
assert.equal(resolveSlashCommand('img')?.id, 'image')
|
|
assert.equal(isMediaSlashAction('media-image'), true)
|
|
assert.equal(isMediaSlashAction('lines'), false)
|
|
assert.equal(getMediaPickerKindFromSlashAction('media-image'), 'image')
|
|
assert.equal(getMediaPickerKindFromSlashAction('media-gallery'), 'gallery')
|
|
assert.equal(getMediaPickerKindFromSlashAction('lines'), '')
|
|
})
|
|
|
|
test('미디어 슬래시 명령 지연 commit은 같은 줄 slash 원문일 때만 무시한다', () => {
|
|
assert.equal(shouldIgnorePendingMediaSlashCommit({
|
|
pendingInsertLine: 3,
|
|
startLine: 3,
|
|
replacementLines: ['/image']
|
|
}), true)
|
|
assert.equal(shouldIgnorePendingMediaSlashCommit({
|
|
pendingInsertLine: 3,
|
|
startLine: 4,
|
|
replacementLines: ['/image']
|
|
}), false)
|
|
assert.equal(shouldIgnorePendingMediaSlashCommit({
|
|
pendingInsertLine: 3,
|
|
startLine: 3,
|
|
replacementLines: ['본문']
|
|
}), false)
|
|
})
|
|
|
|
test('슬래시 제외 줄 Set은 기존 값을 보존한 새 Set으로 갱신한다', () => {
|
|
const source = new Set([1, 2])
|
|
const added = addSlashSuppressedLine(source, 3)
|
|
const removed = removeSlashSuppressedLine(added, 2)
|
|
|
|
assert.deepEqual([...source], [1, 2])
|
|
assert.deepEqual([...added], [1, 2, 3])
|
|
assert.deepEqual([...removed], [1, 3])
|
|
assert.notEqual(added, source)
|
|
assert.notEqual(removed, added)
|
|
})
|
|
|
|
test('슬래시 제외 줄 Set은 유효하지 않은 줄 번호를 무시한다', () => {
|
|
assert.deepEqual([...addSlashSuppressedLine(new Set([1]), Number.NaN)], [1])
|
|
assert.deepEqual([...removeSlashSuppressedLine(new Set([1]), Number.NaN)], [1])
|
|
})
|
|
|
|
test('슬래시 메뉴 하이라이트 인덱스는 명령 목록 범위 안으로 보정한다', () => {
|
|
assert.equal(clampSlashHighlightedIndex(3, 5), 3)
|
|
assert.equal(clampSlashHighlightedIndex(7, 5), 4)
|
|
assert.equal(clampSlashHighlightedIndex(-2, 5), 0)
|
|
assert.equal(clampSlashHighlightedIndex(2, 0), 0)
|
|
assert.equal(clampSlashHighlightedIndex(Number.NaN, Number.NaN), 0)
|
|
})
|
|
|
|
test('슬래시 메뉴 하이라이트 인덱스는 방향키로 순환한다', () => {
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 1, commandCount: 3, key: 'ArrowDown' }), 2)
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 2, commandCount: 3, key: 'ArrowDown' }), 0)
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 0, commandCount: 3, key: 'ArrowUp' }), 2)
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 8, commandCount: 3, key: 'ArrowUp' }), 1)
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 1, commandCount: 0, key: 'ArrowDown' }), 0)
|
|
assert.equal(getNextSlashHighlightedIndex({ currentIndex: 1, commandCount: 3, key: 'Enter' }), 1)
|
|
})
|
|
|
|
test('슬래시 메뉴 키보드 입력은 메뉴 동작으로 분류한다', () => {
|
|
assert.equal(getSlashMenuKeyboardAction('ArrowDown'), 'navigate')
|
|
assert.equal(getSlashMenuKeyboardAction('ArrowUp'), 'navigate')
|
|
assert.equal(getSlashMenuKeyboardAction('Enter'), 'apply')
|
|
assert.equal(getSlashMenuKeyboardAction('Escape'), 'cancel')
|
|
assert.equal(getSlashMenuKeyboardAction('Tab'), '')
|
|
})
|
|
|
|
test('슬래시 명령 줄에 미디어를 삽입할 때 원문 줄을 교체한다', () => {
|
|
const markdown = [
|
|
'첫 줄',
|
|
'/image',
|
|
'마지막 줄'
|
|
].join('\n')
|
|
|
|
assert.equal(insertMarkdownLinesAtSlashTarget(markdown, 1, ['']), [
|
|
'첫 줄',
|
|
'',
|
|
'마지막 줄'
|
|
].join('\n'))
|
|
})
|
|
|
|
test('일반 줄에는 지정 위치 앞에 마크다운 줄을 삽입한다', () => {
|
|
assert.equal(insertMarkdownLinesAtSlashTarget('첫 줄\n마지막 줄', 1, ['중간 줄']), '첫 줄\n중간 줄\n마지막 줄')
|
|
})
|
|
|
|
test('슬래시 명령 포커스 대상은 단일 줄과 블록 삽입을 구분한다', () => {
|
|
assert.deepEqual(getSlashCommandFocusTarget(2, ['## ']), {
|
|
line: 2,
|
|
offset: 3
|
|
})
|
|
assert.deepEqual(getSlashCommandFocusTarget(2, ['```', '', '```']), {
|
|
line: 3,
|
|
offset: 0
|
|
})
|
|
})
|
|
|
|
test('슬래시 명령 textarea 선택 위치는 줄 시작과 포커스 오프셋을 합산한다', () => {
|
|
const markdown = [
|
|
'첫 줄',
|
|
'둘째 줄',
|
|
'## ',
|
|
'마지막 줄'
|
|
].join('\n')
|
|
|
|
assert.deepEqual(getSlashCommandTextareaSelection({
|
|
markdown,
|
|
startLine: 2,
|
|
lines: ['## ']
|
|
}), {
|
|
start: 12,
|
|
end: 12
|
|
})
|
|
})
|
|
|
|
test('슬래시 명령 textarea 선택 위치는 여러 줄 블록의 내부 빈 줄을 가리킨다', () => {
|
|
const markdown = [
|
|
'첫 줄',
|
|
'```',
|
|
'',
|
|
'```',
|
|
'마지막 줄'
|
|
].join('\n')
|
|
|
|
assert.deepEqual(getSlashCommandTextareaSelection({
|
|
markdown,
|
|
startLine: 1,
|
|
lines: ['```', '', '```']
|
|
}), {
|
|
start: 8,
|
|
end: 8
|
|
})
|
|
})
|