diff options
Diffstat (limited to 'packages/meshbay-cli/tests/test_interactive.py')
| -rw-r--r-- | packages/meshbay-cli/tests/test_interactive.py | 79 |
1 files changed, 79 insertions, 0 deletions
diff --git a/packages/meshbay-cli/tests/test_interactive.py b/packages/meshbay-cli/tests/test_interactive.py index 49180d5..fa7e96c 100644 --- a/packages/meshbay-cli/tests/test_interactive.py +++ b/packages/meshbay-cli/tests/test_interactive.py @@ -206,3 +206,82 @@ async def test_delete_removes_what_is_yours_and_asks_first(world): await pilot.press("delete") await pilot.pause(0.2) assert any("select them on the right" in n.message for n in app._notifications) + + +def _log_text(screen) -> str: + from textual.widgets import RichLog + return "\n".join("".join(seg.text for seg in strip) + for strip in screen.query_one(RichLog).lines) + + +async def test_the_interactive_chat_joins_talks_leaves_and_comes_back(world, monkeypatch): + from meshbay_cli.tui.chat import ChatGroupsScreen, ChatRoomScreen + from textual.widgets import DataTable, Input + hub, node, _ = world + hub.groups.append({"id": "g9", "name": "Quiet", "owner_username": "bob-test", + "node_online": True, "is_admin": False}) + quiet = FakeNode() + quiet.ack["enabled_apps"] = ["files"] + sessions = {} + + async def open_group(account, group): + target = quiet if group["id"] == "g9" else node + sessions[group["id"]] = target.session() + return sessions[group["id"]] + monkeypatch.setattr(pool, "open_group", open_group) + node.say("earlier, from bob") + assert await asyncio.to_thread(cli.main, ["--hub", "https://hub.test", "-u", USERNAME, + "--password", PASSPHRASE, "login"]) == 0 + + app = MeshBayApp(context.Context(cli.build_parser().parse_args( + ["--hub", "https://hub.test"])), ChatGroupsScreen) + async with app.run_test(size=(120, 30)) as pilot: + await _until(pilot, lambda: isinstance(app.screen, ChatGroupsScreen)) + table = app.screen.query_one(DataTable) + await _until(pilot, lambda: table.row_count == 2) + + # A group whose chat is off is not entered. + table.move_cursor(row=1) # Quiet@bob-test + await pilot.press("enter") + await _until(pilot, lambda: any("chat turned off" in n.message + for n in app._notifications)) + assert isinstance(app.screen, ChatGroupsScreen) + + table.move_cursor(row=0) # Family@alice-test + await pilot.press("enter") + await _until(pilot, lambda: isinstance(app.screen, ChatRoomScreen)) + room = app.screen + await _until(pilot, lambda: "<bob-test> earlier, from bob" in _log_text(room)) + + # Posting: sealed, signed, stored on the node, shown here at once. + room.query_one(Input).value = "hello from the room" + await pilot.press("enter") + await _until(pilot, lambda: "<alice-test> hello from the room" in _log_text(room)) + assert len(node.chat) == 2 + + # What the node pushes appears as it arrives. + bob = node.say("live, from bob") + sessions["g1"].ch._emit({**node.chat[-1], "type": "chat_msg"}) + await _until(pilot, lambda: "<bob-test> live, from bob" in _log_text(room)) + assert bob.pk_ed + + # /part goes back; entering again shows the conversation once, and a + # pushed message once — the room left behind no handler. + room.query_one(Input).value = "/part" + await pilot.press("enter") + await _until(pilot, lambda: isinstance(app.screen, ChatGroupsScreen)) + await pilot.press("enter") + await _until(pilot, lambda: isinstance(app.screen, ChatRoomScreen)) + room = app.screen + await _until(pilot, lambda: "live, from bob" in _log_text(room)) + node.say("once") + sessions["g1"].ch._emit({**node.chat[-1], "type": "chat_msg"}) + await _until(pilot, lambda: "<bob-test> once" in _log_text(room)) + await pilot.pause(0.2) + assert _log_text(room).count("<bob-test> once") == 1 + + # Esc goes back too; q quits from the list. + await pilot.press("escape") + await _until(pilot, lambda: isinstance(app.screen, ChatGroupsScreen)) + await pilot.press("q") + assert app.return_code in (0, None) |