test sweep: cover terminal_view IME / focus tail paths (T-91)
test / unit + widget + golden + a11y (push) Failing after 30s
test / integration_test (xvfb) (push) Has been skipped
test / bundle smoke (xvfb 5s) (push) Has been skipped
test / daemon subprocess + web WASM smoke (push) Has been skipped
test / dart doc (lib API) (push) Failing after 1m1s

Three tests for the lines the existing TerminalView suite didn't quite
touch: the deleteDetection backspace flow (CustomTextEdit.onDelete
→ scrollToBottom + Terminal.keyInput), the hardwareKeyboardOnly tap
that requests focus directly (_onTapUp's else-branch when there's no
CustomTextEdit), and the single-char IME insert path where the
character maps to a TerminalKey (_onInsert's key != null branch).

Coverage: terminal_view.dart 180/188 -> 187/188 (99.5%). The 1
remaining line is _scrollToBottom's jumpTo call — unreachable in
current wiring since the tree has no Scrollable; _scrollableKey
.currentState is always null and the guard short-circuits.

Note: infinite_scroll_view.dart stays at 90% — the 4 uncovered lines
are the position-setter's value-changed branch, only reachable when
the inner Scrollable swaps its ViewportOffset. The widget doesn't
expose ScrollController or physics, so there's no public surface to
drive that path from a test.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-11 18:04:48 +02:00
co-authored by Claude Opus 4.7
parent 0a43a1f7d2
commit f46ab50ff9
+56
View File
@@ -418,6 +418,62 @@ void main() {
});
});
group('TerminalView — keyboard / IME tail paths', () {
// These cover the last few lines in terminal_view.dart that the existing
// tests didn't quite touch: the onDelete callback wired into
// CustomTextEdit, the hardwareKeyboardOnly tap branch that requests
// focus directly, and the _onInsert path where the inserted character
// maps to a TerminalKey (key != null).
testWidgets('backspace via deleteDetection runs onDelete (scroll + keyInput)', (tester) async {
final r = _OutputRecorder();
final t = r.build();
await tester.pumpWidget(_host(TerminalView(t, autofocus: true, deleteDetection: true)));
await tester.pump();
// deleteDetection seeds the editing value with two spaces; shrinking
// it below that length triggers CustomTextEdit.onDelete, which fires
// _scrollToBottom + Terminal.keyInput(backspace) in TerminalView.
tester.testTextInput.updateEditingValue(const TextEditingValue(
text: '',
selection: TextSelection.collapsed(offset: 0),
));
await tester.pump();
// Backspace produces a non-empty escape sequence (^?).
expect(r.outputs, isNotEmpty);
});
testWidgets('tap on hardwareKeyboardOnly view requests focus on the focus node', (tester) async {
final t = _OutputRecorder().build();
final focus = FocusNode();
addTearDown(focus.dispose);
await tester.pumpWidget(_host(TerminalView(
t,
hardwareKeyboardOnly: true,
focusNode: focus,
)));
// Tap with no selection-clear short-circuit — the else-branch of
// _onTapUp routes through _focusNode.requestFocus when
// hardwareKeyboardOnly is set (no CustomTextEdit to delegate to).
await tester.tapAt(tester.getCenter(find.byType(TerminalView)));
await tester.pump(const Duration(seconds: 1));
expect(focus.hasFocus, isTrue);
});
testWidgets('single-char IME insert routes through keyInput when the char maps to a TerminalKey', (tester) async {
final r = _OutputRecorder();
final t = r.build();
await tester.pumpWidget(_host(TerminalView(t, autofocus: true)));
await tester.pump();
await tester.tap(find.byType(TerminalView));
await tester.pump(const Duration(seconds: 1));
// 'a' is a single char that maps to TerminalKey.a — _onInsert hits
// the key != null branch and calls terminal.keyInput first.
tester.testTextInput.enterText('a');
await tester.pump();
expect(r.outputs, isNotEmpty);
});
});
group('TerminalView — keyboard visibility', () {
testWidgets('platform keyboard show fires _onKeyboardShow on the focused view', (tester) async {
final t = _OutputRecorder().build();