Co-authored-by: Quentin Torroba <quentin.torroba@mistral.ai>
Co-authored-by: Kim-Adeline Miguel <kimadeline.miguel@mistral.ai>
Co-authored-by: Vincent Guilloux <vincent.guilloux@mistral.ai>
Co-authored-by: Clement Sirieix <clem.sirieix@gmail.com>
Co-authored-by: Antoine W <antoine.wronka@mistral.ai>
Co-authored-by: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
Mathias Gesbert 2026-03-09 19:28:09 +01:00 committed by GitHub
parent 5d2e01a6d7
commit dd372ce494
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
89 changed files with 2086 additions and 596 deletions

View file

@ -117,3 +117,169 @@ async def test_ui_resumes_arrow_down_after_manual_move(
await pilot.press("down")
assert textarea.cursor_location[0] == 1
assert chat_input.value == "first line\nsecond line"
@pytest.mark.asyncio
async def test_ui_does_not_intercept_arrow_down_inside_wrapped_single_line_input(
vibe_app: VibeApp,
) -> None:
long_input = "0123456789 " * 20
async with vibe_app.run_test(size=(40, 20)) as pilot:
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
textarea.insert(long_input)
assert chat_input.value == long_input
assert textarea.wrapped_document.height > 1
textarea.action_cursor_up()
location_after_up = textarea.cursor_location
assert textarea.get_cursor_down_location() != location_after_up
await pilot.press("down")
assert chat_input.value == long_input
assert textarea.cursor_location != location_after_up
@pytest.mark.asyncio
async def test_ui_intercepts_arrow_up_only_on_first_wrapped_row(
vibe_app: VibeApp, history_file: Path
) -> None:
long_input = "abcdefghij " * 20
async with vibe_app.run_test(size=(40, 20)) as pilot:
inject_history_file(vibe_app, history_file)
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
textarea.insert(long_input)
assert chat_input.value == long_input
assert textarea.wrapped_document.height > 1
textarea.action_cursor_up()
assert chat_input.value == long_input
while textarea.get_cursor_up_location() != textarea.cursor_location:
textarea.action_cursor_up()
await pilot.press("up")
assert chat_input.value == "how are you?"
@pytest.mark.asyncio
async def test_ui_up_from_wrapped_top_loads_history_after_down_at_wrapped_bottom(
vibe_app: VibeApp, history_file: Path
) -> None:
long_input = "LONG " + ("x" * 160)
async with vibe_app.run_test(size=(40, 20)) as pilot:
inject_history_file(vibe_app, history_file)
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
textarea.insert(long_input)
assert chat_input.value == long_input
assert not textarea.navigator.is_first_wrapped_line(textarea.cursor_location)
assert textarea.navigator.is_last_wrapped_line(textarea.cursor_location)
await pilot.press("down")
textarea.move_cursor((0, 0))
assert textarea.navigator.is_first_wrapped_line(textarea.cursor_location)
await pilot.press("up")
assert chat_input.value == "how are you?"
@pytest.mark.asyncio
async def test_ui_down_cycles_to_next_history_without_manual_move_after_loading_multiline_entry(
vibe_app: VibeApp, tmp_path: Path
) -> None:
long_first_line = "abcdefghij " * 20
history_entry = f"{long_first_line}\nsecond line"
history_path = tmp_path / "history.jsonl"
history_path.write_text(json.dumps(history_entry) + "\n", encoding="utf-8")
async with vibe_app.run_test(size=(40, 20)) as pilot:
inject_history_file(vibe_app, history_path)
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
await pilot.press("up")
assert chat_input.value == history_entry
assert not textarea.navigator.is_first_wrapped_line(textarea.cursor_location)
assert not textarea.navigator.is_last_wrapped_line(textarea.cursor_location)
await pilot.press("down")
assert chat_input.value == ""
@pytest.mark.asyncio
async def test_ui_up_continues_history_cycle_after_loading_wrapped_multiline_entry(
vibe_app: VibeApp, tmp_path: Path
) -> None:
long_first_line = "abcdefghij " * 20
wrapped_multiline = f"{long_first_line}\nsecond line"
history_path = tmp_path / "history.jsonl"
history_entries = ["older message", wrapped_multiline, "Hi there"]
history_path.write_text(
"\n".join(json.dumps(entry) for entry in history_entries) + "\n",
encoding="utf-8",
)
async with vibe_app.run_test(size=(40, 20)) as pilot:
inject_history_file(vibe_app, history_path)
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
await pilot.press("up")
assert chat_input.value == "Hi there"
await pilot.press("up")
assert chat_input.value == wrapped_multiline
assert not textarea.navigator.is_first_wrapped_line(textarea.cursor_location)
await pilot.press("up")
assert chat_input.value == "older message"
@pytest.mark.asyncio
async def test_ui_down_at_visual_end_resumes_history_after_manual_cursor_move(
vibe_app: VibeApp, tmp_path: Path
) -> None:
long_first_line = "abcdefghij " * 20
wrapped_multiline = f"{long_first_line}\nsecond line"
history_path = tmp_path / "history.jsonl"
history_entries = ["older message", wrapped_multiline, "Hi there"]
history_path.write_text(
"\n".join(json.dumps(entry) for entry in history_entries) + "\n",
encoding="utf-8",
)
async with vibe_app.run_test(size=(40, 20)) as pilot:
inject_history_file(vibe_app, history_path)
chat_input = vibe_app.query_one(ChatInputContainer)
textarea = chat_input.input_widget
assert textarea is not None
await pilot.press("up")
await pilot.press("up")
assert chat_input.value == wrapped_multiline
await pilot.press("left")
assert textarea.cursor_location != (0, len(long_first_line))
while not textarea.navigator.is_last_wrapped_line(textarea.cursor_location):
textarea.action_cursor_down()
textarea.move_cursor((1, len("second line")))
assert textarea.navigator.is_last_wrapped_line(textarea.cursor_location)
await pilot.press("down")
assert chat_input.value == "Hi there"