summaryrefslogtreecommitdiffstats
path: root/packages/meshbay-hub/tests/test_transfers.py
diff options
context:
space:
mode:
authorChristophe Besson <cbesson@gmail.com>2026-09-09 01:54:10 +0200
committerChristophe Besson <cbesson@gmail.com>2026-09-09 01:54:10 +0200
commitd6c4808d9a3ef6bc740cda7892508f15ee9ea030 (patch)
treeb9420bd6cc86ac0a72aef09d5ca0ee7e25a3533f /packages/meshbay-hub/tests/test_transfers.py
parenta0b070e5fd382bb4a4262637836cb8d4b268fbf7 (diff)
downloadmeshbay-d6c4808d9a3ef6bc740cda7892508f15ee9ea030.tar.gz
fix(spa): one save dialog per batch, not one per file
Selecting four files on Chrome produced a Save As dialog for the first, then one for the second only after that file had finished, while the last two timed out; on a later attempt the three remaining transfers appeared frozen. Two things were going on. Opening the target inside `prepare` had removed the accidental serialisation that `for (…) await downloadFile(e)` used to provide, so `_openTargetInTurn` now queues the openings — but a queue whose head is an unanswered dialog is a head-of-line block, which is what the "freeze" was. The code already recovered from a picker with no gesture behind it by streaming instead, on the `SecurityError` Chrome throws. That branch was never reached: Chrome does not throw, it shows the dialog anyway and waits for a human. So anything that has to wait its turn is now marked `batched`, and a batched opening prefers the streamed path whatever the download mode says. The first file of a batch — the one actually holding the gesture — still gets its dialog, so the preference is honoured where it can be. For the rest there is no gesture left to spend and nothing is lost by streaming: the file still lands on disk, in the browser's own download folder. Only the choice of folder goes, and it was not on offer. If the worker does not answer, a batched download falls back to the dialog rather than failing. Also logs which path led to a dialog. A dialog is the one outcome nobody can diagnose after the fact — it looks the same whether it was asked for or fallen back to — and the report this fixes needed three test cycles to narrow. The two harnesses that lift `_openDownloadTarget` as text now route console.info to stderr, since they parse stdout as JSON. Measured against the deployed hub in Chrome 152: the streamed path serves the hidden iframe in 2-3 ms on a normal load, after a hard reload (via the `mbdl-claim` recovery already in `_claimController`), and twice in the same document. Hub suite 824 passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HCGdheDLxGReuKHga3BtST
Diffstat (limited to 'packages/meshbay-hub/tests/test_transfers.py')
-rw-r--r--packages/meshbay-hub/tests/test_transfers.py4
1 files changed, 3 insertions, 1 deletions
diff --git a/packages/meshbay-hub/tests/test_transfers.py b/packages/meshbay-hub/tests/test_transfers.py
index 7e21409..c48e38c 100644
--- a/packages/meshbay-hub/tests/test_transfers.py
+++ b/packages/meshbay-hub/tests/test_transfers.py
@@ -432,7 +432,9 @@ def test_the_slot_is_asked_for_after_there_is_somewhere_to_write():
src = (STATIC / "file-utils.js").read_text()
fn = src[src.index("async function downloadEntry"):]
fn = fn[:fn.index("\n}\n")]
- assert fn.index("_openDownloadTarget") < fn.index("openTransfer"), (
+ # `_openTargetInTurn` since target openings were serialised — same call,
+ # queued. What is pinned is that it comes before the slot is asked for.
+ assert fn.index("_openTargetInTurn") < fn.index("openTransfer"), (
"downloadEntry asks for a transfer slot before it has anywhere to "
"write — the grant expires before the download can use it")