Files
BoosAPI/desktop/libs/stream-monaco/test/diffHunk.test.ts
T
boos e0a5f57793 feat(desktop): embed BoosAPI Desktop client as a subproject
Vendor the rebranded BoosAPI Desktop client (Tauri + Vue) into metapi as
a monorepo subdirectory under desktop/. Source only — node_modules,
dist, Cargo target and the upstream .git history are excluded.

desktop/ keeps its own independent Cargo workspace (desktop/src-tauri
with crates/*); it is not part of the backend boosapi crate, so a
`cargo check` at the metapi root still compiles only the backend. Build
the desktop app from desktop/src-tauri per desktop/README.md.

Note: app icons are still placeholder assets pending the final BoosAPI
logo. The updater signing keys live outside the repo and are not
included.
2026-06-22 11:32:57 +08:00

177 lines
4.6 KiB
TypeScript

import { describe, expect, it, vi } from 'vitest'
vi.mock('../src/monaco-shim', () => {
class Range {
constructor(
public startLineNumber: number,
public startColumn: number,
public endLineNumber: number,
public endColumn: number,
) {}
}
return {
default: {
Range,
editor: {
EditorOption: {
lineHeight: 'lineHeight',
},
},
},
Range,
editor: {
EditorOption: {
lineHeight: 'lineHeight',
},
},
}
})
import {
applyDefaultDiffHunkAction,
findLineChangeByHoverLine,
hasModifiedLines,
hasOriginalLines,
inferInlineDiffHunkHoverSide,
positionDiffHunkNode,
} from '../src/core/diffHunk'
function createModel(lines: string[]) {
const value = () => lines.join('\n')
return {
getLineCount() {
return lines.length
},
getLineMaxColumn(line: number) {
return (lines[line - 1] ?? '').length + 1
},
getValueInRange(range: any) {
const start = range.startLineNumber - 1
const end = range.endLineNumber - 1
const selected = lines.slice(start, Math.max(start, end))
if (range.endColumn !== 1 && end < lines.length)
selected.push(lines[end] ?? '')
return `${selected.join('\n')}${selected.length > 0 ? '\n' : ''}`
},
applyEdits: vi.fn(),
}
}
describe('diffHunk helpers', () => {
it('detects whether a hunk has original or modified lines', () => {
const insertion = {
originalStartLineNumber: 0,
originalEndLineNumber: 0,
modifiedStartLineNumber: 3,
modifiedEndLineNumber: 4,
} as any
expect(hasOriginalLines(insertion)).toBe(false)
expect(hasModifiedLines(insertion)).toBe(true)
})
it('finds the nearest hovered line change within tolerance', () => {
const changes = [
{
originalStartLineNumber: 2,
originalEndLineNumber: 3,
modifiedStartLineNumber: 2,
modifiedEndLineNumber: 3,
},
{
originalStartLineNumber: 10,
originalEndLineNumber: 10,
modifiedStartLineNumber: 12,
modifiedEndLineNumber: 12,
},
] as any
expect(findLineChangeByHoverLine(changes, 'modified', 3)).toBe(changes[0])
expect(findLineChangeByHoverLine(changes, 'modified', 14)).toBe(changes[1])
expect(findLineChangeByHoverLine(changes, 'modified', 20)).toBeNull()
})
it('infers inline hover side from DOM hint or hover line fallback', () => {
const change = {
originalStartLineNumber: 4,
originalEndLineNumber: 5,
modifiedStartLineNumber: 6,
modifiedEndLineNumber: 7,
} as any
const deletedTarget = {
closest(selector: string) {
return selector.includes('line-delete') ? {} : null
},
} as HTMLElement
const insertedTarget = {
closest(selector: string) {
return selector.includes('line-insert') ? {} : null
},
} as HTMLElement
expect(inferInlineDiffHunkHoverSide(change, 5, deletedTarget)).toBe('upper')
expect(inferInlineDiffHunkHoverSide(change, 7, insertedTarget)).toBe('lower')
expect(inferInlineDiffHunkHoverSide(change, 5, null)).toBe('upper')
expect(inferInlineDiffHunkHoverSide(change, 6, null)).toBe('lower')
})
it('applies the default lower-stage action by copying modified lines into original', () => {
const originalModel = createModel(['a', 'b'])
const modifiedModel = createModel(['a', 'b', 'c'])
const lineChange = {
originalStartLineNumber: 0,
originalEndLineNumber: 0,
modifiedStartLineNumber: 3,
modifiedEndLineNumber: 3,
} as any
applyDefaultDiffHunkAction({
action: 'stage',
side: 'lower',
lineChange,
originalModel: originalModel as any,
modifiedModel: modifiedModel as any,
})
expect(originalModel.applyEdits).toHaveBeenCalledTimes(1)
expect(originalModel.applyEdits.mock.calls[0][0][0].text).toBe('c\n')
})
it('positions a hunk node within the editor host', () => {
const node = {
offsetWidth: 120,
offsetHeight: 24,
style: {
transform: '',
display: '',
},
} as unknown as HTMLDivElement
const editor = {
getContainerDomNode() {
return {
offsetLeft: 10,
clientWidth: 400,
offsetTop: 20,
clientHeight: 200,
}
},
getTopForLineNumber(line: number) {
return line * 20
},
getScrollTop() {
return 20
},
getOption() {
return 20
},
} as any
positionDiffHunkNode(node, editor, 5)
expect(node.style.display).toBe('flex')
expect(node.style.transform).toContain('translate(')
})
})