""" `window.prompt` does not exist in the desktop client. The same `static/` tree is the web page and the application (CLAUDE.md's "one UI source"), and Electron does not implement `prompt` — Chromium leaves it to the embedder and Electron declines. It does not return null: it **throws**, `Error: prompt() is not supported.` That made the Files toolbar's New folder button do nothing whatsoever. The call sat above its own try, so the click produced no folder, no error, and nothing on screen to react to — the failure looks exactly like a dead button, which is what it was reported as. Measured rather than assumed, against this repo's own Electron 44: prompt('name?') -> Error: prompt() is not supported. confirm('sure?') -> opens a real modal alert('hi') -> opens a real modal So `confirm` and `alert` stay allowed and are used in a dozen places; only `prompt` is banned. Anything that needs typed input needs a field. """ import re from pathlib import Path import pytest STATIC = Path(__file__).resolve().parents[1] / "src" / "meshbay_hub" / "static" pytestmark = pytest.mark.skipif(not STATIC.exists(), reason="SPA sources unavailable") # `prompt(` as a call, not `window.prompt` inside a comment or a longer # identifier like `mkdir_prompt` / `promptForName`. CALL = re.compile(r"(? str: source = re.sub(r"/\*.*?\*/", "", source, flags=re.S) return re.sub(r"^\s*//.*$", "", source, flags=re.M) def test_nothing_calls_prompt(): offenders = [] for path in sorted(STATIC.glob("*.js")): if path.name == "sw.js": continue for i, line in enumerate(_code_only( path.read_text(encoding="utf-8")).splitlines(), 1): if CALL.search(line): offenders.append(f"{path.name}:{i}: {line.strip()}") assert not offenders, ( "prompt() throws in the desktop client, and the click that reaches it " "does nothing at all:\n " + "\n ".join(offenders)) def test_the_pattern_would_catch_a_real_call(): """ A guard that matches nothing passes over an empty set, which looks exactly like success. Both spellings, and the near-misses it must not flag. """ assert CALL.search("const n = prompt('x');") assert CALL.search("const n = window.prompt('x');") assert not CALL.search("t('group.mkdir_prompt')") assert not CALL.search("promptForName();") assert not CALL.search("this.prompt(1);") def test_creating_a_folder_uses_a_field(): """ The control the ban is about. A typed name needs somewhere to type it, and an inline field can show the node's refusal beside the input rather than after a dialog has closed. """ source = (STATIC / "files-app.js").read_text(encoding="utf-8") assert "tb-mkdir-input" in source assert "newDirName" in source assert "group.mkdir_prompt" in source, "the field has no label or placeholder" def test_leaving_the_folder_drops_a_half_typed_name(): """ Otherwise the folder is created where the person is no longer looking — they navigated away, the draft came along, and the name lands in a directory they were not thinking about. """ source = (STATIC / "files-app.js").read_text(encoding="utf-8") assert "useEffect(() => { setNewDirName(null); }, [currentPath]);" in source