test(tabs): run a transfer end to end instead of inspecting the gate - #453
Merged
PathGao merged 1 commit intoAug 4, 2026
Merged
Conversation
#366 gated claim/complete/cancel on the caller being window-<token>. That label exists only for a window create_transfer_window just built, so offer_tab_to_window's destination -- an already-open window labelled main or window-<some other token> -- was refused 100% of the time. #452 fixed it by recording the target on the pending entry and accepting either label. It reached master, not a release. Nothing in the suite failed. The Rust test asserted the predicate behaves as written, and it did: the gate was self-consistently wrong. The script test asserted that the invoke('offer_tab_to_window', ...) call appears in the source, and it still appeared. Both confirmed an implementation exists and is internally consistent, which is precisely what a reachable path becoming unreachable leaves undisturbed. Four tests now drive the broker from stage to complete: * a transfer to an existing window -- stage from main, record the target the way offer_tab_to_window does, claim as that window, complete. This is the path that was dead. * a transfer to a new window -- claim as window-<token> with no target recorded, so the fix cannot trade one path for the other. * a bystander window refused at claim, complete and cancel, with the transfer left intact for its real destination afterwards. * the recorded target releasing its own claim, the only rollback a claimed transfer has: the source's timeout is deliberately inert once a claim exists, so a refusal here would strand the tab in both windows. The authorisation decision moves out of the three #[tauri::command] bodies onto the broker as claim_as/complete_as/cancel_as, which take the caller's label as &str; each command is now one line passing window.label(). A unit test cannot build a tauri::Window, so the gate was otherwise reachable only through the predicate it was written against. Same peek, same order, same error strings. Reverting the recorded-target arm of is_destination_authority and restoring the two predicate tests to their #366 wording leaves the suite at 3 failed / 151 passed -- all three of them these tests. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
PathGao
force-pushed
the
test/transfer-executes-the-protocol
branch
from
August 4, 2026 23:18
63a3751 to
1378038
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Test-only. No product behaviour changes, and nothing here is urgent — it can sit until after v2.7.0 is out.
#366 was mine, and it broke "Move to Window ▸ (an open window)" outright. It never reached a release, and you found and fixed it in #452 before it could. This PR is not a second fix; it is the test that would have caught it, and the reason the suite did not.
The gate and the path it closed
#366 added, to all three transfer commands:
is_destination_labeliscaller == format!("window-{token}"). That label exists for exactly one window: the onecreate_transfer_windowjust built for this token.There are two ways a tab reaches another window, and only one of them ends there:
create_transfer_window(token)— Move to New Windowwindow-<token>offer_tab_to_window(target_label, token)(#214, shipped in v2.6.13) — Move to an existing windowmain, orwindow-<some other token>The second is not a corner: an already-open window's label was assigned by an earlier, unrelated transfer, so it cannot equal
window-<token>for the token now in flight.maincannot either. 100% failure, both platforms.Why 150 Rust tests and 596 script tests stayed green
Two tests point at this code. Neither could see it.
only_the_matching_destination_window_may_claimassertedis_destination_labelbehaves as written. It did. The gate was self-consistently wrong — the predicate and its test agreed with each other and both disagreed with the product.windowOrganization.test.ts::'moving to an existing window uses the acknowledged transfer protocol'is fiveassert.matchcalls looking forinvoke('offer_tab_to_window', { targetLabel, token }),invoke('complete_detached_tab', { token }),acceptOfferedTransfer,onTransferClaimed(tabId)andasync function transfer(inMarkdownViewer.svelteandwindowSession.svelte.ts. All five still matched. fix(transfer): never leave a moved tab open in both windows #366 touched neither file.Between them they proved that an implementation exists and that it is internally consistent. A reachable path becoming unreachable disturbs neither property. Nothing in either suite ever performed a transfer.
What is added
Four tests at the bottom of
tab_transfer.rs'smod tests, driving the real broker fromstagetocomplete.a_transfer_to_an_existing_window_runs_end_to_endmain→set_target_label(whatoffer_tab_to_windowdoes) → claim as that window → completetarget_labelarm goes awaya_transfer_to_a_new_window_runs_end_to_endwindow-<token>, no target recorded → completea_third_party_window_is_refused_at_every_stepwindow-<token>, nor the recorded target, at claim, complete and cancelthe_recorded_destination_may_release_its_own_claimThe existing tests keep testing the parts. These test the composition, because the composition is what was broken.
The one source change
The gate lived inside three
#[tauri::command]bodies, so it was reachable only through atauri::Window, which a unit test cannot construct — which is why it was only ever tested through the free predicate it was written against. The decision moves onto the broker asclaim_as/complete_as/cancel_as, taking the caller's label as&str:Same
peek, same order of operations, same error strings, sameTRANSFER_NOT_FOUNDrace branch incomplete. All three commands are one line. Nothing else insrc-tauri/is touched, and no.svelteor.tsfile is touched at all.Falsification
A test that cannot fail is the failure mode this PR exists to close, so it is checked directly.
is_destination_authorityreverted to its #366 body, tests left in place:That alone turns five tests red, but two of them —
only_the_matching_destination_window_may_claimandcancel_authority_rejects_third_party_windows— only fail because #452 amended them alongside the fix. They did not exist in that form on the day #366 merged, so they are not evidence. Restoring those two to their #366 wording as well reconstructs the suite exactly as it stood while the path was dead:Three red, and all three are these tests.
a_transfer_to_a_new_window_runs_end_to_endstays green throughout, which is the whole point of having it: the mutation removes one path and leaves the other alone, and the suite now says so. The fix was restored and the suite re-run green afterwards.Verification
cd src-tauri && cargo testmaster)npm testnpm run checkcargo clippy --all-targetstab_transfer.rs; the three pre-existing warnings elsewhere (EXE_NAMEunused, apush_str, a collapsibleif) are as onmastercargo fmt --checktab_transfer.rsgoes from 4 pre-existing diffs to 1, incidentally, by rewriting the blocks the remaining three were in. Nothing was reformatted deliberately and the last one is left alone.Notes, not changes
scripts/windowOrganization.test.tsis the other half of this hole and is deliberately untouched. Its'moving to an existing window uses the acknowledged transfer protocol'still asserts that five identifiers appear in two source files, which is what it was able to do —node --testcannot import a.sveltefile (test(scroll-sync): cover the split-view mapping by running it #442's finding). It stayed green through fix(transfer): never leave a moved tab open in both windows #366 and would stay green through the same defect again. Closing that needs the handler extracted the way test(scroll-sync): cover the split-view mapping by running it #442 extracted the scroll-sync mapping, and it belongs in ascripts/PR, not this one.offer_tab_to_window's own wiring has no test.window_runtime::offer_tab_to_windowchecks the window exists, callsset_target_label, then emitstab-transfer-offer. The broker half is now covered; theget_webview_window/emit_tohalf needs anAppHandleand is not reachable from a unit test.set_target_labelispuband last-write-wins. It is called once per transfer, immediately afterstage, by the one caller that has the token. A second call would silently redirect a staged tab. Worth pinning to "only before the first claim" if the offer path ever grows a retry — no bug today, so nothing is changed.