Files
hkuds--openharness/tests/test_ui/test_tui_exit_sequence.py
T
yulin ed0b5f02ab fix(tui): write trailing newline on exit so shell prompt starts on a fresh line (#133)
* fix(tui): write newline on exit so shell prompt starts on fresh line

Ink hides the cursor during rendering and restores it on exit, but does
not emit a trailing newline.  When the TUI process ends, the terminal
cursor sits at the end of the last rendered line, causing the shell
prompt to appear directly concatenated with the TUI output.

Rename restoreCursor → restoreTerminal and append '\n' alongside the
cursor-show escape sequence so the parent shell always receives the
prompt on a clean new line.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* test(tui): add regression guard for exit newline; update changelog

- Add tests/test_ui/test_tui_exit_sequence.py with two tests:
  * test_tui_exit_handler_writes_newline: asserts the cleanup write
    includes the trailing \n alongside \x1B[?25h
  * test_tui_exit_handler_registered_for_all_signals: asserts cleanup
    is registered for 'exit', SIGINT, and SIGTERM
- Add entry to CHANGELOG.md [Unreleased] Fixed section

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(tests): update ohmo cli test inputs for allow_remote_admin_commands prompt

Commit dd1d235 added a new 'Allow explicitly listed administrative slash
commands from remote channels?' confirmation step to the gateway config
wizard, but the four interactive test cases in test_ohmo/test_cli.py were
not updated to provide an answer for it. This caused stdin to be exhausted
and click to emit Abort(), making all four tests fail with exit_code=1.

Add 'n' as the answer for allow_remote_admin_commands in each affected
test, and move the existing 'restart gateway' answer after it in
test_ohmo_config_interactive_can_restart_gateway.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-04-13 18:49:47 +08:00

50 lines
1.9 KiB
Python

"""Regression guard: the React TUI exit handler must write a trailing newline.
When the TUI process exits, Ink leaves the cursor at the end of the last
rendered line. Without a newline the shell prompt appears concatenated with
the TUI output, which is visually broken. This test reads the TypeScript
entry-point source and asserts that the exit-cleanup write includes '\\n'
alongside the cursor-show escape sequence.
"""
from __future__ import annotations
import re
from pathlib import Path
def _frontend_index() -> Path:
repo_root = Path(__file__).resolve().parents[2]
return repo_root / "frontend" / "terminal" / "src" / "index.tsx"
def test_tui_exit_handler_writes_newline() -> None:
"""restoreTerminal must emit \\x1B[?25h\\n so the shell prompt starts on a new line.
Regression for: TUI exit leaves shell prompt concatenated with last TUI line.
"""
source = _frontend_index().read_text(encoding="utf-8")
# Locate the cleanup function body and verify it includes a trailing \\n.
# The expected write is: process.stdout.write('\\x1B[?25h\\n')
pattern = re.compile(
r"process\.stdout\.write\(['\"].*\\x1B\[\?25h\\n.*['\"]\)",
re.MULTILINE,
)
assert pattern.search(source), (
"The TUI exit handler must call process.stdout.write with a trailing '\\n' "
"so the shell prompt starts on a fresh line after the TUI exits. "
f"Check {_frontend_index()} and ensure the cursor-restore write ends with \\n."
)
def test_tui_exit_handler_registered_for_all_signals() -> None:
"""restoreTerminal must be attached to 'exit', SIGINT, and SIGTERM."""
source = _frontend_index().read_text(encoding="utf-8")
for signal in ("exit", "SIGINT", "SIGTERM"):
assert f"process.on('{signal}'" in source, (
f"The TUI exit cleanup must be registered for '{signal}'. "
f"Check {_frontend_index()}."
)