Skip to content

refactor(daemon): relocate the session-lifecycle tests by what they assert - #3670

Merged
thymikee merged 9 commits into
refactor/daemon-handlers-testsfrom
refactor/daemon-session-lifecycle-tests
Oct 15, 2026
Merged

thymikee merged 9 commits into
refactor/daemon-handlers-testsfrom
refactor/daemon-session-lifecycle-tests

Conversation

@thymikee

@thymikee thymikee commented Oct 15, 2026 •

Copy link
Copy Markdown
Member

Summary

Batch session-lifecycle (plus the device, replay-suite and replay-target leftovers) of the daemon test redesign (no test exports of any kind). 13 root tests under src/__tests__/daemon-composition/{session-lifecycle,device,replay-suite,replay-target}/ are placed by what they assert; the directories are gone. Stacked on #3666 (and through it #3652).

Daemon halves (a) run against the package fakes and a new lifecycle-operations-spy.ts (the canned lifecycle port with finalizeApplicationClose as a spy). Assertions about what the real platform adapters or command code do (c) moved beside that code. The device-ready mocks and the patch of platform-runtime-apple-application-tools.ts are gone.

a / c split and test-count parity

Before = exact count at the old path (vitest JSON reporter on a clean tree); after = run count per destination on this head.

Source (before) Daemon half (a) Adapter / command half (c)
session-close-error-precedence (2) session-lifecycle/internal/__tests__/session-close-error-precedence.test.ts (3 → 5) packages/platform-apple/src/lifecycle-physical-close.test.ts (runner stop before a physical-device close)
session-close-save-script (1) .../session-close-save-script.test.ts (1 → 2) covered by platform-apple/lifecycle.test.ts
session-close-shutdown-platform (2) .../session-close-shutdown-platform.test.ts (5 → 7) platform-apple/lifecycle-physical-close.test.ts, platform-android/lifecycle.test.ts (+1): close --shutdown gating
session-teardown-resources (2) .../session-teardown-resources.test.ts (7 → 9) retention policy: src/platform-runtime-resource-cleanup-retention.test.ts in #3666
session-close-runtime-hints (4) .../session-close-lifecycle-runtime.test.ts (5 → 9) src/platform-runtime-android-application-tools.test.ts (2)
session-open-surface (1), session-open-target (4) none src/platform-runtime-open-target.test.ts (18)
session-open-existing (8) .../session-open-existing.test.ts (2 → 10) platform-runtime-open-target.test.ts; src/platform-runtime-apple-application-tools.test.ts (3, macOS frontmost)
session-open-post-open-observation (3) .../session-open-execution-runtime.test.ts (14 → 24, shared) platform-runtime-apple-application-tools.test.ts (runner prewarm forwarding)
session-open-url-prewarm (16) session-open-execution-runtime.test.ts (6 prewarm), sessions/handlers/__tests__/session-prepare.test.ts (3 → 8) platform-runtime-open-target.test.ts (5 URL identity), packages/platform-apple/src/lifecycle-open-prewarm.test.ts (5: cold-boot cache prewarm, Maestro simulator reset, blocking prewarm failure, no-bundle-id skip), apple tools prepareRunner
device/device-ready (5) core/device/device-ready.test.ts (6; +1: an unhandled device is not cached) src/platform-runtime-device-ready.test.ts (4)
replay-suite/session-test-suite-command-flag-policy (6) none src/commands/replay/index.test.ts (19 → 20, schema parity); packages/replay-port/src/daemon-port/test-command-flag-policy.test.ts (5, raw-wire rejections, no daemon)
replay-target/session-replay-target-guard (7) none git mv to src/commands/interaction/runtime/replay-target-guard.test.ts (5); replay-port/.../__tests__/target-classification.test.ts (17 → 19)

61 tests before; 229 pass across the destinations including pre-existing tests in the extended twins. The old session-open-url-prewarm URL-identity cases map one to one: web URL on a simulator with a stale app id → platform-runtime-open-target.test.ts "a web URL on an iOS simulator targets Safari whatever the active app is" plus the session-open-existing.test.ts row "a web URL on an iOS simulator session with a stale app bundle id"; URL on a macOS session clears the stale id → "a URL on a macOS session clears the stale app bundle id"; URL on an iOS device keeps the app → "a web URL on an iOS device keeps the active app context"; custom URL on an existing simulator → "a custom URL on %s keeps the active app bundle id"; custom URL on a fresh simulator infers from the scheme → "a custom URL on a fresh iOS simulator infers the app bundle id from the URL scheme". No case disappeared without a named owner.

Selection

All destinations match packages/*/src/**/*.test.ts or src/**/*.test.ts, so unit-core selects them (pnpm test:unit, test:coverage); the sources were already in unit-core. check:affected --run runs the vitest related leg over them.

