aboutsummaryrefslogtreecommitdiffstats
path: root/packages/meshbay-cli/tests/test_interactive.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-cli/tests/test_interactive.py')
-rw-r--r--packages/meshbay-cli/tests/test_interactive.py79
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)