summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_chat_send.py
diff options
context:
space:
mode:
Diffstat (limited to 'packages/meshbay-hub/tests/test_chat_send.py')
-rw-r--r--packages/meshbay-hub/tests/test_chat_send.py68
1 files changed, 68 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_chat_send.py b/packages/meshbay-hub/tests/test_chat_send.py
index 5db8f26..d442383 100644
--- a/packages/meshbay-hub/tests/test_chat_send.py
+++ b/packages/meshbay-hub/tests/test_chat_send.py
@@ -24,6 +24,13 @@ shapes of answer.
None of it is visible in `chat-app.js`, where every line is correct, so this
drives the real panel over the real transport in a browser rather than reading
either source.
+
+Since 2026-09-09 it covers a **second** way the tab freezes, found from a field
+report and reproduced here: a reconnect clears the connection's device identity
+and settles it again, and the composer gates on that. Nothing announced the
+change, so the panel latched shut on an unrelated re-render and had no event
+that would open it again. Unlike the routing defect above, no timeout ends it —
+only leaving the group or restarting the client does.
"""
import json
import shutil
@@ -147,6 +154,67 @@ def test_the_chat_keys_answer_is_not_handed_to_another_request(probe):
"send then waits out its own 30s timeout with the composer disabled")
+def test_a_reconnect_gives_the_composer_back(probe):
+ """
+ The other way a Chat tab freezes, and the one no timeout ever ends.
+
+ A send that goes astray holds the composer for 30s. This holds it for the
+ rest of the session: `devicePk` — "this connection identified a device to
+ the node" — is settled inside `connect()`, so every reconnect clears it and
+ re-settles it, and the composer gates on it. Nothing announced the change,
+ so the panel went disabled on whatever unrelated re-render happened next
+ (a message arriving) and had no event that would bring it back. The
+ connection stayed perfectly healthy throughout, no request ever timed out,
+ and nothing reached the console: a field report of exactly this arrived
+ with a full console dump that could not say what had happened.
+
+ The three states below are the whole claim: it closes when the identity
+ goes, it stays closed while it is gone, and it **opens again** when the
+ identity comes back.
+ """
+ _, steps = probe
+ sc = steps["reconnect"]
+ assert sc["older request pending"]["composerDisabled"] is False, (
+ "the composer was already unusable before the reconnect")
+ assert sc["device identity cleared"]["composerDisabled"] is True, (
+ "the composer stayed open with no device identity to seal with -- the "
+ "send would be refused with no reason on screen")
+ assert sc["a message arrived meanwhile"]["composerDisabled"] is True, (
+ "an unrelated re-render changed the answer, which means the answer was "
+ "never being derived from anything the panel was told about")
+ assert sc["device identity restored"]["composerDisabled"] is False, (
+ "the composer never came back after the reconnect re-identified the "
+ "device -- this is the freeze that no timeout ends and that only "
+ "leaving the group or restarting the client clears")
+
+
+def test_the_closed_composer_says_which_of_its_two_reasons_it_is(probe):
+ """
+ A disabled textbox is one symptom with two causes — a send in flight, or no
+ device identity — and telling them apart is what the field report could not
+ do. The placeholder is where a person reads the difference.
+ """
+ _, steps = probe
+ sc = steps["reconnect"]
+ assert sc["device identity cleared"]["composerPlaceholder"] \
+ == "chat.encrypted_cannot_send", (
+ "a closed composer offered no reason for being closed")
+ assert sc["device identity restored"]["composerPlaceholder"] \
+ == "chat.placeholder"
+
+
+def test_sending_works_again_after_a_reconnect(probe):
+ """Not just enabled — actually able to seal and send under the identity
+ the reconnect settled on."""
+ _, steps = probe
+ sc = steps["reconnect"]
+ before = sc["device identity restored"]["bubbles"]
+ assert sc["after send"]["bubbles"] == before + 1, (
+ "the message was not added to the conversation after the reconnect")
+ assert sc["after send"]["composerValue"] == "", (
+ "the text came back into the composer, so the send failed")
+
+
def test_history_still_renders(probe):
"""
Not about sending at all, and here because it broke without a sound: