fix(cli): enable typechecking for ui/components tests (#11419)

Co-authored-by: Jacob MacDonald <jakemac@google.com>
This commit is contained in:
Sandy Tao
2025-10-17 16:16:12 -07:00
committed by GitHub
parent f4330c9f5e
commit cedf0235a1
12 changed files with 377 additions and 239 deletions

View File

@@ -12,6 +12,7 @@ import type {
TextBuffer,
TextBufferState,
TextBufferAction,
VisualLayout,
} from './text-buffer.js';
import {
useTextBuffer,
@@ -24,6 +25,12 @@ import {
} from './text-buffer.js';
import { cpLen } from '../../utils/textUtils.js';
const defaultVisualLayout: VisualLayout = {
visualLines: [''],
logicalToVisualMap: [[[0, 0]]],
visualToLogicalMap: [[0, 0]],
};
const initialState: TextBufferState = {
lines: [''],
cursorRow: 0,
@@ -33,6 +40,9 @@ const initialState: TextBufferState = {
redoStack: [],
clipboard: null,
selectionAnchor: null,
viewportWidth: 80,
viewportHeight: 24,
visualLayout: defaultVisualLayout,
};
describe('textBufferReducer', () => {
@@ -1700,28 +1710,40 @@ describe('logicalPosToOffset', () => {
});
});
// Helper to create state for reducer tests
const createTestState = (
lines: string[],
cursorRow: number,
cursorCol: number,
viewportWidth = 80,
): TextBufferState => {
const text = lines.join('\n');
let state = textBufferReducer(initialState, {
type: 'set_text',
payload: text,
});
state = textBufferReducer(state, {
type: 'set_cursor',
payload: { cursorRow, cursorCol, preferredCol: null },
});
state = textBufferReducer(state, {
type: 'set_viewport',
payload: { width: viewportWidth, height: 24 },
});
return state;
};
describe('textBufferReducer vim operations', () => {
describe('vim_delete_line', () => {
it('should delete a single line including newline in multi-line text', () => {
const initialState: TextBufferState = {
lines: ['line1', 'line2', 'line3'],
cursorRow: 1,
cursorCol: 2,
preferredCol: null,
visualLines: [['line1'], ['line2'], ['line3']],
visualScrollRow: 0,
visualCursor: { row: 1, col: 2 },
viewport: { width: 10, height: 5 },
undoStack: [],
redoStack: [],
};
const state = createTestState(['line1', 'line2', 'line3'], 1, 2);
const action: TextBufferAction = {
type: 'vim_delete_line',
payload: { count: 1 },
};
const result = textBufferReducer(initialState, action);
const result = textBufferReducer(state, action);
expect(result).toHaveOnlyValidCharacters();
// After deleting line2, we should have line1 and line3, with cursor on line3 (now at index 1)
@@ -1731,25 +1753,14 @@ describe('textBufferReducer vim operations', () => {
});
it('should delete multiple lines when count > 1', () => {
const initialState: TextBufferState = {
lines: ['line1', 'line2', 'line3', 'line4'],
cursorRow: 1,
cursorCol: 0,
preferredCol: null,
visualLines: [['line1'], ['line2'], ['line3'], ['line4']],
visualScrollRow: 0,
visualCursor: { row: 1, col: 0 },
viewport: { width: 10, height: 5 },
undoStack: [],
redoStack: [],
};
const state = createTestState(['line1', 'line2', 'line3', 'line4'], 1, 0);
const action: TextBufferAction = {
type: 'vim_delete_line',
payload: { count: 2 },
};
const result = textBufferReducer(initialState, action);
const result = textBufferReducer(state, action);
expect(result).toHaveOnlyValidCharacters();
// Should delete line2 and line3, leaving line1 and line4
@@ -1759,25 +1770,14 @@ describe('textBufferReducer vim operations', () => {
});
it('should clear single line content when only one line exists', () => {
const initialState: TextBufferState = {
lines: ['only line'],
cursorRow: 0,
cursorCol: 5,
preferredCol: null,
visualLines: [['only line']],
visualScrollRow: 0,
visualCursor: { row: 0, col: 5 },
viewport: { width: 10, height: 5 },
undoStack: [],
redoStack: [],
};
const state = createTestState(['only line'], 0, 5);
const action: TextBufferAction = {
type: 'vim_delete_line',
payload: { count: 1 },
};
const result = textBufferReducer(initialState, action);
const result = textBufferReducer(state, action);
expect(result).toHaveOnlyValidCharacters();
// Should clear the line content but keep the line
@@ -1787,25 +1787,14 @@ describe('textBufferReducer vim operations', () => {
});
it('should handle deleting the last line properly', () => {
const initialState: TextBufferState = {
lines: ['line1', 'line2'],
cursorRow: 1,
cursorCol: 0,
preferredCol: null,
visualLines: [['line1'], ['line2']],
visualScrollRow: 0,
visualCursor: { row: 1, col: 0 },
viewport: { width: 10, height: 5 },
undoStack: [],
redoStack: [],
};
const state = createTestState(['line1', 'line2'], 1, 0);
const action: TextBufferAction = {
type: 'vim_delete_line',
payload: { count: 1 },
};
const result = textBufferReducer(initialState, action);
const result = textBufferReducer(state, action);
expect(result).toHaveOnlyValidCharacters();
// Should delete the last line completely, not leave empty line
@@ -1815,18 +1804,7 @@ describe('textBufferReducer vim operations', () => {
});
it('should handle deleting all lines and maintain valid state for subsequent paste', () => {
const initialState: TextBufferState = {
lines: ['line1', 'line2', 'line3', 'line4'],
cursorRow: 0,
cursorCol: 0,
preferredCol: null,
visualLines: [['line1'], ['line2'], ['line3'], ['line4']],
visualScrollRow: 0,
visualCursor: { row: 0, col: 0 },
viewport: { width: 10, height: 5 },
undoStack: [],
redoStack: [],
};
const state = createTestState(['line1', 'line2', 'line3', 'line4'], 0, 0);
// Delete all 4 lines with 4dd
const deleteAction: TextBufferAction = {
@@ -1834,7 +1812,7 @@ describe('textBufferReducer vim operations', () => {
payload: { count: 4 },
};
const afterDelete = textBufferReducer(initialState, deleteAction);
const afterDelete = textBufferReducer(state, deleteAction);
expect(afterDelete).toHaveOnlyValidCharacters();
// After deleting all lines, should have one empty line

View File

@@ -6,7 +6,13 @@
import { describe, it, expect } from 'vitest';
import { handleVimAction } from './vim-buffer-actions.js';
import type { TextBufferState } from './text-buffer.js';
import type { TextBufferState, VisualLayout } from './text-buffer.js';
const defaultVisualLayout: VisualLayout = {
visualLines: [''],
logicalToVisualMap: [[[0, 0]]],
visualToLogicalMap: [[0, 0]],
};
// Helper to create test state
const createTestState = (
@@ -23,6 +29,8 @@ const createTestState = (
clipboard: null,
selectionAnchor: null,
viewportWidth: 80,
viewportHeight: 24,
visualLayout: defaultVisualLayout,
});
describe('vim-buffer-actions', () => {
@@ -266,7 +274,7 @@ describe('vim-buffer-actions', () => {
const result = handleVimAction(state, action);
expect(result).toHaveOnlyValidCharacters();
expect(result.cursorRow).toBe(1); // Should move to empty line
expect(result.cursorRow).toBe(1);
expect(result.cursorCol).toBe(0); // Beginning of empty line
});
});
@@ -331,7 +339,7 @@ describe('vim-buffer-actions', () => {
const result = handleVimAction(state, action);
expect(result).toHaveOnlyValidCharacters();
expect(result.cursorRow).toBe(2); // Should move to line with 'test'
expect(result.cursorRow).toBe(2);
expect(result.cursorCol).toBe(3); // Should be at 't' (end of 'test')
});
@@ -354,7 +362,7 @@ describe('vim-buffer-actions', () => {
payload: { count: 1 },
});
expect(result).toHaveOnlyValidCharacters();
expect(result.cursorRow).toBe(1); // Should move to empty line
expect(result.cursorRow).toBe(1);
expect(result.cursorCol).toBe(0); // Empty line has col 0
});
@@ -382,7 +390,7 @@ describe('vim-buffer-actions', () => {
it('should handle precomposed characters with diacritics', () => {
// Test case with precomposed é for comparison
const state = createTestState(['café test'], 0, 0); // Start at 'c'
const state = createTestState(['café test'], 0, 0);
// First 'e' command should move to the 'é' (position 3)
let result = handleVimAction(state, {
@@ -814,7 +822,7 @@ describe('vim-buffer-actions', () => {
const state = createTestState(['hello world'], 0, 5);
const action = {
type: 'vim_change_movement' as const,
payload: { movement: 'h', count: 2 },
payload: { movement: 'h' as const, count: 2 },
};
const result = handleVimAction(state, action);
@@ -827,7 +835,7 @@ describe('vim-buffer-actions', () => {
const state = createTestState(['hello world'], 0, 5);
const action = {
type: 'vim_change_movement' as const,
payload: { movement: 'l', count: 3 },
payload: { movement: 'l' as const, count: 3 },
};
const result = handleVimAction(state, action);
@@ -840,7 +848,7 @@ describe('vim-buffer-actions', () => {
const state = createTestState(['line1', 'line2', 'line3'], 0, 2);
const action = {
type: 'vim_change_movement' as const,
payload: { movement: 'j', count: 2 },
payload: { movement: 'j' as const, count: 2 },
};
const result = handleVimAction(state, action);