vi.mock (each reads what its mock provided or recorded)

  • platform-runtime-android-application-tools.test.ts, ./platform-runtime-runtime-hints.ts: runtimeHints.evaluated is false after building the tools and true after clearRuntimeHints; clearRuntimeHintValues is called once with the device and app.
  • platform-runtime-apple-application-tools.test.ts, platform-apple/macos: the frontmost-app case returns the mocked { appBundleId: 'com.apple.TextEdit', appName: 'TextEdit' }.
  • same file, platform-apple/runner/operations: prewarmIosRunnerSession called with propagateError: false and the request id; prepareIosRunner called with the cleanStaleBundles and timeout fields.
  • platform-runtime-open-target.test.ts, platform-android/mechanics resolveAndroidPackageForOpen, platform-apple/app-resolution resolveIosApp and resolveIosSimulatorDeepLinkBundleId: each result is read through the returned id.
  • platform-runtime-device-ready.test.ts: host-kit/command (runCmd called once; its written JSON consumed), platform-apple/simulator (ensureBootedSimulator called with the device), platform-android/mechanics (waitForAndroidBoot called with the id).
  • Existing twin mocks are untouched; the root device-ready mocks (×3) are gone.

Subpath exports

Package Before (#3666) After
daemon 89 85

Deleted: __tests__/application-lifecycle-runtime-harness, __tests__/device-selection-stub, handlers/session-replay-command, session-lifecycle/internal/__tests__/*. No other package changed; no new subpath, barrel or export *.

Notes

  • packages/platform-apple/src/lifecycle.test.ts is back to its merge-base size (968 lines): the cases this batch adds live in two new files beside lifecycle.ts (lifecycle-open-prewarm.test.ts, lifecycle-physical-close.test.ts), because the test-file size ratchet fails a file over 1,000 lines that grows (46 + 5 + 2 = 53 tests, all passing).
  • Edits beyond packages/daemon and the daemon-composition tree are additive tests in platform-apple, platform-android, replay-port and src/commands/**, plus new src/platform-runtime-*.test.ts files; they carry rules the root fixture only wrapped. Say if any belongs to another worker.
  • The agent's own platform-runtime-resource-cleanup.test.ts retention tests were dropped in favor of refactor(daemon): relocate the handler tests by what they assert #3666's equivalent -retention file (same rules).

Validation

check:quick, check:layering, check:fallow and check:gate-manifest pass on this head; check:affected --run fails only test-file-size-ratchet on the pre-split head (fixed by the split above); test-file-size-ratchet passes after it.

🤖 Generated with Claude Code

View guided diff Turn on auto-fix

@cubic-dev-ai cubic-dev-ai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All reported issues were addressed across 36 files

Reply with feedback, questions, or to request a fix.

View guided diff | Turn on auto-fix | Re-trigger cubic

Comment thread packages/platform-apple/src/lifecycle-open-prewarm.test.ts
@thymikee
thymikee force-pushed the refactor/daemon-session-lifecycle-tests branch from a674acf to 29f06e4 Compare October 15, 2026 14:19
@thymikee
thymikee force-pushed the refactor/daemon-session-lifecycle-tests branch from 29f06e4 to e86468b Compare October 15, 2026 14:35
thymikee and others added 8 commits October 15, 2026 16:36
…tion

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
session-close-error-precedence: (a) daemon error precedence into the in-package twin
  with finalize spy; (c) apple pre-close runner stop into platform-apple lifecycle.test.
session-close-save-script: (a) into the in-package twin.
session-close-shutdown-platform: (a) daemon forwarding into the twin; (c) shutdown gating
  into platform-apple and platform-android lifecycle tests.
session-teardown-resources: (a) close-handler recording tests into the twin; (c) retention
  policy into src/platform-runtime-resource-cleanup.test.ts.
session-close-runtime-hints: (a) hint facts and clearing into session-close-lifecycle-runtime
  twin; (c) lazy runtime-hints load into src/platform-runtime-android-application-tools.test.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
session-open-surface, session-open-target: (c) merged into src/platform-runtime-open-target.test.ts.
session-open-existing: (a) resolved-identity storage, surface refusal and frontmost surface carry
  into the in-package session-open-existing twin; (c) open-target and surface rules into
  src/platform-runtime-open-target.test.ts, macOS frontmost resolution into
  src/platform-runtime-apple-application-tools.test.ts.
session-open-post-open-observation: (a) settle consequence of the observation verdict into the
  session-open-execution-runtime twin; (c) runner prewarm adapter into the apple tools test.
session-open-url-prewarm: (a) prewarm flag/timing/cold-boot request and the prepare response shape
  (session-open-execution-runtime twin, session-prepare twin); (c) URL identity rules into the
  open-target test, prepareRunner adapter into the apple tools test, cold-boot cache prewarm,
  Maestro simulator reset, blocking prewarm failure and no-bundle-id prewarm skip into
  platform-apple lifecycle.test.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rd composition tests

device-ready: (a) readiness cache/TTL contract against a spy port into
  packages/daemon/src/core/device/device-ready.test.ts; (c) per-family readiness mechanics into
  src/platform-runtime-device-ready.test.ts.
session-test-suite-command-flag-policy: (c) CLI-schema vs policy parity into
  src/commands/replay/index.test.ts; raw-wire rejections into
  packages/replay-port/src/daemon-port/test-command-flag-policy.test.ts (no daemon in the loop).
session-replay-target-guard: (c) post-resolution guard cases relocated to
  src/commands/interaction/runtime/replay-target-guard.test.ts; the two classifyReplayTarget
  verification cases move to replay-port target-classification.test.ts.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…atch left without importers

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
….ts so lifecycle.test.ts stays under the size tripwire

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… app-link case dispatch a URL

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee
thymikee force-pushed the refactor/daemon-session-lifecycle-tests branch from e86468b to f9d77d5 Compare October 15, 2026 14:36
@thymikee

Copy link
Copy Markdown
Member Author

The test relocation looks good overall, but one case from the old tests is missing at f9d77d5. The old session-open-url-prewarm.test.ts published an iOS simulator session with a stale app id (com.example.old), opened a web URL, and asserted the target became com.apple.mobilesafari with the stale id dropped. The new test.each in platform-runtime-open-target.test.ts passes no current app id for both the device and simulator rows, and the only "keeps the active app" case is iOS device only. A change that made the simulator branch of resolveIosBundleIdForOpen honor the current app id, as the device branch does, would pass every moved test. Could you add a simulator row with a stale current app id and a web URL that asserts com.apple.mobilesafari? The rule to check is that a web URL on a simulator always targets Safari whatever the current app is, and it should hold for every platform row in that test.each. Because this case disappeared, the "no case disappeared" claim in the PR body is not accurate yet. CI is still pending: all 13 non-passing checks are queued and none has failed. Once the case is back and CI is green, this should be ready to merge.

@github-actions

github-actions Bot commented Oct 15, 2026 •

Copy link
Copy Markdown
Contributor

Size Report

Metric Base Current Diff
Installed (including dependencies) 5.24 MB 5.24 MB 0 B
Package (unpacked) 5.24 MB 5.24 MB 0 B
Package (download) 1.57 MB 1.57 MB -11 B

Startup median (7 runs, lower is better):

Scenario Base Current Diff
CLI --version 29.4 ms 29.6 ms +0.2 ms
CLI --help 81.0 ms 83.2 ms +2.1 ms

@thymikee
thymikee added this pull request to stack #3681 October 15, 2026 15:46
…en-target module and in the existing-session table

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@thymikee

Copy link
Copy Markdown
Member Author

Restored in 4338018. The simulator web-URL-with-a-stale-app case is back in both halves: platform-runtime-open-target.test.ts 'a web URL on an iOS simulator targets Safari whatever the active app is' (stale id com.example.old, expects com.apple.mobilesafari) and a new row in the session-open-existing.test.ts table ('a web URL on an iOS simulator session with a stale app bundle id': the stale id is forwarded as currentAppBundleId and the session ends up on Safari). Mutation, as you described: making the simulator branch of resolveIosBundleIdForOpen return currentAppBundleId ?? IOS_SAFARI_BUNDLE_ID for web URLs fails the new test (1 failing); reverted. I mapped all five old URL-identity cases (macOS clear, device keep, custom URL keep, fresh-simulator inference, this one) in the PR body, so the 'no case disappeared' claim now has a named owner per case. Totals: 61 before, 229 passing across the destinations.

@thymikee

Copy link
Copy Markdown
Member Author

This PR is ready from review at 4338018. The finding from the earlier review (#3670 (comment)) is fixed, and nothing new came up in the 19 lines added to two test files, which touch no production route.

Not blocking, and fine to take or leave: the new stale-app simulator row in https://github.com/callstack/agent-device/blob/4338018/packages/daemon/src/sessions/session-lifecycle/internal/__tests__/session-open-existing.test.ts#L169 stubs resolveOpenTarget to return Safari. So the row passes even if the simulator branch ignored currentAppBundleId, and only the forwarding of the stale id is really checked. You could rename the label to say the stale id is forwarded to the resolver.

Both open inline threads from the other reviewer are fixed at this head, so you can resolve them. The call-history scoping in session-open-existing.test.ts is done with mockClear per case (#3670 (comment)). The session-prepare.test.ts thread was resolved earlier, and this delta does not touch it (#3670 (comment)).

I read the code and the tests. I did not run the tests or the mutation, and I did not re-check every old-to-new assertion mapping outside this case, which the earlier review covered. No checks have failed. All 17 remaining checks are still queued, so there is no run result yet. There are no conflicts. Once the queued checks go green, nothing else stands between this and merge.

@thymikee thymikee added the ready-for-human Valid work that needs human implementation, judgment, or maintainer merge label Oct 15, 2026
@thymikee
thymikee merged commit d000e71 into main Oct 15, 2026
20 checks passed
@thymikee
thymikee deleted the refactor/daemon-session-lifecycle-tests branch October 15, 2026 16:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready-for-human Valid work that needs human implementation, judgment, or maintainer merge

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant