diff options
Diffstat (limited to 'packages/meshbay-hub/tests/test_app_settings_plugin.py')
| -rw-r--r-- | packages/meshbay-hub/tests/test_app_settings_plugin.py | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/packages/meshbay-hub/tests/test_app_settings_plugin.py b/packages/meshbay-hub/tests/test_app_settings_plugin.py index 6a768a9..8a095af 100644 --- a/packages/meshbay-hub/tests/test_app_settings_plugin.py +++ b/packages/meshbay-hub/tests/test_app_settings_plugin.py @@ -320,3 +320,75 @@ def test_a_refusal_does_not_look_like_a_footnote(): assert "role=" in block and "alert" in block, ( "a refusal that appears after a click has to be announced, not just " "drawn") + + +# ── Saving, and being able to tell ────────────────────────────────────────── + +PANE_FLAGS = {"chat-app-settings.js": "dirty", + "video-app-settings.js": "dirsDirty", + "music-app-settings.js": "dirsDirty", + "photos-app-settings.js": "dirty"} + + +@pytest.mark.parametrize("pane", sorted(PANE_FLAGS)) +def test_save_is_a_button_and_not_dim_text(pane): + """ + It was `btn btn-small btn-secondary`, and there is no `.btn` rule in the + stylesheet at all — so it took `.btn-secondary`: no background, a + transparent border, dim grey text. Enabled it already looked like a + disabled control, and disabled it was that at 40% opacity. + + "You cannot always click Save, you do not notice, and it does not work" is + one sentence describing all of that. + """ + source = (STATIC / pane).read_text(encoding="utf-8") + assert 'class="app-save"' in source, f"{pane}'s Save is not the shared control" + assert "btn-secondary" not in source, ( + f"{pane}'s Save is still styled as dim text") + + +@pytest.mark.parametrize("pane", sorted(PANE_FLAGS)) +def test_an_inert_save_says_why(pane): + """ + A disabled control that explains itself is the difference between "nothing + changed" and "this is broken". Without it the reader has to know what the + pane counts as a change. + """ + source = (STATIC / pane).read_text(encoding="utf-8") + assert "app-save-why" in source and "settings_app.no_changes" in source + + +def test_the_disabled_state_is_visually_distinct(): + css = (STATIC / "style.css").read_text(encoding="utf-8") + rule = css[css.index(".app-save {"):] + rule = rule[:rule.index(".app-save-row")] + assert "var(--accent)" in rule, "an enabled Save has no fill" + disabled = rule[rule.index(".app-save:disabled"):] + assert "background: none" in disabled and "--text-dim" in disabled, ( + "disabled differs from enabled by opacity alone, which is what made " + "it unreadable") + + +def test_a_saved_setting_reaches_the_page_that_renders_the_pane(): + """ + Why Chat was the systematic case. + + `_dispatch` resolves an admin ack against the pending request and returns — + right for an op whose caller already knows the value it chose. Chat's pane + calls `transport.setChatDirectory` itself, so nothing told `group-page` + anything: the node saved it, every *other* connected client learned it from + the broadcast, and the one that asked went on showing an unsaved-looking + draft. Clicking Save again just re-sent it. + """ + transport = TRANSPORT.read_text(encoding="utf-8") + block = transport[transport.index("const BROADCAST_ACK_TYPES"):] + block = block[:block.index("]);") + 3] + for ack in ("chat_directory_ack", "chat_link_preview_ack", + "app_directories_ack"): + assert ack in block, f"{ack} is swallowed by its own request" + + assert "_replayBroadcast" in transport + replay = transport[transport.index("function _replayBroadcast"):] + replay = replay[:replay.index("\n}") + 2] + for cb in ("_onChatDirectory", "_onChatLinkPreview", "_onAppDirectories"): + assert cb in replay, f"{cb} is never called for the requester" |