Skip to content

Commit 4e43f8e

Browse files
committed
test: add tests for touchToCell and terminalGrid
Export existing pure functions and lock down their behaviour before refactoring onTouchMove to reduce cognitive complexity.
1 parent 4e1d0a5 commit 4e43f8e

2 files changed

Lines changed: 105 additions & 3 deletions

File tree

src/gestures/scroll.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ function clamp(value: number, min: number, max: number): number {
2323
return Math.min(max, Math.max(min, value))
2424
}
2525

26-
function terminalGrid(screenRect: DOMRect, term: XTerminal): { cols: number; rows: number } {
26+
export function terminalGrid(screenRect: DOMRect, term: XTerminal): { cols: number; rows: number } {
2727
const colsFromTerm = term.cols
2828
const rowsFromTerm = term.rows
2929
if (typeof colsFromTerm === 'number' && typeof rowsFromTerm === 'number') {
@@ -45,7 +45,11 @@ function terminalGrid(screenRect: DOMRect, term: XTerminal): { cols: number; row
4545
return { cols: 80, rows: 24 }
4646
}
4747

48-
function touchToCell(touch: Touch, screen: HTMLElement, term: XTerminal): { x: number; y: number } {
48+
export function touchToCell(
49+
touch: Touch,
50+
screen: HTMLElement,
51+
term: XTerminal,
52+
): { x: number; y: number } {
4953
const rect = screen.getBoundingClientRect()
5054
const { cols, rows } = terminalGrid(rect, term)
5155
const width = Math.max(1, rect.width)

tests/gestures.test.ts

Lines changed: 99 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import { describe, expect, test } from 'vitest'
22
import { createGestureLock, resetLock, tryLock } from '../src/gestures/lock'
33
import { clampFontSize, touchDistance } from '../src/gestures/pinch'
4-
import { averageY, pageSeq, scrollSeq } from '../src/gestures/scroll'
4+
import { averageY, pageSeq, scrollSeq, terminalGrid, touchToCell } from '../src/gestures/scroll'
55
import { isValidSwipe } from '../src/gestures/swipe'
6+
import { mockTerminal } from './fixtures'
67

78
describe('isValidSwipe', () => {
89
const config = {
@@ -185,3 +186,100 @@ describe('pageSeq', () => {
185186
expect(source).toContain('\\x3c${code};${x};${y}M')
186187
})
187188
})
189+
190+
describe('terminalGrid', () => {
191+
test('returns cols/rows from terminal when available', () => {
192+
const term = { ...mockTerminal(), cols: 120, rows: 40 }
193+
const rect = { width: 800, height: 600 } as DOMRect
194+
expect(terminalGrid(rect, term)).toEqual({ cols: 120, rows: 40 })
195+
})
196+
197+
test('rounds non-integer cols/rows', () => {
198+
const term = { ...mockTerminal(), cols: 79.6, rows: 23.4 }
199+
const rect = { width: 800, height: 600 } as DOMRect
200+
expect(terminalGrid(rect, term)).toEqual({ cols: 80, rows: 23 })
201+
})
202+
203+
test('falls back to 80x24 when term has no cols/rows and no measure element', () => {
204+
const term = mockTerminal()
205+
const rect = { width: 800, height: 600 } as DOMRect
206+
expect(terminalGrid(rect, term)).toEqual({ cols: 80, rows: 24 })
207+
})
208+
209+
test('falls back to 80x24 when cols/rows are zero', () => {
210+
const term = { ...mockTerminal(), cols: 0, rows: 0 }
211+
const rect = { width: 800, height: 600 } as DOMRect
212+
expect(terminalGrid(rect, term)).toEqual({ cols: 80, rows: 24 })
213+
})
214+
215+
test('uses char measure element when term cols/rows unavailable', () => {
216+
const term = mockTerminal()
217+
const rect = { width: 800, height: 480 } as DOMRect
218+
const measure = document.createElement('span')
219+
measure.className = 'xterm-char-measure-element'
220+
measure.style.width = '10px'
221+
measure.style.height = '20px'
222+
document.body.appendChild(measure)
223+
224+
// happy-dom may not compute real layout, so this tests the fallback path
225+
const result = terminalGrid(rect, term)
226+
expect(result.cols).toBeGreaterThan(0)
227+
expect(result.rows).toBeGreaterThan(0)
228+
229+
document.body.removeChild(measure)
230+
})
231+
})
232+
233+
describe('touchToCell', () => {
234+
function makeScreen(width: number, height: number): HTMLElement {
235+
const el = document.createElement('div')
236+
Object.defineProperty(el, 'getBoundingClientRect', {
237+
value: () => ({
238+
left: 0,
239+
top: 0,
240+
width,
241+
height,
242+
right: width,
243+
bottom: height,
244+
x: 0,
245+
y: 0,
246+
toJSON() {},
247+
}),
248+
})
249+
return el
250+
}
251+
252+
function makeTouch(clientX: number, clientY: number): Touch {
253+
return { clientX, clientY } as Touch
254+
}
255+
256+
test('touch at top-left returns cell (1, 1)', () => {
257+
const screen = makeScreen(800, 480)
258+
const term = { ...mockTerminal(), cols: 80, rows: 24 }
259+
expect(touchToCell(makeTouch(0, 0), screen, term)).toEqual({ x: 1, y: 1 })
260+
})
261+
262+
test('touch at bottom-right returns cell (cols, rows)', () => {
263+
const screen = makeScreen(800, 480)
264+
const term = { ...mockTerminal(), cols: 80, rows: 24 }
265+
// Touch at the far edge — should map to last cell
266+
expect(touchToCell(makeTouch(799, 479), screen, term)).toEqual({ x: 80, y: 24 })
267+
})
268+
269+
test('touch at centre returns middle cell', () => {
270+
const screen = makeScreen(800, 480)
271+
const term = { ...mockTerminal(), cols: 80, rows: 24 }
272+
const cell = touchToCell(makeTouch(400, 240), screen, term)
273+
expect(cell.x).toBe(41)
274+
expect(cell.y).toBe(13)
275+
})
276+
277+
test('clamps touch outside screen bounds', () => {
278+
const screen = makeScreen(800, 480)
279+
const term = { ...mockTerminal(), cols: 80, rows: 24 }
280+
// Touch far below/right of screen
281+
expect(touchToCell(makeTouch(9999, 9999), screen, term)).toEqual({ x: 80, y: 24 })
282+
// Touch above/left of screen
283+
expect(touchToCell(makeTouch(-100, -100), screen, term)).toEqual({ x: 1, y: 1 })
284+
})
285+
})

0 commit comments

Comments
 (0)