-
Notifications
You must be signed in to change notification settings - Fork 519
Expand file tree
/
Copy pathmultiline-input.test.tsx
More file actions
163 lines (123 loc) · 5.08 KB
/
multiline-input.test.tsx
File metadata and controls
163 lines (123 loc) · 5.08 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
import { describe, test, expect } from 'bun:test'
/**
* Tests for tab character cursor rendering in MultilineInput component.
*
* The shouldHighlight logic determines whether to show a highlighted character
* or the cursor symbol (▍) at the cursor position.
*
* Additionally, tabs are expanded to spaces (TAB_WIDTH=4) for proper rendering,
* so the cursor appears at the correct visual position.
*/
describe('MultilineInput - tab character handling', () => {
const TAB_WIDTH = 4
/**
* Helper function that mimics the shouldHighlight logic from MultilineInput.
* This tests the core fix: tabs should NOT be highlighted (like newlines).
*/
function shouldHighlightChar(
showCursor: boolean,
isPlaceholder: boolean,
cursorPosition: number,
displayValue: string,
): boolean {
return (
showCursor &&
!isPlaceholder &&
cursorPosition < displayValue.length &&
displayValue[cursorPosition] !== '\n' &&
displayValue[cursorPosition] !== '\t' // This is the fix being tested
)
}
/**
* Calculate cursor position in expanded string (tabs -> spaces)
*/
function calculateRenderCursorPosition(
cursorPosition: number,
displayValue: string,
): number {
let renderPos = 0
for (let i = 0; i < cursorPosition && i < displayValue.length; i++) {
renderPos += displayValue[i] === '\t' ? TAB_WIDTH : 1
}
return renderPos
}
test('does NOT highlight when cursor is on a tab character', () => {
const value = 'hello\tworld'
const cursorPosition = 5 // Position of the tab
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
// Tab characters should not be highlighted (should show cursor symbol instead)
expect(shouldHighlight).toBe(false)
})
test('does NOT highlight when cursor is on a newline character', () => {
const value = 'line1\nline2'
const cursorPosition = 5 // Position of the newline
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
// Newlines should not be highlighted (existing behavior)
expect(shouldHighlight).toBe(false)
})
test('DOES highlight when cursor is on a regular character', () => {
const value = 'hello'
const cursorPosition = 1 // Position of 'e'
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
// Regular characters should be highlighted
expect(shouldHighlight).toBe(true)
})
test('does NOT highlight when not focused (showCursor=false)', () => {
const value = 'hello\tworld'
const cursorPosition = 5
const shouldHighlight = shouldHighlightChar(false, false, cursorPosition, value)
expect(shouldHighlight).toBe(false)
})
test('does NOT highlight when showing placeholder', () => {
const value = ''
const cursorPosition = 0
const shouldHighlight = shouldHighlightChar(true, true, cursorPosition, value)
expect(shouldHighlight).toBe(false)
})
test('does NOT highlight when cursor is at end of string', () => {
const value = 'hello'
const cursorPosition = 5 // Beyond last character
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
expect(shouldHighlight).toBe(false)
})
test('handles multiple tabs - does NOT highlight tab at position 2', () => {
const value = '\t\t\tindented'
const cursorPosition = 2 // Third tab
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
expect(shouldHighlight).toBe(false)
})
test('handles tab at end of string', () => {
const value = 'text\t'
const cursorPosition = 4 // Position of trailing tab
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
expect(shouldHighlight).toBe(false)
})
test('handles space character - DOES highlight (spaces are visible)', () => {
const value = 'hello world'
const cursorPosition = 5 // Position of space
const shouldHighlight = shouldHighlightChar(true, false, cursorPosition, value)
// Spaces should be highlighted (they are visible characters)
expect(shouldHighlight).toBe(true)
})
test('expands single tab to 4 spaces for rendering', () => {
const value = 'hello\tworld'
const cursorPosition = 6 // After the tab
const renderPos = calculateRenderCursorPosition(cursorPosition, value)
// Position 6 in original = position 9 in rendered (5 chars + 4-space tab)
expect(renderPos).toBe(9)
})
test('expands multiple tabs correctly', () => {
const value = '\t\t\ttest'
const cursorPosition = 3 // After 3 tabs
const renderPos = calculateRenderCursorPosition(cursorPosition, value)
// 3 tabs = 12 spaces
expect(renderPos).toBe(12)
})
test('mixed content with tabs calculates correct render position', () => {
const value = 'a\tb\tc'
const cursorPosition = 3 // After 'a', tab, 'b'
const renderPos = calculateRenderCursorPosition(cursorPosition, value)
// 'a' (1) + tab (4) + 'b' (1) = 6
expect(renderPos).toBe(6)
})
})