Repository navigation
test(macos): make the macOS test job deterministic - #257
Merged
Merged
Conversation
akonwi
force-pushed
the
macos/test-stability
branch
from
October 22, 2026 19:11
53958ab to
a27373f
Compare
The suite runs its tests in parallel, and on CI's three-core runner the main actor was measured blocked for 6 s, and the cooperative pool for 2.7 s, while the suite starts. Waits that gave a condition 0.5-5 s before failing therefore failed on correct code (#234, #256). Add one `eventually` helper whose limit only keeps a broken build from hanging, and use it for every condition the tests polled with a short budget. Tests that pressed a key a fixed number of times, or after a fixed sleep, now press until the effect is seen. The SSH fakes keep the app's own ssh idle timeout, which no test waits out.
The layout capture and scratchpad autosave tests waited real time for their delays and then for the result, so a busy runner could miss the deadline (#234). SessionWindowModel and ScratchpadState now take the sleep they debounce with, and the tests pass a ManualSleeper: they wait for the delay to begin, check nothing happened yet, end it, and check the result, including that quitting cancels a pending capture.
SwiftUI edits every text field in the process with one shared field editor. When a test running at the same time focused a text field in its own window, it took the editor from the launcher's window, leaving that window as its own first responder, so the launcher test's arrow keys and Return went nowhere (#234). CI diagnostics showed the search field focused and then losing focus about 120 ms later; a second focused window reproduces it locally every time. The test now hosts the launcher in a FocusIsolatedWindow, which edits with its own instance of SwiftUI's field editor. It no longer activates the app or makes the window key, since focus never depended on either, and it waits for the field and the key presses' effects rather than sleeping.
akonwi
force-pushed
the
macos/test-stability
branch
from
October 22, 2026 19:32
a27373f to
976f1b7
Compare
Windowed diff, inline annotation, and transcript history tests slept a fixed 150-1500 ms after each step and then asserted on layout, scroll position, or focus. On CI's busy runner that wasn't always enough: diffPaneShowsServerFileAndTargetInBothAppearances failed when the pane hadn't laid out for its shorter window before the wheel event. Each step now waits with `eventually` for the state its assertions check. The two diff tests that interrupt a slow read wait for the read to start.
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.
Makes the macOS test job deterministic. Fixes #234 and #256.
Root causes
CI diagnostics (temporary instrumentation, since dropped) on the 3-core
macos-latestrunner showed:TileArrangementTests.layoutChangesAreCapturedAfterADelay: its first capture was still pending after 6.2 s (Flaky macOS CI tests: SessionLauncherTests.renderLauncherForReview and TileArrangementTests #234).SSHHostTests.closingAHostWithdrawsItsQuestion: the first question took 4–5 s to arrive (Flaky: SSHHostTests.closingAHostWithdrawsItsQuestion is timing-dependent #256).SSHServerConnectionTestsfailed the same way in one diagnostic run.opened == [],renamed == ["a"]). This explains the consistentrenderLauncherForReviewfailures (Flaky macOS CI tests: SessionLauncherTests.renderLauncherForReview and TileArrangementTests #234). Adding windowed tests such as fix(macos): shrink and scroll tile tabs without a system scroller #254's makes the overlap more likely. Opening a second focused window reproduces it locally every time. Activation and key-window status don't matter: the app was never active on CI, and focus works without either.Fixes
eventually(TestTiming.swift): one polling helper whose 60 s limit only stops a broken build from hanging. It replaces every short-budget polling loop and ad-hocuntil/eventually/waithelper (about 60 call sites). Tests that pressed a key a fixed number of times, or after a fixed sleep, now press until they see the effect.SessionWindowModelandScratchpadStatetake aSleeper. WithManualSleeper, the layout-capture and autosave tests wait for the delay to start, check that nothing happened yet, end the delay, and check the result. They no longer measure wall-clock time; they assert which delay was requested.diffPaneShowsServerFileAndTargetInBothAppearanceshad failed on CI because of these sleeps.FocusIsolatedWindow(TestWindows.swift): edits with its own instance of SwiftUI's field editor. The launcher test uses it, and no longer callsNSApp.activate()ormakeKey().Validation
closingAHostWithdrawsItsQuestion: 5.2 / 8.1 / 3.9 s (old budget 5 s per wait)layoutChangesAreCapturedAfterADelay: 10.2 / 9.9 / 6.7 s (old budget 5 s)renderLauncherForReview: 9.0 / 9.9 / 6.6 syesprocesses saturating the CPU. Before the last DiffTests fix, a loaded run caught one more fixed-sleep race, which is now fixed. Earlier, the affected suites passed in repeated isolated loops.FocusIsolatedWindow, it passes.code-reviewersubagent: no blocking issues. Its findings are addressed: the VCS cancellation race is fixed, the remaining polling loops are converted, and the property is renamed tosleeper.Follow-up for the remaining fixed sleeps that haven't been seen failing: #260.
Closes #234. Closes #256.