From e280eb0734c2ffcc7d6f1105ead23235afc3e8df Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Sat, 7 Nov 2026 06:59:05 -0800 Subject: [PATCH] test: remove 125 low-value tests (#39513) * test: remove 124 low-value tests * test: remove 125 low-value tests --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- config/reliability-gates.jsonc | 27 +-- .../scripts/ci/sharding/ci-shard-timings.json | 9 - .../claude/claude-subagent-id-aliases.test.ts | 33 ---- .../cli/appimage-copy-pre-extraction.test.ts | 58 +----- src/main/cli/appimage-extracted-root.test.ts | 59 +----- ...ppimage-generation-stable-launcher.test.ts | 68 ------- ...ppimage-payload-removal.reentrancy.test.ts | 21 -- .../cli/appimage-serve-preparation.test.ts | 5 - .../cli-command-installation-races.test.ts | 11 -- ...cli-command-privileged-transaction.test.ts | 20 -- .../cli-installer-command-conflicts.test.ts | 27 --- .../cli/cli-installer-windows-path.test.ts | 68 ------- src/main/cli/cli-installer.test.ts | 161 +-------------- .../cli/legacy-appimage-cli-wrapper.test.ts | 7 - .../cli/linux-bare-orca-dispatcher.test.ts | 71 +------ .../cli/windows-user-path-registry.test.ts | 39 ---- .../remote-browser-page-input-model.test.ts | 19 -- .../remote-browser-service-failure.test.ts | 21 -- ...e-browser-stream-restart-scheduler.test.ts | 56 ------ .../use-remote-browser-page-keyboard.test.tsx | 16 +- ...use-remote-browser-page-navigation.test.ts | 46 ----- .../browser-webauthn-account-dialog.test.tsx | 17 +- .../palette-duplicate-key-ghost-rows.test.tsx | 60 ------ .../cmd-j/palette-filter-option-list.test.ts | 18 -- .../palette-focus-restore-target.test.ts | 10 - .../components/confirmation-dialog.test.tsx | 45 ----- .../confirmation-skip-preference.test.ts | 69 ------- ...request-contextual-tour-when-ready.test.ts | 62 ------ .../use-crash-report-copy.test.tsx | 18 -- .../agent-board-filtering.test.ts | 48 ----- .../preview-grid-claim.test.ts | 49 ----- ...preview-terminal-box-fit-lifecycle.test.ts | 59 ------ .../use-agent-dashboard-telemetry.test.ts | 136 ------------- .../dashboard/useAgentBucketCounts.test.tsx | 74 ------- .../dictation-insertion-target.test.ts | 46 ----- src/shared/libproc-process-table.test.ts | 69 ------- src/shared/linear/inline-media.test.ts | 47 ----- .../linear/issue-attribute-filter.test.ts | 9 - .../linear/issue-view-resume-state.test.ts | 183 +----------------- src/shared/linear/links.test.ts | 90 +-------- src/shared/linear/workspace-types.test.ts | 34 ---- src/shared/linux-wayland-session.test.ts | 31 --- .../local-windows-terminal-runtime.test.ts | 5 - src/shared/locale-text-collators.test.ts | 77 -------- src/shared/localhost-worktree-labels.test.ts | 15 +- src/shared/loose-ref-count.test.ts | 29 --- src/shared/machine-name.test.ts | 20 -- src/shared/macos-symbolic-hotkeys.test.ts | 14 -- .../managed-orcad-execution-host.test.ts | 13 -- src/shared/managed-orcad-ssh-owner.test.ts | 15 +- src/shared/manual-repo-order.test.ts | 41 ---- src/shared/map-with-concurrency.test.ts | 17 -- ...-model-catalog-renderer-cache.unit.test.ts | 37 ---- .../e2e/ai-vault-account-stream.unit.test.ts | 134 +------------ 54 files changed, 23 insertions(+), 2410 deletions(-) delete mode 100644 src/main/cli/appimage-generation-stable-launcher.test.ts delete mode 100644 src/renderer/src/components/cmd-j/palette-duplicate-key-ghost-rows.test.tsx delete mode 100644 src/renderer/src/components/confirmation-skip-preference.test.ts delete mode 100644 src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts delete mode 100644 src/renderer/src/components/dashboard-popout/preview-grid-claim.test.ts delete mode 100644 src/renderer/src/components/dashboard/useAgentBucketCounts.test.tsx delete mode 100644 src/shared/linear/inline-media.test.ts delete mode 100644 src/shared/locale-text-collators.test.ts delete mode 100644 src/shared/machine-name.test.ts diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index fb99a81d7c1..86379ba93e9 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -6224,13 +6224,13 @@ "providers": ["remote-runtime"], "coveredPlatforms": ["macos", "linux"], "coveredProviders": ["remote-runtime"], - "coverageNotes": "Deterministic fake-clock tests cover counted backoff, in-flight ownership and handoff, cancellation, supersession, transient and permanent failures, late stale rejection, silent hosts, flapping streams, viewport restarts, stale events, budget exhaustion, and manual recovery. A headless paired-runtime journey drops the real runtime connection, proves the bounded retry state and visible Reconnect control, reconnects the same host, and requires a newly painted frame. Headed paired-server, Windows, sleep/wake, and real network-partition evidence remain uncollected.", + "coverageNotes": "The retained fake-clock scheduler cases check bounded exhaustion, rejected attempts continuing to exhaustion, in-flight cancellation, and one queued replacement chain. Direct transient-success counted-delay, healthy-budget reset, and pending-cancellation cases were removed. Existing lifecycle and paired-runtime coverage remain separate and were not re-reviewed as equivalent replacements in this audit. The historical headless paired journey disconnects the real runtime, shows Reconnect, reconnects the same host, and requires a new frame. Headed paired-server, Windows, sleep/wake, and real network-partition evidence remain uncollected.", "motivatingLinks": [ "https://github.com/stablyai/orca/pull/12787", "https://linear.app/stably/issue/STA-3483" ], "invariant": "A current remote browser stream that closes must retry transient failures on one counted, capped backoff chain. Cancellation, pane or runtime supersession, missing pages, and permanent failures stop that chain without stale state mutation. A stream that stays healthy refills the budget; a silent or flapping stream cannot retry forever. Exhaustion and every non-retrying failure leave an actionable Reconnect control, and manual reconnect creates a fresh stream without resurrecting stale subscriptions.", - "oracle": "With one fake clock and exact pane, operation, stream, page, and runtime identities, drop a confirmed stream and require the counted delay sequence, one active chain, stale-token rejection, exact cancellation, full cleanup, and either a new live subscription or one stopped state with Reconnect after exhaustion. Inject transport error without close, close racing rejection, never-ready subscriptions, ready-then-end flapping, viewport supersession, missing pages, and permanent failures. In a separate paired client against an isolated headless Orca host, paint one remote frame, disconnect the owning runtime, require the bounded-retry notice and Reconnect control, reconnect, click once, and require a different frame object URL from the recovered stream.", + "oracle": "The retained direct scheduler oracles require finite exhaustion, continuation after rejected attempts, cancellation of in-flight ownership without re-arming, and one queued replacement chain. Existing lifecycle assertions separately describe stale pane/operation/stream/page/runtime refusal, liveness, and manual recovery; they are not claimed equivalent to removed direct scheduler cases. The paired-runtime oracle paints a remote frame, disconnects its owning runtime, observes the bounded-retry notice and Reconnect control, reconnects, and requires a different frame object URL.", "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-lifecycle.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts", "pnpm exec playwright test tests/e2e/paired-remote-browser-stream-reconnect.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1" @@ -6244,10 +6244,10 @@ { "file": "src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts", "assertions": [ - "transient failures retry until recovery on counted delays", "budget exhaustion stops exactly once", "cancellation retires an in-flight attempt without re-arming", - "a close during an in-flight attempt queues one replacement chain" + "a close during an in-flight attempt queues one replacement chain", + "rejected attempts continue until budget exhaustion" ] }, { @@ -6269,16 +6269,6 @@ } ], "evidenceRuns": [ - { - "date": "2026-08-07", - "runner": "local", - "platform": "macos", - "command": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-errors.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-lifecycle.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-status.test.ts", - "currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-lifecycle.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts", - "result": "passed", - "durationSeconds": 0.36, - "summary": "Four focused files passed 61 deterministic error, status, scheduler, lifecycle, in-flight ownership, stale-rejection, liveness, and cleanup tests." - }, { "date": "2026-08-07", "runner": "ci", @@ -6298,8 +6288,8 @@ "evidence": "The deterministic suite and one changed-E2E CI run passed; soak history has not started." }, "redGreenEvidence": { - "status": "complete", - "evidence": "The byte-identical scheduler oracle fails with the reschedule disabled at one attempt instead of four and passes after restoration. On the PR head, the delayed handoff oracle counted two scheduled attempts instead of one, and the late stale-rejection oracle lost the replacement ready deadline and never offered reconnect; both pass after the ownership fixes. Current main structurally contains the original one-shot timer dead end. The focused suite passes 61 tests, and the isolated paired-runtime CI journey passes both disconnect and cold-open recovery scenarios." + "status": "partial", + "evidence": "The direct one-versus-four transient-success mutation oracle was removed. Historical handoff and stale-lifecycle mutation descriptions are preserved below as provenance; no fresh mutation run validates the reduced scheduler suite or supplies equivalent replacement coverage." }, "performanceBudget": { "required": true, @@ -6315,7 +6305,10 @@ "The paired journey covers headless orca serve, not the primary headed desktop-server topology.", "The live fault is an explicit disconnect rather than sleep/wake or a real network partition.", "The E2E observes UI convergence and new frame identity but does not count screencast subscribe attempts directly.", - "Live Linux and Windows evidence is uncollected." + "Live Linux and Windows evidence is uncollected.", + "Audit1833 removed direct transient-success counted-delay, healthy-budget reset, and pending-cancellation cases. No equivalent lifecycle coverage is claimed.", + "Audit1833 retires this complete dated local receipt because the selected scheduler was reduced; its 61 tests and currentCommand are not current candidate validation. Original receipt verbatim: {\"date\":\"2026-08-07\",\"runner\":\"local\",\"platform\":\"macos\",\"command\":\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-errors.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-lifecycle.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-status.test.ts\",\"currentCommand\":\"pnpm exec vitest run --config config/vitest.config.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-lifecycle.test.ts src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts\",\"result\":\"passed\",\"durationSeconds\":0.36,\"summary\":\"Four focused files passed 61 deterministic error, status, scheduler, lifecycle, in-flight ownership, stale-rejection, liveness, and cleanup tests.\"}", + "Historical red/green description retired from current completeness evidence, not re-executed by audit1833: {\"status\":\"complete\",\"evidence\":\"The byte-identical scheduler oracle fails with the reschedule disabled at one attempt instead of four and passes after restoration. On the PR head, the delayed handoff oracle counted two scheduled attempts instead of one, and the late stale-rejection oracle lost the replacement ready deadline and never offered reconnect; both pass after the ownership fixes. Current main structurally contains the original one-shot timer dead end. The focused suite passes 61 tests, and the isolated paired-runtime CI journey passes both disconnect and cold-open recovery scenarios.\"}" ], "demotionRule": "Keep experimental or demote if retries can stop before recovery or exhaustion, continue after exhaustion, run in parallel, mutate a superseded pane, hide the Reconnect control, leak a subscription or timer, or fail to paint a new frame after manual reconnect." }, diff --git a/config/scripts/ci/sharding/ci-shard-timings.json b/config/scripts/ci/sharding/ci-shard-timings.json index ba60b2e44f4..5ebe23a20dc 100644 --- a/config/scripts/ci/sharding/ci-shard-timings.json +++ b/config/scripts/ci/sharding/ci-shard-timings.json @@ -1340,7 +1340,6 @@ "src/main/cli/appimage-extraction-pruning.test.ts": 117, "src/main/cli/appimage-generation-lease.test.ts": 75, "src/main/cli/appimage-generation-residency.test.ts": 41, - "src/main/cli/appimage-generation-stable-launcher.test.ts": 163, "src/main/cli/appimage-payload-removal.reentrancy.test.ts": 46, "src/main/cli/appimage-serve-preparation.test.ts": 123, "src/main/cli/appimage-stable-launcher.test.ts": 135, @@ -5700,7 +5699,6 @@ "src/renderer/src/components/browser-pane/workspace-doc/doc-preview-webview-attach.test.ts": 200, "src/renderer/src/components/browser-pane/workspace-doc/use-doc-preview-guest-tools.test.ts": 439, "src/renderer/src/components/browser-webauthn-account-dialog.test.tsx": 484, - "src/renderer/src/components/cmd-j/palette-duplicate-key-ghost-rows.test.tsx": 230, "src/renderer/src/components/cmd-j/palette-filter-option-list.test.ts": 44, "src/renderer/src/components/cmd-j/palette-focus-restore-target.test.ts": 186, "src/renderer/src/components/cmd-j/palette-list-entry-render-keys.test.ts": 45, @@ -5709,7 +5707,6 @@ "src/renderer/src/components/codex-restart-chip.test.tsx": 2105, "src/renderer/src/components/comment-code-context-state.test.ts": 41, "src/renderer/src/components/confirmation-dialog.test.tsx": 1231, - "src/renderer/src/components/confirmation-skip-preference.test.ts": 157, "src/renderer/src/components/connect-dialog-outside-dismiss.test.tsx": 1125, "src/renderer/src/components/contextual-tours/ContextualTourOverlay.visibility.test.tsx": 2101, "src/renderer/src/components/contextual-tours/request-contextual-tour-when-ready.test.ts": 1798, @@ -5722,10 +5719,8 @@ "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-geometry.test.tsx": 2194, "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.settings-lifetime.test.tsx": 2488, "src/renderer/src/components/dashboard-popout/AgentTerminalPreview.test.tsx": 3334, - "src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts": 48, "src/renderer/src/components/dashboard-popout/dashboard-agent-status-patch.test.ts": 74, "src/renderer/src/components/dashboard-popout/dashboard-preview-link-composition.test.tsx": 8657, - "src/renderer/src/components/dashboard-popout/preview-grid-claim.test.ts": 436, "src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts": 192, "src/renderer/src/components/dashboard-popout/preview-terminal-ime-bridge-kitty-bytes.test.ts": 479, "src/renderer/src/components/dashboard-popout/remote-runtime-terminal-preview-api.test.ts": 81, @@ -5741,7 +5736,6 @@ "src/renderer/src/components/dashboard/build-dashboard-snapshot.rows-cache.test.ts": 3640, "src/renderer/src/components/dashboard/build-dashboard-snapshot.test.ts": 2121, "src/renderer/src/components/dashboard/reveal-dashboard-agent.test.ts": 1098, - "src/renderer/src/components/dashboard/useAgentBucketCounts.test.tsx": 318, "src/renderer/src/components/dashboard/useLiveDashboardSnapshot.test.ts": 3346, "src/renderer/src/components/dashboard/useRetainedAgents.test.ts": 2028, "src/renderer/src/components/dictation/dictation-insertion-target.test.ts": 323, @@ -8772,7 +8766,6 @@ "src/shared/libproc-process-table-real-ps.test.ts": 75, "src/shared/libproc-process-table.test.ts": 241, "src/shared/libproc-ps-fallback.test.ts": 184, - "src/shared/linear/inline-media.test.ts": 38, "src/shared/linear/issue-attribute-filter.test.ts": 49, "src/shared/linear/issue-view-resume-state.test.ts": 80, "src/shared/linear/links.test.ts": 58, @@ -8780,10 +8773,8 @@ "src/shared/linux-wayland-session.test.ts": 46, "src/shared/local-build-compatibility.test.ts": 46, "src/shared/local-windows-terminal-runtime.test.ts": 41, - "src/shared/locale-text-collators.test.ts": 54, "src/shared/localhost-worktree-labels.test.ts": 41, "src/shared/loose-ref-count.test.ts": 140, - "src/shared/machine-name.test.ts": 43, "src/shared/macos-symbolic-hotkeys.test.ts": 95, "src/shared/managed-agent-command-token.test.ts": 45, "src/shared/managed-orcad-execution-host.test.ts": 170, diff --git a/src/main/claude/claude-subagent-id-aliases.test.ts b/src/main/claude/claude-subagent-id-aliases.test.ts index 89005f524a0..842cedf4ff9 100644 --- a/src/main/claude/claude-subagent-id-aliases.test.ts +++ b/src/main/claude/claude-subagent-id-aliases.test.ts @@ -1,39 +1,6 @@ import { describe, expect, it } from 'vitest' import { ClaudeSubagentIds } from './claude-subagent-id-aliases' -describe('ClaudeSubagentIds', () => { - it('drops the oldest alias past the bound and keeps the newest', () => { - const ids = new ClaudeSubagentIds() - for (let index = 0; index <= 512; index += 1) { - ids.alias(`toolu_${index}`, `task-${index}`) - } - expect(ids.canonical('toolu_0')).toBe('toolu_0') - expect(ids.canonical('toolu_512')).toBe('task-512') - expect(ids.canonical('toolu_1')).toBe('task-1') - }) - - it('drops the oldest exclusion past the bound and keeps the newest', () => { - const ids = new ClaudeSubagentIds() - for (let index = 0; index <= 512; index += 1) { - ids.exclude(`task-${index}`) - } - expect(ids.isExcluded('task-0')).toBe(false) - expect(ids.isExcluded('task-512')).toBe(true) - expect(ids.isExcluded('task-1')).toBe(true) - }) - - it('does not retain oversized aliases or exclusions', () => { - const ids = new ClaudeSubagentIds() - const oversized = 'x'.repeat(513) - ids.alias(oversized, 'task-1') - ids.alias('tool-1', oversized) - ids.exclude(oversized) - expect(ids.canonical(oversized)).toBe(oversized) - expect(ids.canonical('tool-1')).toBe('tool-1') - expect(ids.isExcluded(oversized)).toBe(false) - }) -}) - describe('ClaudeSubagentIds with an earlier run journaled', () => { it("prefers what this run was told, and falls back to the earlier run's alias", () => { const ids = new ClaudeSubagentIds((toolUseId) => diff --git a/src/main/cli/appimage-copy-pre-extraction.test.ts b/src/main/cli/appimage-copy-pre-extraction.test.ts index b6a5859219e..cc7df714320 100644 --- a/src/main/cli/appimage-copy-pre-extraction.test.ts +++ b/src/main/cli/appimage-copy-pre-extraction.test.ts @@ -1,7 +1,7 @@ import { existsSync } from 'node:fs' import { mkdir, mkdtemp, rename, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { dirname, join } from 'node:path' +import { join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { resolveAppImageExtractedRoot } from './appimage-extracted-root' import { resolveAppImageLauncherEndpointPath } from './appimage-stable-launcher' @@ -59,62 +59,6 @@ describe('startAppImageCopyPreExtraction', () => { expect(existsSync(resolveAppImageLauncherEndpointPath(cacheRootPath, 'installed'))).toBe(false) expect(lines.at(-1)).toContain('Unpacked this AppImage') }) - - it('drops idle copies of earlier releases once this one has its copy', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - const copy = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - const earlier = join(dirname(copy.rootPath), 'a'.repeat(24)) - await mkdir(join(earlier, 'resources', 'bin'), { recursive: true }) - await writeFile(join(earlier, 'resources', 'bin', 'orca-ide'), '', { mode: 0o755 }) - - const started = preExtraction.startAppImageCopyPreExtraction({ - appImagePath, - cacheRootPath, - probeCache: acceptCache, - runExtract: async (_path, cwd) => writePayload(cwd), - log: () => {} - }) - - expect(await started).toBe(true) - await vi.waitFor(() => expect(existsSync(earlier)).toBe(false)) - expect(existsSync(copy.payloadLauncherPath)).toBe(true) - }) - - it('drops idle earlier copies at a launch that already has its copy', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - const copy = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - await mkdir(join(copy.rootPath, 'resources', 'bin'), { recursive: true }) - await writeFile(copy.payloadLauncherPath, '', { mode: 0o755 }) - const earlier = join(dirname(copy.rootPath), 'b'.repeat(24)) - await mkdir(join(earlier, 'resources', 'bin'), { recursive: true }) - - expect(preExtraction.startAppImageCopyPreExtraction({ appImagePath, cacheRootPath })).toBeNull() - await vi.waitFor(() => expect(existsSync(earlier)).toBe(false)) - expect(existsSync(copy.payloadLauncherPath)).toBe(true) - }) - - it('stops waiting at the bound while the copy is still unpacking', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - let finish: () => void = () => {} - const extracting = new Promise((resolve) => { - finish = resolve - }) - - const started = preExtraction.startAppImageCopyPreExtraction({ - appImagePath, - cacheRootPath, - probeCache: acceptCache, - runExtract: async (_path, cwd) => { - await extracting - await writePayload(cwd) - }, - log: () => {} - }) - - expect(await preExtraction.waitForAppImageCopyPreExtraction(20)).toBe(false) - finish() - expect(await started).toBe(true) - }) }) describe('preExtractDownloadedAppImageUpdate', () => { diff --git a/src/main/cli/appimage-extracted-root.test.ts b/src/main/cli/appimage-extracted-root.test.ts index c3794992ae1..d30914ddd4c 100644 --- a/src/main/cli/appimage-extracted-root.test.ts +++ b/src/main/cli/appimage-extracted-root.test.ts @@ -1,20 +1,15 @@ import { existsSync } from 'node:fs' -import { chmod, mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from 'node:fs/promises' +import { mkdir, mkdtemp, readFile, readdir, rm, symlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' import { dirname, join } from 'node:path' import { afterEach, describe, expect, it } from 'vitest' import { ensureAppImageExtractedRoot, - isAppImageInstalledLauncherOwnedBySibling, readAppImageSourceOfNamespace, - resolveAppImageCacheKey, resolveAppImageExtractedRoot } from './appimage-extracted-root' import { getAppImageActiveExtractionPath } from './appimage-extraction-pruning' -import { - publishAppImageLauncherEndpoint, - resolveAppImageStableLauncherPath -} from './appimage-stable-launcher' +import { resolveAppImageStableLauncherPath } from './appimage-stable-launcher' const created: string[] = [] @@ -58,18 +53,6 @@ describe('appimage extracted root', () => { expect(readAppImageSourceOfNamespace(cacheRootPath, namespaceKey)).toBeNull() }) - // chmod, backup restores and SELinux relabels must not trigger re-extraction of unchanged payloads. - it('does not re-key the payload when only inode metadata changes', async () => { - const { appImagePath } = await makeFixture() - const before = resolveAppImageCacheKey(appImagePath) - - await chmod(appImagePath, 0o700) - expect(resolveAppImageCacheKey(appImagePath)).toBe(before) - - await chmod(appImagePath, 0o755) - expect(resolveAppImageCacheKey(appImagePath)).toBe(before) - }) - it('publishes nothing when extraction fails partway', async () => { const { appImagePath, cacheRootPath } = await makeFixture() @@ -207,42 +190,4 @@ describe('appimage extracted root', () => { await expect(readFile(currentRoot.payloadLauncherPath, 'utf8')).resolves.toBe('generation-2') expect(existsSync(initialRoot.rootPath)).toBe(false) }) - - it('bounds retries when every extraction changes the AppImage generation', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - let extractCount = 0 - - const result = await ensureAppImageExtractedRoot({ - appImagePath, - cacheRootPath, - runExtract: async (_path, cwd) => { - extractCount += 1 - await writePayload(cwd) - await writeFile(appImagePath, '#'.repeat(extractCount + 1), { mode: 0o755 }) - } - }) - - expect(result).toBeNull() - expect(extractCount).toBe(2) - }) - - it('requires a sibling installed endpoint to target an executable payload', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - const siblingLauncher = join( - cacheRootPath, - 'a'.repeat(24), - 'b'.repeat(24), - 'resources', - 'bin', - 'orca-ide' - ) - publishAppImageLauncherEndpoint(cacheRootPath, 'installed', siblingLauncher) - const options = { appImagePath, cacheRootPath } - - expect(isAppImageInstalledLauncherOwnedBySibling(options)).toBe(false) - - await mkdir(dirname(siblingLauncher), { recursive: true }) - await writeFile(siblingLauncher, '#!/usr/bin/env bash\n', { mode: 0o755 }) - expect(isAppImageInstalledLauncherOwnedBySibling(options)).toBe(true) - }) }) diff --git a/src/main/cli/appimage-generation-stable-launcher.test.ts b/src/main/cli/appimage-generation-stable-launcher.test.ts deleted file mode 100644 index 2d87479b239..00000000000 --- a/src/main/cli/appimage-generation-stable-launcher.test.ts +++ /dev/null @@ -1,68 +0,0 @@ -import { mkdir, mkdtemp, rm, symlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, describe, expect, it, vi } from 'vitest' -import { - ensureAppImageStableLauncher, - resolveAppImageStableLauncherPath -} from './appimage-stable-launcher' - -vi.mock('electron', () => ({ - app: { isPackaged: true, getPath: () => tmpdir(), getAppPath: () => tmpdir() } -})) - -import { CliInstaller } from './cli-installer' - -const created: string[] = [] - -afterEach(async () => { - vi.unstubAllEnvs() - await Promise.all(created.splice(0).map((root) => rm(root, { recursive: true, force: true }))) -}) - -async function makeGeneration() { - const root = await mkdtemp(join(tmpdir(), 'orca-generation-launcher-')) - created.push(root) - const cacheRootPath = join(root, 'cache', 'orca', 'appimage') - const generationRoot = join(cacheRootPath, 'a'.repeat(24), 'b'.repeat(24)) - const resourcesPath = join(generationRoot, 'resources') - await mkdir(join(resourcesPath, 'bin'), { recursive: true }) - await writeFile(join(resourcesPath, 'bin', 'orca-ide'), '#!/usr/bin/env bash\n', { mode: 0o755 }) - await writeFile(join(generationRoot, 'orca-ide'), '', { mode: 0o755 }) - expect(ensureAppImageStableLauncher(cacheRootPath)).toBe( - resolveAppImageStableLauncherPath(cacheRootPath) - ) - vi.stubEnv('APPIMAGE', '') - vi.stubEnv('APPDIR', '') - return { - homePath: join(root, 'home'), - resourcesPath, - generationRoot, - stableLauncherPath: resolveAppImageStableLauncherPath(cacheRootPath) - } -} - -describe.skipIf(process.platform === 'win32')( - 'CLI registration from an extracted generation', - () => { - it('recognises the stable launcher it registered as its own `orca-ide`', async () => { - const fixture = await makeGeneration() - const commandDirectory = join(fixture.homePath, '.local', 'bin') - await mkdir(commandDirectory, { recursive: true }) - await symlink(fixture.stableLauncherPath, join(commandDirectory, 'orca-ide')) - const installer = new CliInstaller({ - platform: 'linux', - isPackaged: true, - userDataPath: join(fixture.homePath, 'user-data'), - resourcesPath: fixture.resourcesPath, - execPath: join(fixture.generationRoot, 'orca-ide'), - appPath: join(fixture.resourcesPath, 'app.asar'), - homePath: fixture.homePath, - processPathEnv: commandDirectory - }) - const status = await installer.install() - expect(status.state).toBe('installed') - expect(status.commandPath).toBe(join(commandDirectory, 'orca-ide')) - }) - } -) diff --git a/src/main/cli/appimage-payload-removal.reentrancy.test.ts b/src/main/cli/appimage-payload-removal.reentrancy.test.ts index d80d496b0aa..d144758d378 100644 --- a/src/main/cli/appimage-payload-removal.reentrancy.test.ts +++ b/src/main/cli/appimage-payload-removal.reentrancy.test.ts @@ -20,27 +20,6 @@ function deferred(): { promise: Promise; resolve: () => void } { } describe('removeExtractedAppImagePayload reentrancy', () => { - it('keeps asar interception disabled while a later removal is still running', async () => { - process.noAsar = false - const first = deferred() - const second = deferred() - rmMock.mockReset() - rmMock.mockReturnValueOnce(first.promise).mockReturnValueOnce(second.promise) - const { removeExtractedAppImagePayload } = await import('./appimage-payload-removal') - - const firstCall = removeExtractedAppImagePayload('/cache/gen-a') - const secondCall = removeExtractedAppImagePayload('/cache/gen-b') - expect(process.noAsar).toBe(true) - - first.resolve() - await firstCall - expect(process.noAsar).toBe(true) - - second.resolve() - await secondCall - expect(process.noAsar).toBe(false) - }) - it('keeps the flag held when the first removal rejects mid-overlap', async () => { process.noAsar = false const second = deferred() diff --git a/src/main/cli/appimage-serve-preparation.test.ts b/src/main/cli/appimage-serve-preparation.test.ts index b70e01eb73e..2c03e0bda91 100644 --- a/src/main/cli/appimage-serve-preparation.test.ts +++ b/src/main/cli/appimage-serve-preparation.test.ts @@ -21,11 +21,6 @@ async function makeFixture() { // POSIX permissions and shebang execution are what the probe measures. describe.skipIf(process.platform === 'win32')('probeAppImageCache', () => { - it('accepts a private, writable cache that can run programs', async () => { - const { appImagePath, cacheRootPath } = await makeFixture() - await expect(probeAppImageCache(cacheRootPath, appImagePath)).resolves.toBeNull() - }) - it('refuses a cache other users can write to', async () => { const { appImagePath, cacheRootPath } = await makeFixture() await mkdir(cacheRootPath, { recursive: true }) diff --git a/src/main/cli/cli-command-installation-races.test.ts b/src/main/cli/cli-command-installation-races.test.ts index 34c7f6dfe7d..88dbfce5ae8 100644 --- a/src/main/cli/cli-command-installation-races.test.ts +++ b/src/main/cli/cli-command-installation-races.test.ts @@ -154,17 +154,6 @@ async function rejectionFrom(operation: Promise): Promise { } describe.skipIf(process.platform === 'win32')('CLI command filesystem races', () => { - it('replaces and removes an unchanged stale symlink through the real filesystem', async () => { - const fixture = await createMacCommandFixture() - await symlink(fixture.staleLauncherPath, fixture.commandPath) - const installer = createMacInstaller(fixture) - - await expect(installer.install()).resolves.toMatchObject({ state: 'installed' }) - await expect(readlink(fixture.commandPath)).resolves.toBe(fixture.launcherPath) - await expect(installer.remove()).resolves.toMatchObject({ state: 'not_installed' }) - await expect(lstat(fixture.commandPath)).rejects.toMatchObject({ code: 'ENOENT' }) - }) - it('restores a foreign symlink whose quarantined inode identity is reused', async () => { const fixture = await createMacCommandFixture() const foreignTarget = join(fixture.root, 'foreign-command') diff --git a/src/main/cli/cli-command-privileged-transaction.test.ts b/src/main/cli/cli-command-privileged-transaction.test.ts index 49c58788a08..6fbf63644ad 100644 --- a/src/main/cli/cli-command-privileged-transaction.test.ts +++ b/src/main/cli/cli-command-privileged-transaction.test.ts @@ -167,26 +167,6 @@ describe.skipIf(process.platform !== 'darwin' || process.getuid?.() === 0)( ).toBe(false) }) - it('creates missing parent directories readable by the user', async () => { - const fixture = await createPrivilegedFixture() - const commandPath = join(fixture.protectedDirectory, 'nested', 'bin', 'orca') - const installer = new CliInstaller({ - ...fixtureInstallerOptions(fixture), - commandPathOverride: commandPath, - privilegedRunner: async (command) => { - await chmod(fixture.protectedDirectory, 0o700) - await executePrivilegedShell(command) - } - }) - - await chmod(fixture.protectedDirectory, 0o500) - await expect(installer.install()).resolves.toMatchObject({ state: 'installed' }) - expect((await lstat(join(fixture.protectedDirectory, 'nested'))).mode & 0o777).toBe(0o755) - expect((await lstat(join(fixture.protectedDirectory, 'nested', 'bin'))).mode & 0o777).toBe( - 0o755 - ) - }) - it('makes an unreadable link to the current launcher readable with one privileged step', async () => { const fixture = await createPrivilegedFixture() const commands: string[] = [] diff --git a/src/main/cli/cli-installer-command-conflicts.test.ts b/src/main/cli/cli-installer-command-conflicts.test.ts index 75e8b10aae9..f5ee0e5328a 100644 --- a/src/main/cli/cli-installer-command-conflicts.test.ts +++ b/src/main/cli/cli-installer-command-conflicts.test.ts @@ -30,33 +30,6 @@ describe('CliInstaller', () => { vi.restoreAllMocks() }) - it.skipIf(process.platform === 'win32')( - 'refuses to replace an unknown symlink at the command path', - async () => { - const fixture = await makeFixture() - const installPath = join(fixture.root, 'bin', 'orca') - const existingTarget = '/tmp/not-orca' - await mkdir(join(fixture.root, 'bin'), { recursive: true }) - await symlink(existingTarget, installPath) - - const installer = new CliInstaller({ - platform: 'darwin', - isPackaged: false, - userDataPath: fixture.userDataPath, - execPath: '/Applications/Orca.app/Contents/MacOS/Orca', - appPath: fixture.appPath, - commandPathOverride: installPath - }) - - await expect(installer.getStatus()).resolves.toMatchObject({ - state: 'conflict', - supported: true - }) - await expect(installer.install()).rejects.toThrow('Refusing to replace non-Orca command') - await expect(readlink(installPath)).resolves.toBe(existingTarget) - } - ) - // Older builds wrote generated launcher files directly into /usr/local/bin/orca. it.skipIf(process.platform === 'win32')( 'replaces stale generated Unix launcher files', diff --git a/src/main/cli/cli-installer-windows-path.test.ts b/src/main/cli/cli-installer-windows-path.test.ts index 7d038c930f3..a0c7f5063f4 100644 --- a/src/main/cli/cli-installer-windows-path.test.ts +++ b/src/main/cli/cli-installer-windows-path.test.ts @@ -28,74 +28,6 @@ describe('CliInstaller', () => { vi.restoreAllMocks() }) - it('creates a windows wrapper and updates the user PATH', async () => { - const fixture = await makeFixture() - const installPath = join(fixture.root, 'Programs', 'Orca', 'bin', 'orca.cmd') - let userPath = 'C:\\Windows\\System32' - const installer = new CliInstaller({ - platform: 'win32', - isPackaged: false, - userDataPath: fixture.userDataPath, - execPath: 'C:\\Users\\me\\AppData\\Local\\Orca\\Orca.exe', - appPath: fixture.appPath, - commandPathOverride: installPath, - userPathReader: async () => userPathRead(userPath), - userPathWriter: async (value) => { - userPath = value - } - }) - - const installed = await installer.install() - expect(installed.state).toBe('installed') - expect(installed.pathConfigured).toBe(true) - expect(userPath).toContain(join(fixture.root, 'Programs', 'Orca', 'bin')) - - const wrapperContent = await readFile(installPath, 'utf8') - expect(wrapperContent).toContain('ORCA_LAUNCHER=') - expect(wrapperContent).toContain('orca.cmd') - const launcherContent = await readFile(installed.launcherPath as string, 'utf8') - expect(launcherContent).toContain(`set "ORCA_USER_DATA_PATH=${fixture.userDataPath}"`) - expect(launcherContent).toContain('set "ORCA_APP_EXECUTABLE=%ELECTRON%"') - - const removed = await installer.remove() - expect(removed.state).toBe('not_installed') - expect(userPath).not.toContain(join(fixture.root, 'Programs', 'Orca', 'bin')) - }) - - it.each(['UnauthorizedAccessException', 'SecurityException'])( - 'rejects with a friendly message for Windows PATH denial: %s', - async (permissionMarker) => { - const fixture = await makeFixture() - const installPath = join(fixture.root, 'Programs', 'Orca', 'bin', 'orca.cmd') - const installer = new CliInstaller({ - platform: 'win32', - isPackaged: false, - userDataPath: fixture.userDataPath, - execPath: 'C:\\Users\\me\\AppData\\Local\\Orca\\Orca.exe', - appPath: fixture.appPath, - commandPathOverride: installPath, - userPathReader: async () => userPathRead('C:\\Windows\\System32'), - userPathWriter: async () => { - // The .NET error id survives localized or mojibake PowerShell output. - const error = new Error( - `Command failed: powershell -NoProfile -Command [Environment]::SetEnvironmentVariable('Path', '...', 'User')\nFullyQualifiedErrorId : ${permissionMarker},Microsoft.PowerShell.Commands` - ) - Object.assign(error, { code: 1 }) - throw error - } - }) - - const result = installer.install() - await expect(result).rejects.toThrow(/access denied|Group Policy|manually/i) - await expect(result).rejects.not.toThrow(/Command failed: powershell/) - await expect(result).rejects.toMatchObject({ - cause: expect.objectContaining({ - message: expect.stringContaining(permissionMarker) - }) - }) - } - ) - it('fails closed without writing when a Windows PATH mutation cannot read the registry', async () => { const fixture = await makeFixture() const userPathWriter = vi.fn() diff --git a/src/main/cli/cli-installer.test.ts b/src/main/cli/cli-installer.test.ts index f403339b4e4..40bbed18e1d 100644 --- a/src/main/cli/cli-installer.test.ts +++ b/src/main/cli/cli-installer.test.ts @@ -1,7 +1,6 @@ -import { existsSync } from 'node:fs' -import { lstat, mkdir, readFile, readdir, readlink, rm, symlink, writeFile } from 'node:fs/promises' +import { lstat, mkdir, readFile, readdir, readlink, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { basename, dirname, join, relative, sep } from 'node:path' +import { basename, dirname, join } from 'node:path' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const execFileMock = vi.hoisted(() => vi.fn()) @@ -43,36 +42,6 @@ describe('CliInstaller', () => { vi.restoreAllMocks() }) - it.skipIf(process.platform === 'win32')( - 'creates a linux symlink under the requested path and warns when PATH is missing', - async () => { - const fixture = await makeFixture() - const installPath = join(fixture.root, '.local', 'bin', 'orca-ide') - const installer = new CliInstaller({ - platform: 'linux', - isPackaged: false, - userDataPath: fixture.userDataPath, - execPath: '/opt/Orca/orca-ide', - appPath: fixture.appPath, - commandPathOverride: installPath, - processPathEnv: '/usr/bin' - }) - - const installed = await installer.install() - expect(installed.state).toBe('installed') - expect(installed.commandName).toBe('orca-ide') - expect(installed.pathConfigured).toBe(false) - expect(installed.detail).toContain('.local') - - const launcherContent = await readFile(installed.launcherPath as string, 'utf8') - expect(launcherContent).toContain('ELECTRON_RUN_AS_NODE=1 exec "$ELECTRON" "$CLI" "$@"') - expect(launcherContent).toContain(`export ORCA_USER_DATA_PATH='${fixture.userDataPath}'`) - - const removed = await installer.remove() - expect(removed.state).toBe('not_installed') - } - ) - it.skipIf(process.platform === 'win32')( 'uses a separate orca-dev command for default development installs', async () => { @@ -101,65 +70,6 @@ describe('CliInstaller', () => { } ) - // Extraction avoids the ephemeral FUSE mount and AppRun's --no-sandbox injection into node mode. - it.skipIf(process.platform === 'win32')( - 'symlinks the linux command at the extracted AppImage launcher', - async () => { - const fixture = await makeFixture() - const commandDir = join(fixture.root, '.local', 'bin') - const installPath = join(commandDir, 'orca-ide') - const appImagePath = join(fixture.root, 'Orca.AppImage') - const cacheRootPath = join(fixture.root, 'cache') - await writeFile(appImagePath, '#!/usr/bin/env bash\n', { - encoding: 'utf8', - mode: 0o755 - }) - - const installer = new CliInstaller({ - platform: 'linux', - isPackaged: true, - userDataPath: fixture.userDataPath, - appPath: fixture.appPath, - appImagePath, - appImageCacheRootPath: cacheRootPath, - appImageExtractRunner: fakeAppImageExtractRunner, - commandPathOverride: installPath, - processPathEnv: commandDir - }) - - const initial = await installer.getStatus() - expect(initial).toMatchObject({ state: 'not_installed', installMethod: 'symlink' }) - - const installed = await installer.install() - expect(installed).toMatchObject({ - state: 'installed', - commandName: 'orca-ide', - installMethod: 'symlink', - pathConfigured: true - }) - // The command target remains stable while its cache endpoint advances generations. - expect(relative(cacheRootPath, installed.launcherPath as string).split(sep)).toEqual([ - 'launcher', - 'orca-ide' - ]) - expect(installed.currentTarget).toBe(installed.launcherPath) - await expect(readlink(installPath)).resolves.toBe(installed.launcherPath) - - const extractedRoot = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - await rm(extractedRoot.rootPath, { recursive: true, force: true }) - await expect(installer.getStatus()).resolves.toMatchObject({ state: 'stale' }) - const repaired = await installer.install() - expect(repaired.state).toBe('installed') - - const removed = await installer.remove() - expect(removed.state).toBe('not_installed') - await expect(lstat(repaired.launcherPath as string)).resolves.toBeDefined() - expect( - existsSync(resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })!.rootPath) - ).toBe(false) - } - ) - it.skipIf(process.platform === 'win32')( 're-extracts and re-points the command when the AppImage is replaced', async () => { @@ -249,73 +159,6 @@ describe('CliInstaller', () => { } ) - it.skipIf(process.platform === 'win32')( - 'removes the old managed linux orca symlink when installing orca-ide', - async () => { - const fixture = await makeFixture() - const homePath = join(fixture.root, 'home') - const commandDir = join(homePath, '.local', 'bin') - const resourcesPath = join(fixture.root, 'resources') - const launcherPath = join(resourcesPath, 'bin', 'orca-ide') - const oldLauncherPath = join(resourcesPath, 'bin', 'orca') - const legacyCommandPath = join(commandDir, 'orca') - await mkdir(commandDir, { recursive: true }) - await mkdir(join(resourcesPath, 'bin'), { recursive: true }) - await writeFile(launcherPath, '#!/usr/bin/env bash\n', 'utf8') - await writeFile(oldLauncherPath, '#!/usr/bin/env bash\n', 'utf8') - await symlink(oldLauncherPath, legacyCommandPath) - - const installer = new CliInstaller({ - platform: 'linux', - isPackaged: true, - userDataPath: fixture.userDataPath, - appPath: fixture.appPath, - resourcesPath, - homePath, - processPathEnv: commandDir - }) - - const installed = await installer.install() - expect(installed.commandPath).toBe(join(commandDir, 'orca-ide')) - await expect(lstat(legacyCommandPath)).rejects.toMatchObject({ code: 'ENOENT' }) - } - ) - - it.skipIf(process.platform === 'win32')( - 'removes a legacy linux orca symlink when registering from an AppImage', - async () => { - const fixture = await makeFixture() - const homePath = join(fixture.root, 'home') - const commandDir = join(homePath, '.local', 'bin') - const legacyCommandPath = join(commandDir, 'orca') - const appImagePath = join(fixture.root, 'Orca.AppImage') - const cacheRootPath = join(fixture.root, 'cache') - await mkdir(commandDir, { recursive: true }) - await writeFile(appImagePath, '#!/usr/bin/env bash\n', { - encoding: 'utf8', - mode: 0o755 - }) - const extractedRoot = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - await symlink(join(dirname(extractedRoot.payloadLauncherPath), 'orca'), legacyCommandPath) - - const installer = new CliInstaller({ - platform: 'linux', - isPackaged: true, - userDataPath: fixture.userDataPath, - appPath: fixture.appPath, - appImagePath, - appImageCacheRootPath: cacheRootPath, - appImageExtractRunner: fakeAppImageExtractRunner, - homePath, - processPathEnv: commandDir - }) - - const installed = await installer.install() - expect(installed.commandPath).toBe(join(commandDir, 'orca-ide')) - await expect(lstat(legacyCommandPath)).rejects.toMatchObject({ code: 'ENOENT' }) - } - ) - it.skipIf(process.platform === 'win32')( 'removes a legacy AppImage wrapper only when it names the current AppImage', async () => { diff --git a/src/main/cli/legacy-appimage-cli-wrapper.test.ts b/src/main/cli/legacy-appimage-cli-wrapper.test.ts index 5c4a64f8f3a..732376e6fbd 100644 --- a/src/main/cli/legacy-appimage-cli-wrapper.test.ts +++ b/src/main/cli/legacy-appimage-cli-wrapper.test.ts @@ -5,13 +5,6 @@ import { } from './legacy-appimage-cli-wrapper' describe('legacy AppImage CLI wrapper', () => { - it('recovers a path containing a newline', () => { - const appImagePath = "/tmp/Orca\nnightly's.AppImage" - expect(extractLegacyAppImageCliWrapperTarget(buildLegacyAppImageCliWrapper(appImagePath))).toBe( - appImagePath - ) - }) - it('rejects a wrapper with a changed command body', () => { const wrapper = buildLegacyAppImageCliWrapper('/tmp/Orca.AppImage') expect( diff --git a/src/main/cli/linux-bare-orca-dispatcher.test.ts b/src/main/cli/linux-bare-orca-dispatcher.test.ts index ff36fc1e9bd..b0b19412683 100644 --- a/src/main/cli/linux-bare-orca-dispatcher.test.ts +++ b/src/main/cli/linux-bare-orca-dispatcher.test.ts @@ -1,8 +1,7 @@ -import { existsSync } from 'node:fs' import type * as NodeFsPromises from 'node:fs/promises' import { mkdir, mkdtemp, readFile, rm, writeFile } from 'node:fs/promises' import { tmpdir } from 'node:os' -import { dirname, join, resolve } from 'node:path' +import { dirname, join } from 'node:path' import { afterEach, describe, expect, it, vi } from 'vitest' const { filePublicationFailures } = vi.hoisted(() => ({ @@ -57,7 +56,6 @@ vi.mock('./appimage-registration-lock', () => ({ })) import { installLinuxBareOrcaDispatcher } from './linux-bare-orca-dispatcher' -import { resolveAppImageExtractedRoot } from './appimage-extracted-root' const created: string[] = [] @@ -81,22 +79,6 @@ afterEach(async () => { }) describe('installLinuxBareOrcaDispatcher', () => { - it('publishes when the home filesystem does not support hard links', async () => { - const { homePath, resourcesPath } = await makeFixture() - filePublicationFailures.link = 1 - - const result = await installLinuxBareOrcaDispatcher({ - resourcesPath, - homePath, - appImagePath: null - }) - - expect(result.state).toBe('installed') - await expect(readFile(result.dispatcherPath, 'utf8')).resolves.toContain( - '# orca-serve-bare-orca-dispatcher' - ) - }) - it('restores a displaced foreign dispatcher when hard links are unsupported', async () => { const { homePath, resourcesPath } = await makeFixture() await installLinuxBareOrcaDispatcher({ resourcesPath, homePath, appImagePath: null }) @@ -174,57 +156,6 @@ describe('installLinuxBareOrcaDispatcher', () => { }) await expect(readFile(dispatcherPath, 'utf8')).resolves.toBe('#!/bin/sh\necho foreign\n') }) - - it('prunes old owner generations without touching a sibling namespace', async () => { - const { homePath, resourcesPath } = await makeFixture() - const appImagePath = join(homePath, 'Orca.AppImage') - const cacheRootPath = join(homePath, 'cache', 'unused', '..') - await mkdir(homePath, { recursive: true }) - await writeFile(appImagePath, '#!/usr/bin/env bash\n', { mode: 0o755 }) - const events: string[] = [] - const options = { - resourcesPath, - homePath, - appImagePath, - appImageCacheRootPath: cacheRootPath, - appImageExtractRunner: async (_path: string, cwd: string) => { - events.push('extract') - await writePayload(cwd) - } - } - - await installLinuxBareOrcaDispatcher(options) - const previous = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - const sibling = join(resolve(cacheRootPath), 'f'.repeat(24), 'e'.repeat(24)) - await mkdir(sibling, { recursive: true }) - await writeFile(appImagePath, '#!/usr/bin/env bash\n# next\n', { mode: 0o755 }) - const lockEntered = Promise.withResolvers() - const releaseLock = Promise.withResolvers() - events.length = 0 - registrationLock.pause = releaseLock.promise - registrationLock.entered = (rootPath) => { - events.push('lock-entered') - lockEntered.resolve(rootPath) - } - registrationLock.completed = () => { - events.push( - existsSync(previous.rootPath) ? 'lock-left-before-prune' : 'lock-left-after-prune' - ) - } - - const installation = installLinuxBareOrcaDispatcher(options) - await expect(lockEntered.promise).resolves.toBe(resolve(cacheRootPath)) - expect(events).toEqual(['lock-entered']) - expect(existsSync(previous.rootPath)).toBe(true) - releaseLock.resolve() - await installation - const current = resolveAppImageExtractedRoot({ appImagePath, cacheRootPath })! - - expect(events).toEqual(['lock-entered', 'extract', 'lock-left-after-prune']) - expect(existsSync(previous.rootPath)).toBe(false) - expect(existsSync(current.rootPath)).toBe(true) - expect(existsSync(sibling)).toBe(true) - }) }) async function writePayload(cwd: string): Promise { diff --git a/src/main/cli/windows-user-path-registry.test.ts b/src/main/cli/windows-user-path-registry.test.ts index 223e7557c78..85f187ded4a 100644 --- a/src/main/cli/windows-user-path-registry.test.ts +++ b/src/main/cli/windows-user-path-registry.test.ts @@ -32,45 +32,6 @@ describe('WindowsUserPathRegistryReader', () => { await expect(failedReader.read()).resolves.toMatchObject({ state: 'unknown' }) }) - it('coalesces concurrent reads, caches status reads, and bypasses the cache when fresh', async () => { - let now = 100 - let resolveRegistry!: (value: ReturnType) => void - const registryLoader = vi.fn( - () => - new Promise>((resolve) => { - resolveRegistry = resolve - }) - ) - const reader = new WindowsUserPathRegistryReader({ - platform: 'win32', - registryLoader, - now: () => now, - cacheTtlMs: 1_000 - }) - - const first = reader.read() - const concurrent = reader.read() - expect(registryLoader).toHaveBeenCalledOnce() - resolveRegistry(registryModule('C:\\Tools')) - await expect(Promise.all([first, concurrent])).resolves.toEqual([ - { state: 'success', value: 'C:\\Tools', expandable: true }, - { state: 'success', value: 'C:\\Tools', expandable: true } - ]) - - await reader.read() - expect(registryLoader).toHaveBeenCalledOnce() - - now += 1 - const refreshed = reader.readFresh() - expect(registryLoader).toHaveBeenCalledTimes(2) - resolveRegistry(registryModule('C:\\Tools;C:\\Orca')) - await expect(refreshed).resolves.toEqual({ - state: 'success', - value: 'C:\\Tools;C:\\Orca', - expandable: true - }) - }) - it.each([ { type: 1, expandable: false }, { type: 2, expandable: true } diff --git a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-page-input-model.test.ts b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-page-input-model.test.ts index 73f95c44063..11f978854d7 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-page-input-model.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-page-input-model.test.ts @@ -22,25 +22,6 @@ describe('remote browser page input model', () => { frameMetadata: { deviceWidth: frame.width, deviceHeight: frame.height }, naturalSize: { width: 2926, height: 1698 } }) - const screenOf = (x: number, y: number) => ({ - clientX: frameRect.left + x * scale, - clientY: frameRect.top + y * scale - }) - - it('lands on the page point drawn under the pointer, corners included', () => { - expect(cssViewport).toEqual(frame) - for (const [x, y] of [ - [0, 0], - [731, 424], - [1463, 849], - [1200, 100] - ]) { - expect(mapRemoteBrowserClientPoint({ ...screenOf(x, y), frameRect, cssViewport })).toEqual({ - x, - y - }) - } - }) it('clamps a pointer in the letterbox to the page edge', () => { expect( diff --git a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-service-failure.test.ts b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-service-failure.test.ts index b384a169582..9c1efde7218 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-service-failure.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-service-failure.test.ts @@ -12,16 +12,6 @@ describe('browser service failures on a responding remote host', () => { beforeEach(() => vi.useFakeTimers()) afterEach(() => vi.useRealTimers()) - it('shows the browser setup failure on initial open and keeps manual recovery', async () => { - const harness = createHarness() - harness.failEverySubscribe(rpcError('browser_unavailable', 'unconfigured backend')) - harness.lifecycle.open() - await settle() - expect(harness.currentError).toBe(SERVICE_NOTICE) - expect(harness.currentStatusKind).toBe('stopped') - expect(harness.reconnectOffered).toBe(true) - }) - it('keeps browser service recovery bounded and restores the stream once it returns', async () => { const harness = createHarness() await openStreamAndConfirmReady(harness) @@ -48,15 +38,4 @@ describe('browser service failures on a responding remote host', () => { expect(harness.reconnectOffered).toBe(true) expect(harness.subscribeAttempts).toBeLessThanOrEqual(6) }) - - it('keeps the service failure specific when resizing replaces a live stream', async () => { - const harness = createHarness() - await openStreamAndConfirmReady(harness) - harness.setViewportSize({ width: 1_024, height: 768 }) - harness.failEverySubscribe(rpcError('browser_unavailable', 'backend exited')) - harness.lifecycle.restartForViewport('page-1') - await settle() - expect(harness.currentError).toBe(SERVICE_NOTICE) - expect(harness.reconnectOffered).toBe(true) - }) }) diff --git a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts index ebf1da0bdd5..c95e0aa261e 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-restart-scheduler.test.ts @@ -7,27 +7,6 @@ afterEach(() => { }) describe('RemoteBrowserStreamRestartScheduler', () => { - it('retries transient failures until it recovers, without spending the whole budget', async () => { - vi.useFakeTimers() - const scheduler = new RemoteBrowserStreamRestartScheduler() - let attempts = 0 - const FAILURES_BEFORE_SUCCESS = 3 - - const run = vi.fn(async () => { - attempts += 1 - return attempts <= FAILURES_BEFORE_SUCCESS - }) - - scheduler.schedule(run) - await vi.advanceTimersByTimeAsync(31_000) - - expect(attempts).toBe(FAILURES_BEFORE_SUCCESS + 1) - expect(scheduler.isScheduled).toBe(false) - - await vi.advanceTimersByTimeAsync(60_000) - expect(attempts).toBe(FAILURES_BEFORE_SUCCESS + 1) - }) - // The property the pane depends on: retries are finite, and it is told when they run out. An // unbounded scheduler leaves a dead stream retrying forever behind a recurring error. it('stops after the budget and reports it exactly once', async () => { @@ -114,39 +93,4 @@ describe('RemoteBrowserStreamRestartScheduler', () => { expect(replacementRun).toHaveBeenCalledTimes(1) expect(scheduler.isScheduled).toBe(false) }) - - it('reset() forgets prior failures so the next drop backs off from the first delay again', async () => { - vi.useFakeTimers() - const scheduler = new RemoteBrowserStreamRestartScheduler() - const setTimeoutSpy = vi.spyOn(global, 'setTimeout') - const run = vi.fn().mockResolvedValueOnce(true).mockResolvedValue(false) - - scheduler.schedule(run) - await vi.advanceTimersByTimeAsync(1_500) - expect(scheduler.attemptCount).toBe(2) - - // The lifecycle explicitly refills the budget after a sustained healthy stream. - scheduler.reset() - expect(scheduler.attemptCount).toBe(0) - - scheduler.schedule(run) - const call = setTimeoutSpy.mock.calls.at(-1) - expect(call?.[1]).toBe(500) - }) - - it('cancel() clears a pending timer and resets the attempt count', async () => { - vi.useFakeTimers() - const scheduler = new RemoteBrowserStreamRestartScheduler() - const run = vi.fn(async () => true) - - scheduler.schedule(run) - expect(scheduler.isScheduled).toBe(true) - scheduler.cancel() - - expect(scheduler.isScheduled).toBe(false) - expect(scheduler.attemptCount).toBe(0) - - await vi.advanceTimersByTimeAsync(60_000) - expect(run).not.toHaveBeenCalled() - }) }) diff --git a/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-keyboard.test.tsx b/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-keyboard.test.tsx index fe83bc66a58..ed1831df1be 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-keyboard.test.tsx +++ b/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-keyboard.test.tsx @@ -1,7 +1,7 @@ // @vitest-environment happy-dom import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' import { afterEach, describe, expect, it, vi } from 'vitest' -import { BROWSER_TEXT_INSERT_CHUNK_BYTES } from '../../../../../shared/browser-text-insertion-chunks' + import { createHarness } from './remote-browser-stream-lifecycle-test-harness' import { useRemoteBrowserPageInputQueue } from './use-remote-browser-page-input' import { useRemoteBrowserPageKeyboard } from './use-remote-browser-page-keyboard' @@ -73,20 +73,6 @@ describe('streamed browser page keyboard input', () => { ]) }) - it('splits a large paste so no request exceeds the runtime socket frame', async () => { - render() - const text = 'x'.repeat(BROWSER_TEXT_INSERT_CHUNK_BYTES + 1) - - fireEvent.paste(screen.getByTestId('frame'), { clipboardData: { getData: () => text } }) - - await waitFor(() => expect(callRuntimeRpc).toHaveBeenCalledTimes(2)) - const params = { worktree: 'worktree-a', page: 'page-a' } - expect(sentInput()).toEqual([ - ['browser.keyboardInsertText', { ...params, text: text.slice(0, -1) }], - ['browser.keyboardInsertText', { ...params, text: 'x' }] - ]) - }) - it('copies and cuts to the local clipboard, deleting only after the write', async () => { const order: string[] = [] const ui = { diff --git a/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-navigation.test.ts b/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-navigation.test.ts index 7d6bcbec117..481965f3b90 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-navigation.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/use-remote-browser-page-navigation.test.ts @@ -58,52 +58,6 @@ describe('useRemoteBrowserPageNavigation history recording', () => { afterEach(() => cleanup()) - it('files one entry however often the same page is re-read', () => { - const { result } = renderNavigation() - - // Post-input refreshes read tab info; unchanged history must not rewrite the store and re-render every address bar. - for (let index = 0; index < 20; index += 1) { - act(() => - result.current.applyRemoteTabInfo({ url: 'https://remote.internal/docs', title: 'Docs' }) - ) - } - - expect(useAppStore.getState().browserUrlHistory).toEqual([ - expect.objectContaining({ url: 'https://remote.internal/docs', visitCount: 1 }) - ]) - }) - - it('files again once the page really moves', () => { - const { result } = renderNavigation() - - act(() => result.current.applyRemoteTabInfo({ url: 'https://remote.internal/a', title: 'A' })) - act(() => result.current.applyRemoteTabInfo({ url: 'https://remote.internal/b', title: 'B' })) - act(() => result.current.applyRemoteTabInfo({ url: 'https://remote.internal/a', title: 'A' })) - - expect( - useAppStore.getState().browserUrlHistory.map((entry) => [entry.url, entry.visitCount]) - ).toEqual([ - ['https://remote.internal/b', 1], - ['https://remote.internal/a', 2] - ]) - }) - - it('picks up a title that only arrives on a later read of the same page', () => { - const { result } = renderNavigation() - - act(() => result.current.applyRemoteTabInfo({ url: 'https://remote.internal/docs', title: '' })) - act(() => - result.current.applyRemoteTabInfo({ - url: 'https://remote.internal/docs', - title: 'Remote docs' - }) - ) - - expect(useAppStore.getState().browserUrlHistory).toEqual([ - expect.objectContaining({ title: 'Remote docs' }) - ]) - }) - it('redacts a Kagi session token before it reaches history', () => { const { result } = renderNavigation() diff --git a/src/renderer/src/components/browser-webauthn-account-dialog.test.tsx b/src/renderer/src/components/browser-webauthn-account-dialog.test.tsx index e54fa129097..bfc7402ad77 100644 --- a/src/renderer/src/components/browser-webauthn-account-dialog.test.tsx +++ b/src/renderer/src/components/browser-webauthn-account-dialog.test.tsx @@ -1,7 +1,7 @@ // @vitest-environment happy-dom import '@testing-library/jest-dom/vitest' -import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react' +import { act, cleanup, render, screen } from '@testing-library/react' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { BrowserWebAuthnAccountRequest } from '../../../shared/browser-webauthn-account' @@ -60,21 +60,6 @@ describe('BrowserWebAuthnAccountDialog', () => { }) } - it('returns the selected credential without displaying opaque credential IDs', async () => { - render() - showRequest() - - expect(screen.getByText('accounts.example.com')).toBeInTheDocument() - expect(screen.queryByText('work-id')).not.toBeInTheDocument() - await waitFor(() => expect(screen.getByRole('button', { name: /Personal/ })).toHaveFocus()) - fireEvent.click(screen.getByRole('button', { name: /Work/ })) - - expect(respondMock).toHaveBeenCalledWith({ - requestId: 'request-1', - credentialId: 'work-id' - }) - }) - it('closes a timed-out prompt when main dispatches teardown', () => { render() showRequest() diff --git a/src/renderer/src/components/cmd-j/palette-duplicate-key-ghost-rows.test.tsx b/src/renderer/src/components/cmd-j/palette-duplicate-key-ghost-rows.test.tsx deleted file mode 100644 index b5e7f973d4e..00000000000 --- a/src/renderer/src/components/cmd-j/palette-duplicate-key-ghost-rows.test.tsx +++ /dev/null @@ -1,60 +0,0 @@ -// @vitest-environment happy-dom -import { describe, expect, it } from 'vitest' -import { act } from 'react' -import { createRoot } from 'react-dom/client' -import { buildPaletteListEntryRenderKeys } from './palette-list-entry-render-keys' - -/** Duplicate persisted IDs can strand React rows after query narrowing; disambiguated render keys must unmount them. */ -type Row = { id: string; label: string } - -function PaletteList({ rows, uniqueKeys }: { rows: Row[]; uniqueKeys: boolean }) { - const renderKeys = uniqueKeys - ? buildPaletteListEntryRenderKeys(rows.map((row) => row.id)) - : rows.map((row) => row.id) - return ( -
- {rows.map((row, index) => ( - {row.label} - ))} -
- ) -} - -const DUPLICATE_TAB_ID = 'workspace-tab:editor:lungfish:FINAL-REPORT.md' - -function rowsForQuery(query: string): Row[] { - // "l" matches the worktree name; "li" and beyond match nothing in that workspace. - const remoteRows = - query === 'l' - ? [ - { id: DUPLICATE_TAB_ID, label: `[lungfish ${query}-hit]` }, - { id: DUPLICATE_TAB_ID, label: `[lungfish ${query}-hit]` } - ] - : [] - return [...remoteRows, { id: '__header_open_tabs__', label: '(OPEN TABS)' }] -} - -async function typeQuery(uniqueKeys: boolean): Promise { - const host = document.createElement('div') - document.body.appendChild(host) - const root = createRoot(host) - for (const query of ['l', 'li', 'lin', 'line', 'linea', 'linear']) { - await act(async () => { - root.render() - }) - } - const rendered = host.textContent ?? '' - root.unmount() - host.remove() - return rendered -} - -describe('duplicate persisted tab ids in the Cmd+J list', () => { - it('strands a ghost row when the render key repeats', async () => { - expect(await typeQuery(false)).toBe('[lungfish l-hit](OPEN TABS)') - }) - - it('leaves nothing behind once render keys are disambiguated', async () => { - expect(await typeQuery(true)).toBe('(OPEN TABS)') - }) -}) diff --git a/src/renderer/src/components/cmd-j/palette-filter-option-list.test.ts b/src/renderer/src/components/cmd-j/palette-filter-option-list.test.ts index 111101be82c..0d45124ae3b 100644 --- a/src/renderer/src/components/cmd-j/palette-filter-option-list.test.ts +++ b/src/renderer/src/components/cmd-j/palette-filter-option-list.test.ts @@ -1,7 +1,6 @@ import { describe, expect, it } from 'vitest' import { buildPaletteFilterOptionSearchText, - FILTER_OPTION_MAX_PINNED_SELECTED, rankPaletteFilterOptions } from './palette-filter-option-list' import type { PaletteFilterOption } from './palette-filter-options' @@ -34,21 +33,4 @@ describe('rankPaletteFilterOptions', () => { expect(ranked.ordered.map((row) => row.id)).toEqual(['a', 'b']) expect(ranked.selectedCollapsed).toBe(false) }) - - it('collapses pinned selected rows when they would crowd the list', () => { - const many = Array.from({ length: FILTER_OPTION_MAX_PINNED_SELECTED + 3 }, (_, i) => - option(`s${i}`, `Selected ${i}`, 1) - ) - const rest = [option('u1', 'Unselected', 9)] - const ranked = rankPaletteFilterOptions({ - options: [...many, ...rest], - selectedIds: new Set(many.map((row) => row.id)), - query: '', - rankMode: 'popularity' - }) - - expect(ranked.selectedCollapsed).toBe(true) - expect(ranked.selectedCount).toBe(many.length) - expect(ranked.ordered.map((row) => row.id)).toEqual(['u1']) - }) }) diff --git a/src/renderer/src/components/cmd-j/palette-focus-restore-target.test.ts b/src/renderer/src/components/cmd-j/palette-focus-restore-target.test.ts index f9d3b1c5700..53398f5fb12 100644 --- a/src/renderer/src/components/cmd-j/palette-focus-restore-target.test.ts +++ b/src/renderer/src/components/cmd-j/palette-focus-restore-target.test.ts @@ -22,14 +22,4 @@ describe('resolvePaletteFocusRestoreTarget', () => { expect(resolvePaletteFocusRestoreTarget(active)).toBe(active) }) - - it('falls back to the first terminal when the previous element is gone', () => { - const first = addTerminal('first') - const detached = document.createElement('textarea') - detached.className = 'xterm-helper-textarea' - // Never appended → not connected (e.g. its pane unmounted while Cmd+J was open). - - expect(detached.isConnected).toBe(false) - expect(resolvePaletteFocusRestoreTarget(detached)).toBe(first) - }) }) diff --git a/src/renderer/src/components/confirmation-dialog.test.tsx b/src/renderer/src/components/confirmation-dialog.test.tsx index 08fb3b6abc4..b1e9e2f6237 100644 --- a/src/renderer/src/components/confirmation-dialog.test.tsx +++ b/src/renderer/src/components/confirmation-dialog.test.tsx @@ -44,31 +44,6 @@ function renderDialog(options: ConfirmationDialogOptions): { onSettled: ReturnTy describe('ConfirmationDialogProvider', () => { afterEach(cleanup) - it('focuses the primary action when requested and confirms with Enter', async () => { - const { onSettled } = renderDialog({ - title: 'Reveal hidden workspace?', - confirmLabel: 'Clear filters and reveal', - initialFocus: 'confirm' - }) - await userEvent.click(screen.getByRole('button', { name: 'ask' })) - await waitFor(() => - expect(screen.getByRole('button', { name: 'Clear filters and reveal' })).toHaveFocus() - ) - await userEvent.keyboard('{Enter}') - await waitFor(() => expect(onSettled).toHaveBeenCalledWith(true)) - }) - - it('still cancels with Escape when the primary action has focus', async () => { - const { onSettled } = renderDialog({ - title: 'Reveal hidden workspace?', - initialFocus: 'confirm' - }) - await userEvent.click(screen.getByRole('button', { name: 'ask' })) - await waitFor(() => expect(screen.getByRole('button', { name: 'Confirm' })).toHaveFocus()) - await userEvent.keyboard('{Escape}') - await waitFor(() => expect(onSettled).toHaveBeenCalledWith(false)) - }) - it('tells the cancel button apart from Escape', async () => { const onCancelClicked = vi.fn() const { onSettled } = renderDialog({ title: 'Use your camera?', onCancelClicked }) @@ -112,26 +87,6 @@ describe('ConfirmationDialogProvider', () => { expect(onCancelClicked).toHaveBeenCalledOnce() }) - it('keeps the default cancel focus for callers that do not opt in', async () => { - renderDialog({ title: 'Delete artifact?', confirmVariant: 'destructive' }) - await userEvent.click(screen.getByRole('button', { name: 'ask' })) - await waitFor(() => expect(screen.getByRole('button', { name: 'Cancel' })).toHaveFocus()) - }) - - it('shows only the confirm button for a notice', async () => { - const { onSettled } = renderDialog({ - title: "Can't use p1 here yet", - confirmLabel: 'OK', - acknowledgeOnly: true, - initialFocus: 'confirm' - }) - await userEvent.click(screen.getByRole('button', { name: 'ask' })) - await waitFor(() => expect(screen.getByRole('button', { name: 'OK' })).toHaveFocus()) - expect(screen.queryByRole('button', { name: 'Cancel' })).not.toBeInTheDocument() - await userEvent.keyboard('{Enter}') - await waitFor(() => expect(onSettled).toHaveBeenCalledWith(true)) - }) - it('runs the skip callback when confirmed with the box checked', async () => { const onConfirmed = vi.fn() const { onSettled } = renderDialog({ diff --git a/src/renderer/src/components/confirmation-skip-preference.test.ts b/src/renderer/src/components/confirmation-skip-preference.test.ts deleted file mode 100644 index 34837a74108..00000000000 --- a/src/renderer/src/components/confirmation-skip-preference.test.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const mocks = vi.hoisted(() => ({ - toastError: vi.fn(), - toastSuccess: vi.fn() -})) - -vi.mock('sonner', () => ({ - toast: { error: mocks.toastError, success: mocks.toastSuccess } -})) - -vi.mock('@/i18n/i18n', () => ({ - translate: (_key: string, fallback: string) => fallback -})) - -import { persistConfirmationSkipPreference } from './confirmation-skip-preference' - -function deferred(): { - promise: Promise - reject: (error: Error) => void - resolve: () => void -} { - let reject!: (error: Error) => void - let resolve!: () => void - const promise = new Promise((onResolve, onReject) => { - resolve = onResolve - reject = onReject - }) - return { promise, reject, resolve } -} - -function persist(updateSettings: () => Promise): void { - persistConfirmationSkipPreference({ - updates: { skipDeleteArtifactConfirm: true }, - settingsSectionId: 'artifact-confirmation', - updateSettings, - openSettingsPage: vi.fn(), - openSettingsTarget: vi.fn() - }) -} - -describe('persistConfirmationSkipPreference', () => { - beforeEach(() => { - mocks.toastError.mockReset() - mocks.toastSuccess.mockReset() - }) - - it('shows success only after the preference is persisted', async () => { - const write = deferred() - persist(() => write.promise) - - expect(mocks.toastSuccess).not.toHaveBeenCalled() - write.resolve() - - await vi.waitFor(() => expect(mocks.toastSuccess).toHaveBeenCalledOnce()) - expect(mocks.toastError).not.toHaveBeenCalled() - }) - - it('reports a failed preference write without claiming success', async () => { - const write = deferred() - persist(() => write.promise) - write.reject(new Error('write failed')) - - await vi.waitFor(() => - expect(mocks.toastError).toHaveBeenCalledWith('Could not save the confirmation preference.') - ) - expect(mocks.toastSuccess).not.toHaveBeenCalled() - }) -}) diff --git a/src/renderer/src/components/contextual-tours/request-contextual-tour-when-ready.test.ts b/src/renderer/src/components/contextual-tours/request-contextual-tour-when-ready.test.ts index cd863251dcc..5cf2473f931 100644 --- a/src/renderer/src/components/contextual-tours/request-contextual-tour-when-ready.test.ts +++ b/src/renderer/src/components/contextual-tours/request-contextual-tour-when-ready.test.ts @@ -8,43 +8,6 @@ describe('requestContextualTourWhenReady', () => { vi.useRealTimers() }) - it('retries a forced tour request until the target starts', () => { - vi.useFakeTimers() - let activeContextualTourId: string | null = null - const requestContextualTour = vi.fn(() => { - if (requestContextualTour.mock.calls.length === 3) { - activeContextualTourId = 'workspace-agent-sessions' - } - }) - vi.spyOn(useAppStore, 'getState').mockImplementation( - () => - ({ - activeContextualTourId, - requestContextualTour - }) as unknown as ReturnType - ) - - requestContextualTourWhenReady({ - id: 'workspace-agent-sessions', - source: 'setup_guide_parallel_work', - retryDelayMs: 10, - maxAttempts: 5 - }) - - vi.advanceTimersByTime(0) - vi.advanceTimersByTime(10) - vi.advanceTimersByTime(10) - vi.advanceTimersByTime(20) - - expect(requestContextualTour).toHaveBeenCalledTimes(3) - expect(requestContextualTour).toHaveBeenLastCalledWith( - 'workspace-agent-sessions', - 'setup_guide_parallel_work', - undefined, - { force: true } - ) - }) - it('can wait for another tour to clear before requesting the target tour', () => { vi.useFakeTimers() let activeContextualTourId: string | null = 'workspace-agent-sessions' @@ -81,29 +44,4 @@ describe('requestContextualTourWhenReady', () => { { force: true } ) }) - - it('cancels pending retries when the caller unmounts or starts another action', () => { - vi.useFakeTimers() - const requestContextualTour = vi.fn() - vi.spyOn(useAppStore, 'getState').mockImplementation( - () => - ({ - activeContextualTourId: null, - requestContextualTour - }) as unknown as ReturnType - ) - - const cancel = requestContextualTourWhenReady({ - id: 'workspace-agent-sessions', - source: 'setup_guide_parallel_work', - retryDelayMs: 10, - maxAttempts: 5 - }) - - vi.advanceTimersByTime(0) - cancel() - vi.advanceTimersByTime(50) - - expect(requestContextualTour).toHaveBeenCalledTimes(1) - }) }) diff --git a/src/renderer/src/components/crash-report/use-crash-report-copy.test.tsx b/src/renderer/src/components/crash-report/use-crash-report-copy.test.tsx index 69b010907ac..d52f27718b3 100644 --- a/src/renderer/src/components/crash-report/use-crash-report-copy.test.tsx +++ b/src/renderer/src/components/crash-report/use-crash-report-copy.test.tsx @@ -95,24 +95,6 @@ describe('useCrashReportCopy', () => { expect(JSON.stringify(copyLatestDiagnostics.mock.calls)).not.toContain('private notes for B') }) - it('keeps a returned copy failure visible with its safe reason', async () => { - copyLatestDiagnostics.mockResolvedValueOnce({ - ok: false, - error: 'Crash diagnostics are too large to copy safely.' - }) - const { result } = renderHook(() => useCrashReportCopy(report(), 'current notes')) - - await act(async () => result.current()) - - expect(toast.error).toHaveBeenCalledWith('Crash report details could not be copied.', { - id: CRASH_REPORT_COPY_FAILURE_TOAST_ID, - description: 'Crash diagnostics are too large to copy safely.', - duration: Infinity, - dismissible: true - }) - expect(toast.success).not.toHaveBeenCalled() - }) - it('shows a safe sticky error toast when copy IPC rejects', async () => { copyLatestDiagnostics.mockRejectedValueOnce( new Error('renderer destroyed with token=must-not-be-shown') diff --git a/src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts b/src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts deleted file mode 100644 index 82d6930a514..00000000000 --- a/src/renderer/src/components/dashboard-popout/agent-board-filtering.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { DashboardCard } from '../../../../shared/dashboard-snapshot' -import { - EMPTY_DASHBOARD_FILTERS, - filterDashboardCards, - toggleDashboardFilter -} from './agent-board-filtering' - -function card(overrides: Partial): DashboardCard { - return { - paneKey: 'pane', - ptyId: null, - agentType: 'claude', - bucket: 'working', - dotState: 'working', - task: '', - repoId: 'repo-1', - worktreeId: 'worktree-1', - tabId: 'tab-1', - leafId: null, - repoName: 'Orca', - worktreeName: 'dashboard', - startedAt: 0, - finishedAt: null, - stateChangedAt: 0, - unseen: false, - ...overrides - } -} - -describe('agent board filtering', () => { - it('supports the synthesized no-review filter and immutable toggles', () => { - const cards = [ - card({ paneKey: 'none' }), - card({ paneKey: 'open', review: { number: 1, state: 'open' } }), - card({ paneKey: 'linked-uncached', hasReview: true }) - ] - - expect( - filterDashboardCards(cards, '', { - ...EMPTY_DASHBOARD_FILTERS, - reviewStates: ['none'] - }).map((candidate) => candidate.paneKey) - ).toEqual(['none']) - expect(toggleDashboardFilter(['open'], 'draft')).toEqual(['open', 'draft']) - expect(toggleDashboardFilter(['open', 'draft'], 'open')).toEqual(['draft']) - }) -}) diff --git a/src/renderer/src/components/dashboard-popout/preview-grid-claim.test.ts b/src/renderer/src/components/dashboard-popout/preview-grid-claim.test.ts deleted file mode 100644 index 5b618ee4580..00000000000 --- a/src/renderer/src/components/dashboard-popout/preview-grid-claim.test.ts +++ /dev/null @@ -1,49 +0,0 @@ -// @vitest-environment happy-dom - -import { afterEach, describe, expect, it, vi } from 'vitest' -import { createPreviewGridClaim } from './preview-grid-claim' - -function dimension(element: HTMLElement, name: string, value: number): void { - Object.defineProperty(element, name, { configurable: true, value }) -} - -describe('createPreviewGridClaim', () => { - afterEach(() => { - vi.clearAllMocks() - vi.useRealTimers() - }) - - it('coalesces a continuous resize burst into one settled fit request', async () => { - vi.useFakeTimers() - const fit = vi.fn(async (_ptyId: string, cols: number, rows: number) => ({ cols, rows })) - Object.assign(window, { api: { terminalPreview: { fit } } }) - const box = document.createElement('div') - const container = document.createElement('div') - const screen = document.createElement('div') - screen.className = 'xterm-screen' - box.appendChild(container) - container.appendChild(screen) - dimension(box, 'clientWidth', 800) - dimension(box, 'clientHeight', 480) - dimension(screen, 'offsetWidth', 800) - dimension(screen, 'offsetHeight', 384) - const claim = createPreviewGridClaim({ - ptyId: 'pty-1', - container, - getTerminal: () => ({ cols: 80, rows: 24 }) as never - }) - - claim.schedule() - for (let step = 1; step <= 10; step += 1) { - await vi.advanceTimersByTimeAsync(100) - dimension(box, 'clientWidth', 800 + step * 20) - claim.schedule() - } - - expect(fit).not.toHaveBeenCalled() - await vi.advanceTimersByTimeAsync(200) - expect(fit).toHaveBeenCalledTimes(1) - expect(fit).toHaveBeenCalledWith('pty-1', 100, 30) - claim.dispose() - }) -}) diff --git a/src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts b/src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts index beeb9b7dc38..bbfd1bf39e0 100644 --- a/src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts +++ b/src/renderer/src/components/dashboard-popout/preview-terminal-box-fit-lifecycle.test.ts @@ -63,22 +63,6 @@ function thrown(operation: () => void): unknown { throw new Error('Expected an error') } -it('keeps live geometry and coalesces repeated requests into one frame', () => { - const owner = harness() - owner.schedule() - owner.schedule() - owner.schedule() - expect(owner.read).not.toHaveBeenCalled() - expect(frames.size).toBe(1) - flush() - expect(owner.read).toHaveBeenCalledOnce() - expect(owner.container.style.transform).toBe('scale(0.75)') - expect(owner.container.style.transformOrigin).toBe('top left') - expect(owner.box.style.alignItems).toBe('flex-start') - owner.dispose() - expect(cancelFrame).not.toHaveBeenCalled() -}) - it('cancels frame zero once and suppresses captured or later callbacks after disposal', () => { const owner = harness() owner.schedule() @@ -93,49 +77,6 @@ it('cancels frame zero once and suppresses captured or later callbacks after dis expect(cancelFrame).toHaveBeenCalledExactlyOnceWith(0) }) -it('preserves synchronous frame completion without canceling a completed handle', () => { - vi.stubGlobal('requestAnimationFrame', (callback: FrameRequestCallback) => { - callback(16) - return 0 - }) - const owner = harness() - owner.schedule() - owner.schedule() - expect(owner.read).toHaveBeenCalledTimes(2) - owner.dispose() - expect(cancelFrame).not.toHaveBeenCalled() -}) - -it('retains a reentrant successor frame and cancels only that pending successor', () => { - const owner = harness() - owner.read.mockImplementationOnce(() => { - owner.schedule() - return null - }) - owner.schedule() - flush() - expect(owner.read).toHaveBeenCalledOnce() - expect([...frames.keys()]).toEqual([1]) - owner.dispose() - expect(cancelFrame).toHaveBeenCalledExactlyOnceWith(1) -}) - -it('marks disposal before cancellation reenters schedule or invokes the retired callback', () => { - const owner = harness() - owner.schedule() - const callback = frames.get(0) - cancelFrame.mockImplementationOnce((id) => { - owner.schedule() - owner.dispose() - callback?.(16) - return frames.delete(id) - }) - owner.dispose() - expect(owner.read).not.toHaveBeenCalled() - expect(frames.size).toBe(0) - expect(cancelFrame).toHaveBeenCalledExactlyOnceWith(0) -}) - it('preserves a fit error and allows the next live request after completion', () => { const error = new Error('terminal read failed') const owner = harness() diff --git a/src/renderer/src/components/dashboard-popout/use-agent-dashboard-telemetry.test.ts b/src/renderer/src/components/dashboard-popout/use-agent-dashboard-telemetry.test.ts index 8730fa017a0..5b351691f32 100644 --- a/src/renderer/src/components/dashboard-popout/use-agent-dashboard-telemetry.test.ts +++ b/src/renderer/src/components/dashboard-popout/use-agent-dashboard-telemetry.test.ts @@ -59,105 +59,6 @@ describe('dashboard visible-use telemetry', () => { vi.restoreAllMocks() }) - it.each(['popout', 'in_window'] as const)( - 'observes %s across days without recording another opening', - async (surface) => { - vi.setSystemTime(new Date('2026-10-22T12:00:00Z')) - renderHook(() => useAgentDashboardTelemetry(surface)) - await flushConsent() - expect(track.mock.calls).toEqual([ - ['agent_dashboard_opened', { surface }], - ['agent_dashboard_active', { surface }] - ]) - - vi.setSystemTime(new Date('2026-10-23T12:00:00Z')) - act(() => vi.advanceTimersByTime(60_000)) - - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_opened')).toHaveLength( - 1 - ) - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength( - 2 - ) - } - ) - - it('waits for a hidden window to become visible and pauses again when hidden', async () => { - visibility = 'hidden' - const { unmount } = renderHook(() => useAgentDashboardTelemetry('popout')) - await flushConsent() - act(() => vi.advanceTimersByTime(60_000)) - expect(track.mock.calls).toEqual([['agent_dashboard_opened', { surface: 'popout' }]]) - - visibility = 'visible' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - expect(track).toHaveBeenLastCalledWith('agent_dashboard_active', { surface: 'popout' }) - expect(track).toHaveBeenCalledTimes(2) - - visibility = 'hidden' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - act(() => vi.advanceTimersByTime(120_000)) - expect(track).toHaveBeenCalledTimes(2) - - unmount() - visibility = 'visible' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - act(() => vi.advanceTimersByTime(120_000)) - expect(track).toHaveBeenCalledTimes(2) - }) - - it('stops observations when the board closes while visible', async () => { - const { unmount } = renderHook(() => useAgentDashboardTelemetry('in_window')) - await flushConsent() - expect(track).toHaveBeenCalledTimes(2) - - unmount() - act(() => vi.advanceTimersByTime(120_000)) - - expect(track).toHaveBeenCalledTimes(2) - }) - - it('retains a confirmed observation across visibility changes and observes the next visible day', async () => { - vi.setSystemTime(new Date('2026-10-22T12:00:00Z')) - renderHook(() => useAgentDashboardTelemetry('popout')) - await flushConsent() - - for (let index = 0; index < 3; index++) { - visibility = 'hidden' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - visibility = 'visible' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - await flushConsent() - } - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength(1) - - visibility = 'hidden' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - vi.setSystemTime(new Date('2026-10-24T12:00:00Z')) - visibility = 'visible' - act(() => document.dispatchEvent(new Event('visibilitychange'))) - await flushConsent() - - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength(2) - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_opened')).toHaveLength(1) - }) - - it('sends only two visible-use observations across 24 hours without rerendering the board', async () => { - vi.setSystemTime(new Date('2026-10-22T12:00:00Z')) - let renders = 0 - renderHook(() => { - renders++ - useAgentDashboardTelemetry('popout') - }) - await flushConsent() - - act(() => vi.advanceTimersByTime(24 * 60 * 60_000)) - - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength(2) - expect(getConsentState).toHaveBeenCalledTimes(1) - expect(renders).toBe(1) - }) - it.each(['pending_banner', 'user_opt_out', 'do_not_track', 'orca_disabled', 'ci'] as const)( 'creates no timer or daily-use attempts while blocked by %s', async (reason) => { @@ -216,41 +117,4 @@ describe('dashboard visible-use telemetry', () => { expect(vi.getTimerCount()).toBe(0) expect(track.mock.calls).toEqual([['agent_dashboard_opened', { surface: 'popout' }]]) }) - - it('retries an unrecorded observation and suppresses same-day ticks after confirmation', async () => { - let recorded = false - track.mockImplementation(() => Promise.resolve(recorded)) - renderHook(() => useAgentDashboardTelemetry('popout')) - await flushConsent() - - recorded = true - await act(async () => vi.advanceTimersByTimeAsync(60_000)) - await act(async () => vi.advanceTimersByTimeAsync(5 * 60_000)) - - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength(2) - }) - - it('does not stack IPC requests while an observation is pending', async () => { - track.mockReturnValue(new Promise(() => {})) - renderHook(() => useAgentDashboardTelemetry('popout')) - await flushConsent() - - await act(async () => vi.advanceTimersByTimeAsync(10 * 60_000)) - - expect(track.mock.calls.filter(([event]) => event === 'agent_dashboard_active')).toHaveLength(1) - }) - - it('releases timers and visibility listeners after repeated open/close cycles', async () => { - const added = vi.spyOn(document, 'addEventListener') - const removed = vi.spyOn(document, 'removeEventListener') - for (let index = 0; index < 25; index++) { - const { unmount } = renderHook(() => useAgentDashboardTelemetry('popout')) - await flushConsent() - unmount() - } - - expect(vi.getTimerCount()).toBe(0) - expect(added.mock.calls.filter(([event]) => event === 'visibilitychange')).toHaveLength(25) - expect(removed.mock.calls.filter(([event]) => event === 'visibilitychange')).toHaveLength(25) - }) }) diff --git a/src/renderer/src/components/dashboard/useAgentBucketCounts.test.tsx b/src/renderer/src/components/dashboard/useAgentBucketCounts.test.tsx deleted file mode 100644 index 6ea97065139..00000000000 --- a/src/renderer/src/components/dashboard/useAgentBucketCounts.test.tsx +++ /dev/null @@ -1,74 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, renderHook } from '@testing-library/react' -import { afterEach, describe, expect, it, vi } from 'vitest' - -const mocks = vi.hoisted(() => ({ - state: { - repos: [], - worktreesByRepo: {}, - tabsByWorktree: {}, - unifiedTabsByWorktree: {}, - agentStatusByPaneKey: {}, - retainedAgentsByPaneKey: {}, - migrationUnsupportedByPtyId: {}, - runtimeAgentOrchestrationByPaneKey: {}, - terminalLayoutsByTabId: {}, - ptyIdsByTabId: {}, - runtimePaneTitlesByTabId: {}, - folderWorkspaces: [{ id: 'folder-1' }], - acknowledgedAgentsByPaneKey: {} as Record, - unrelatedEpoch: 0, - agentStatusEpoch: 0 - }, - buildDashboardBucketCounts: vi.fn() -})) - -vi.mock('@/store', () => ({ - useAppStore: (selector: (state: typeof mocks.state) => unknown) => selector(mocks.state) -})) - -vi.mock('./build-dashboard-bucket-counts', () => ({ - buildDashboardBucketCounts: mocks.buildDashboardBucketCounts, - createDashboardBucketCountsCache: () => ({ - byWorktree: new Map(), - computeCount: 0, - lastComputedWorktreeIds: [] - }) -})) - -import { resetAgentBucketCountStateForTests, useAgentBucketCounts } from './useAgentBucketCounts' - -afterEach(() => { - cleanup() - vi.clearAllMocks() - resetAgentBucketCountStateForTests() - mocks.state.acknowledgedAgentsByPaneKey = {} - mocks.state.unrelatedEpoch = 0 -}) - -describe('useAgentBucketCounts', () => { - it('moves acknowledged completions to idle without recomputing for unrelated writes', () => { - mocks.buildDashboardBucketCounts.mockImplementation( - (state: { acknowledgedAgentsByPaneKey?: Record }) => ({ - attention: 0, - working: 0, - done: state.acknowledgedAgentsByPaneKey?.['pane-done'] ? 0 : 1, - idle: state.acknowledgedAgentsByPaneKey?.['pane-done'] ? 1 : 0 - }) - ) - const { result, rerender } = renderHook(() => useAgentBucketCounts()) - - expect(result.current).toEqual({ attention: 0, working: 0, done: 1, idle: 0 }) - expect(mocks.buildDashboardBucketCounts).toHaveBeenCalledTimes(1) - - mocks.state.unrelatedEpoch += 1 - rerender() - expect(mocks.buildDashboardBucketCounts).toHaveBeenCalledTimes(1) - - mocks.state.acknowledgedAgentsByPaneKey = { 'pane-done': 1 } - rerender() - expect(result.current).toEqual({ attention: 0, working: 0, done: 0, idle: 1 }) - expect(mocks.buildDashboardBucketCounts).toHaveBeenCalledTimes(2) - }) -}) diff --git a/src/renderer/src/components/dictation/dictation-insertion-target.test.ts b/src/renderer/src/components/dictation/dictation-insertion-target.test.ts index deb734406f7..d7db7df7348 100644 --- a/src/renderer/src/components/dictation/dictation-insertion-target.test.ts +++ b/src/renderer/src/components/dictation/dictation-insertion-target.test.ts @@ -1,10 +1,8 @@ // @vitest-environment happy-dom import { afterEach, describe, expect, it, vi } from 'vitest' -import { getUtf8ByteLength } from '../../../../shared/utf8-byte-limits' import { - TEXT_CONTROL_PASTE_CHUNK_MAX_BYTES, TEXT_CONTROL_PASTE_DIRECT_MAX_BYTES, TEXT_CONTROL_PASTE_MAX_BYTES } from '@/lib/text-control-paste' @@ -26,13 +24,6 @@ afterEach(() => { }) }) -function appendTextarea(): HTMLTextAreaElement { - const textarea = document.createElement('textarea') - document.body.appendChild(textarea) - textarea.focus() - return textarea -} - function appendContentEditable(): HTMLElement { const element = document.createElement('div') element.contentEditable = 'true' @@ -54,43 +45,6 @@ function installExecCommandMock( } describe('dictation insertion target', () => { - it('chunks large textarea dictation without one large input event', async () => { - vi.useFakeTimers() - const textarea = appendTextarea() - const inputEvents: InputEvent[] = [] - textarea.addEventListener('input', (event) => inputEvents.push(event as InputEvent)) - const text = 'a'.repeat(TEXT_CONTROL_PASTE_DIRECT_MAX_BYTES + 5) - - insertText(text, { kind: 'text', element: textarea }) - await vi.runAllTimersAsync() - - expect(textarea.value).toBe(text) - expect(inputEvents).toHaveLength(1) - expect(inputEvents[0].inputType).toBe('insertText') - expect(inputEvents[0].data ?? '').toBe('') - }) - - it('chunks large contenteditable dictation through bounded insertText calls', async () => { - vi.useFakeTimers() - const editor = appendContentEditable() - const beforeInputEvents: InputEvent[] = [] - editor.addEventListener('beforeinput', (event) => beforeInputEvents.push(event as InputEvent)) - const execCommand = installExecCommandMock(() => true) - const text = 'ab\u{1f600}'.repeat(20_000) - - insertText(text, { kind: 'contentEditable', element: editor }) - await vi.runAllTimersAsync() - - expect(execCommand.mock.calls.length).toBeGreaterThan(1) - expect( - execCommand.mock.calls.every( - (call) => getUtf8ByteLength(String(call[2] ?? '')) <= TEXT_CONTROL_PASTE_CHUNK_MAX_BYTES - ) - ).toBe(true) - expect(beforeInputEvents).toHaveLength(execCommand.mock.calls.length) - expect(beforeInputEvents.some((event) => event.data === text)).toBe(false) - }) - it('cancels chunked contenteditable dictation when the target disconnects', async () => { vi.useFakeTimers() const editor = appendContentEditable() diff --git a/src/shared/libproc-process-table.test.ts b/src/shared/libproc-process-table.test.ts index 1fa81265627..88cedb20957 100644 --- a/src/shared/libproc-process-table.test.ts +++ b/src/shared/libproc-process-table.test.ts @@ -17,7 +17,6 @@ import { nativeReadWaitersForTests, resetNativeReadsForTests } from './libproc-n import { runPsInProcess } from './libproc-process-table' import { resetPsFallbackForTests } from './libproc-ps-fallback' import { createProcessTableSnapshotReader } from './process-table-snapshot-reader' -import { parseCheapProcessTableRows, parseStrictProcessTableRows } from './process-table-snapshot' const TTYS004 = (16 << 24) | 4 // 2026-09-03T16:02:01Z, a single-digit day so lstart pads it. @@ -145,65 +144,6 @@ afterEach(() => { }) describe('runPsInProcess', () => { - it('prints a whole-table capture the strict and cheap parsers read like ps output', async () => { - installAddon() - const utc = { env: { TZ: 'UTC0', LC_ALL: 'C' }, timeoutMs: 1000 } - - const full = await runPsInProcess( - ['-axo', 'pid=,ppid=,pgid=,tpgid=,stat=,tty=,lstart=,command='], - utc - ) - expect(full?.code).toBe(0) - // ps sorts by terminal, then pid. - expect(parseStrictProcessTableRows(full!.stdout)).toEqual([ - expect.objectContaining({ pid: 1, tty: '??', command: '/sbin/launchd' }), - expect.objectContaining({ pid: 4400, stat: 'T', tty: '??', command: 'vim' }), - expect.objectContaining({ pid: 4401, stat: 'Z', command: '' }), - expect.objectContaining({ pid: 4200, stat: 'S', tty: 'ttys004', command: '/usr/bin/login' }), - expect.objectContaining({ pid: 4242, stat: 'Ss', tty: 'ttys004', command: '-zsh' }), - expect.objectContaining({ - pid: 4300, - stat: 'S+', - tty: 'ttys004', - startTime: 'Thu Sep 3 16:02:01 2026', - command: 'node /usr/local/bin/claude --resume' - }) - ]) - // Neither the root daemon nor the pane's root login is a pane descendant worth a setuid ps. - expect(runProcess).not.toHaveBeenCalled() - - const cheap = await runPsInProcess(['-axo', 'pid=,ppid=,pgid=,tpgid=,stat=,lstart='], utc) - expect(parseCheapProcessTableRows(cheap!.stdout).at(-1)).toEqual({ - pid: 4300, - ppid: 4242, - pgid: 4300, - tpgid: 4300, - stat: 'S+', - startTime: 'Thu Sep 3 16:02:01 2026' - }) - }) - - it('selects by pid or terminal and exits 1 like ps when nothing matches', async () => { - const addon = installAddon() - - expect(await runPsInProcess(['-p', '4300,4300', '-o', 'pid=,tdev='], BUDGET)).toMatchObject({ - code: 0, - stdout: '4300 16/4\n' - }) - expect(addon.readProcessTable).toHaveBeenLastCalledWith({ command: false, pids: [4300] }) - expect(await runPsInProcess(['-p', '9999', '-o', 'stat=,lstart='], BUDGET)).toMatchObject({ - code: 1, - stdout: '' - }) - const tty = await runPsInProcess(['-o', 'pid=,stat=', '-t', '/dev/ttys004'], BUDGET) - expect(tty?.stdout).toBe('4200 S\n4242 Ss\n4300 S+\n') - expect(addon.readProcessTable).toHaveBeenLastCalledWith({ command: false, tty: '/dev/ttys004' }) - expect(await runPsInProcess(['-o', 'pid=', '-t', 'ttys999'], BUDGET)).toMatchObject({ - code: 1, - timedOut: false - }) - }) - it('keeps the real ps for invocations it cannot reproduce, and answers a failing addon with /bin/ps', async () => { installAddon() expect(await runPsInProcess(['-axo', 'pid=PROCESS_ID'], BUDGET)).toBeNull() @@ -409,15 +349,6 @@ describe('runPsInProcess', () => { expect(runProcess).toHaveBeenCalledTimes(2) }) - it('lets concurrent tty= readers wait out one naming pass instead of running ps', async () => { - installAddon() - // 4300's read is still stalled from the timeout case above. - const args = ['-o', 'pid=,tty=', '-p', '4242'] - const results = await Promise.all([1, 2, 3].map(() => runPsInProcess(args, BUDGET))) - expect(results.map((result) => result?.stdout)).toEqual(Array(3).fill('4242 ttys004\n')) - expect(runProcess).not.toHaveBeenCalled() - }) - it('leaves argv of the user’s own mid-exec processes and of exiting ones to (comm), asking ps only for other users', async () => { const foreign = { ppid: 4242, tdev: TTYS004, uid: OTHER_UID, flags: 0x2 } const table = [ diff --git a/src/shared/linear/inline-media.test.ts b/src/shared/linear/inline-media.test.ts deleted file mode 100644 index 6e633d1e8bf..00000000000 --- a/src/shared/linear/inline-media.test.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { extractLinearInlineMedia } from './inline-media' - -describe('Linear inline media extraction', () => { - it('extracts markdown and HTML media URLs with source metadata', () => { - const media = extractLinearInlineMedia( - [ - '![Screenshot](https://uploads.linear.app/workspace/file/image-id?signature=abc)', - '' - ].join('\n'), - 'comment', - 'comment-1' - ) - - expect(media).toEqual([ - { - source: 'comment', - sourceId: 'comment-1', - url: 'https://uploads.linear.app/workspace/file/image-id?signature=abc', - altText: 'Screenshot', - fileName: 'image-id', - linearUpload: true - }, - { - source: 'comment', - sourceId: 'comment-1', - url: 'https://example.com/diagram.png', - altText: null, - fileName: 'diagram.png', - linearUpload: false - } - ]) - }) - - it('deduplicates repeated media URLs from the same markdown body', () => { - const media = extractLinearInlineMedia( - [ - '![](https://uploads.linear.app/workspace/file/image-id)', - '![](https://uploads.linear.app/workspace/file/image-id)' - ].join('\n'), - 'description' - ) - - expect(media).toHaveLength(1) - expect(media[0]?.linearUpload).toBe(true) - }) -}) diff --git a/src/shared/linear/issue-attribute-filter.test.ts b/src/shared/linear/issue-attribute-filter.test.ts index f0d5b1f952b..0d8e624a0db 100644 --- a/src/shared/linear/issue-attribute-filter.test.ts +++ b/src/shared/linear/issue-attribute-filter.test.ts @@ -1,8 +1,6 @@ import { describe, expect, it } from 'vitest' import { - EMPTY_LINEAR_ISSUE_ATTRIBUTE_FILTER, canonicalizeLinearIssueAttributeFilter, - emptyLinearIssueAttributeFilter, isEmptyLinearIssueAttributeFilter, linearIssueAttributeFilterSignature, parseLinearIssueAttributeFilter, @@ -17,13 +15,6 @@ const sample: LinearIssueAttributeFilter = { } describe('linear-issue-attribute-filter', () => { - it('treats the canonical empty value as empty and signature-less', () => { - expect(isEmptyLinearIssueAttributeFilter(EMPTY_LINEAR_ISSUE_ATTRIBUTE_FILTER)).toBe(true) - expect(isEmptyLinearIssueAttributeFilter(emptyLinearIssueAttributeFilter())).toBe(true) - expect(linearIssueAttributeFilterSignature(EMPTY_LINEAR_ISSUE_ATTRIBUTE_FILTER)).toBe('') - expect(linearIssueAttributeFilterSignature(undefined)).toBe('') - }) - it('canonicalizes without mutating the input and produces a stable signature', () => { const input = structuredClone(sample) const canonical = canonicalizeLinearIssueAttributeFilter(input) diff --git a/src/shared/linear/issue-view-resume-state.test.ts b/src/shared/linear/issue-view-resume-state.test.ts index c37a4e475cc..9b08afbbdcb 100644 --- a/src/shared/linear/issue-view-resume-state.test.ts +++ b/src/shared/linear/issue-view-resume-state.test.ts @@ -11,8 +11,7 @@ import { resolveLinearIssueViewResumeState, selectLinearWorkspaceIssueFilter, serializeLinearIssueViewResumeState, - setLinearWorkspaceIssueFilter, - type LinearIssueViewResumeState + setLinearWorkspaceIssueFilter } from './issue-view-resume-state' function filter(overrides: Partial = {}): LinearIssueAttributeFilter { @@ -23,53 +22,14 @@ const FILTER_A = filter({ stateIds: ['state-a'], priorities: [1] }) const FILTER_B = filter({ labelIds: ['label-b'], assignee: { kind: 'user', id: 'user-b' } }) describe('resolveLinearIssueViewResumeState', () => { - it('falls back to list/none/priority with every display property when nothing is persisted', () => { - expect(resolveLinearIssueViewResumeState(undefined)).toEqual({ - viewMode: 'list', - groupBy: 'none', - orderBy: 'priority', - displayProperties: [...LINEAR_DISPLAY_PROPERTIES], - teamPropertyTouched: false, - filtersByWorkspaceId: {} - }) - }) - - it('restores a complete persisted view', () => { - const persisted: LinearIssueViewResumeState = { - viewMode: 'board', - groupBy: 'assignee', - orderBy: 'updated', - displayProperties: ['state', 'labels'], - teamPropertyTouched: true, - filtersByWorkspaceId: { 'workspace-a': FILTER_A, 'workspace-b': FILTER_B } - } - - expect(resolveLinearIssueViewResumeState(persisted)).toEqual(persisted) - }) - it('keeps an empty display-property list, which means every property is hidden', () => { expect(resolveLinearIssueViewResumeState({ displayProperties: [] }).displayProperties).toEqual( [] ) }) - - it('drops unknown display properties and restores catalog order', () => { - const resolved = resolveLinearIssueViewResumeState({ - displayProperties: ['updated', 'bogus', 'state'] - }) - - expect(resolved.displayProperties).toEqual(['state', 'updated']) - }) }) describe('normalizeLinearIssueViewResumeState', () => { - it('drops a malformed preference blob entirely', () => { - expect(normalizeLinearIssueViewResumeState('board')).toBeUndefined() - expect(normalizeLinearIssueViewResumeState(null)).toBeUndefined() - expect(normalizeLinearIssueViewResumeState(['board'])).toBeUndefined() - expect(normalizeLinearIssueViewResumeState({ viewMode: 'grid', groupBy: 42 })).toBeUndefined() - }) - it('keeps the valid fields when only some of them are corrupt', () => { const normalized = normalizeLinearIssueViewResumeState({ viewMode: 'board', @@ -118,75 +78,7 @@ describe('normalizeLinearIssueViewResumeState', () => { }) }) -describe('isDefaultLinearIssueViewResumeState', () => { - // Returning undefined clears persisted defaults after users revert every setting. - it('drops a serialized default view so reverting a setting clears what was stored', () => { - expect( - normalizeLinearIssueViewResumeState( - serializeLinearIssueViewResumeState(defaultLinearIssueViewResumeState()) - ) - ).toBeUndefined() - }) - - it.each([ - ['viewMode', { viewMode: 'board' as const }], - ['groupBy', { groupBy: 'status' as const }], - ['orderBy', { orderBy: 'updated' as const }], - ['teamPropertyTouched', { teamPropertyTouched: true }], - ['displayProperties', { displayProperties: ['state' as const] }], - [ - 'filtersByWorkspaceId', - { filtersByWorkspaceId: { 'workspace-1': filter({ priorities: [1] }) } } - ] - ])('keeps a view that differs from the default in %s', (_label, overrides) => { - expect( - normalizeLinearIssueViewResumeState( - serializeLinearIssueViewResumeState({ - ...defaultLinearIssueViewResumeState(), - ...overrides - }) - ) - ).toBeDefined() - }) -}) - describe('serializeLinearIssueViewResumeState', () => { - it('round-trips a restored view unchanged', () => { - const restored = resolveLinearIssueViewResumeState({ - viewMode: 'board', - groupBy: 'team', - orderBy: 'identifier', - displayProperties: ['labels', 'state'], - teamPropertyTouched: true, - filtersByWorkspaceId: { 'workspace-a': FILTER_A } - }) - - expect(serializeLinearIssueViewResumeState(restored)).toEqual(restored) - }) - - it('emits display properties in catalog order regardless of toggle order', () => { - const serialized = serializeLinearIssueViewResumeState({ - ...defaultLinearIssueViewResumeState(), - displayProperties: new Set(['updated', 'state'] as const) - }) - - expect(serialized.displayProperties).toEqual(['state', 'updated']) - }) - - it('omits empty filters and canonicalizes the rest', () => { - const serialized = serializeLinearIssueViewResumeState({ - ...defaultLinearIssueViewResumeState(), - filtersByWorkspaceId: { - 'workspace-empty': emptyLinearIssueAttributeFilter(), - 'workspace-a': filter({ labelIds: ['b', 'a', 'a'] }) - } - }) - - expect(serialized.filtersByWorkspaceId).toEqual({ - 'workspace-a': filter({ labelIds: ['a', 'b'] }) - }) - }) - // Overlength IDs can make a nonempty filter empty only after bounding. it('omits a filter that only becomes empty once bounded', () => { const serialized = serializeLinearIssueViewResumeState({ @@ -211,12 +103,6 @@ describe('selectLinearWorkspaceIssueFilter', () => { expect(selectLinearWorkspaceIssueFilter(filters, 'workspace-b')).toEqual(FILTER_B) }) - it('is unfiltered for a workspace with nothing saved', () => { - expect(selectLinearWorkspaceIssueFilter(filters, 'workspace-c')).toEqual( - emptyLinearIssueAttributeFilter() - ) - }) - it('never applies another workspace filter while Linear is unresolved or disconnected', () => { expect(selectLinearWorkspaceIssueFilter(filters, null)).toEqual( emptyLinearIssueAttributeFilter() @@ -248,19 +134,6 @@ describe('setLinearWorkspaceIssueFilter', () => { expect(selectLinearWorkspaceIssueFilter(filters, 'workspace-b')).toEqual(FILTER_B) }) - it('returns the same record when the canonical filter is unchanged', () => { - const filters = setLinearWorkspaceIssueFilter({}, 'workspace-a', FILTER_A) - - expect(setLinearWorkspaceIssueFilter(filters, 'workspace-a', { ...FILTER_A })).toBe(filters) - // Canonical-equivalent unsorted/duplicate IDs must preserve record identity too. - expect( - setLinearWorkspaceIssueFilter(filters, 'workspace-a', { - ...FILTER_A, - stateIds: ['state-a', 'state-a'] - }) - ).toBe(filters) - }) - it('removes the entry when the filter is cleared and leaves other workspaces alone', () => { let filters = setLinearWorkspaceIssueFilter({}, 'workspace-a', FILTER_A) filters = setLinearWorkspaceIssueFilter(filters, 'workspace-b', FILTER_B) @@ -281,57 +154,3 @@ describe('setLinearWorkspaceIssueFilter', () => { expect(setLinearWorkspaceIssueFilter(filters, '', FILTER_B)).toBe(filters) }) }) - -describe('startup sequences', () => { - const persisted = { - viewMode: 'board', - groupBy: 'status', - orderBy: 'updated', - displayProperties: ['state'], - teamPropertyTouched: true, - filtersByWorkspaceId: { 'workspace-a': FILTER_A, 'workspace-b': FILTER_B } - } - - it('cold start with the workspace already resolved shows that workspace filter', () => { - const restored = resolveLinearIssueViewResumeState(persisted) - - expect(selectLinearWorkspaceIssueFilter(restored.filtersByWorkspaceId, 'workspace-b')).toEqual( - FILTER_B - ) - expect(restored.viewMode).toBe('board') - }) - - it('cold start with the workspace resolving after hydration keeps the restored filter', () => { - const restored = resolveLinearIssueViewResumeState(persisted) - - // Hydration lands first with Linear still unresolved... - expect(selectLinearWorkspaceIssueFilter(restored.filtersByWorkspaceId, null)).toEqual( - emptyLinearIssueAttributeFilter() - ) - // ...and the workspace resolving later needs no reset effect to surface the filter. - expect(selectLinearWorkspaceIssueFilter(restored.filtersByWorkspaceId, 'workspace-a')).toEqual( - FILTER_A - ) - expect(serializeLinearIssueViewResumeState(restored)).toEqual(restored) - }) - - it('persists the full map when a workspace switch happens during startup', () => { - const restored = resolveLinearIssueViewResumeState(persisted) - // Linear resolves workspace-b mid-startup and the user edits its filter there. - const edited = setLinearWorkspaceIssueFilter( - restored.filtersByWorkspaceId, - 'workspace-b', - filter({ priorities: [0] }) - ) - - expect( - serializeLinearIssueViewResumeState({ ...restored, filtersByWorkspaceId: edited }) - ).toEqual({ - ...persisted, - filtersByWorkspaceId: { - 'workspace-a': FILTER_A, - 'workspace-b': filter({ priorities: [0] }) - } - }) - }) -}) diff --git a/src/shared/linear/links.test.ts b/src/shared/linear/links.test.ts index 7f63e16d00f..61dfcd594b0 100644 --- a/src/shared/linear/links.test.ts +++ b/src/shared/linear/links.test.ts @@ -1,55 +1,8 @@ import { describe, expect, it } from 'vitest' -import { - buildLinearIssueLinkUpdates, - buildLinearIssueUrl, - buildLinearPersonalApiKeySettingsUrl, - buildLinearTeamUrl, - buildLinearWorkspaceApiSettingsUrl, - getLinearOrganizationUrlKeyFromIssueUrl, - parseLinearIssueInput -} from './links' +import { buildLinearIssueLinkUpdates, parseLinearIssueInput } from './links' describe('linear links', () => { - it('builds team URLs from workspace and team keys', () => { - expect(buildLinearTeamUrl({ organizationUrlKey: 'acme', teamKey: 'ENG' })).toBe( - 'https://linear.app/acme/team/ENG/all' - ) - }) - - it('encodes URL path segments', () => { - expect(buildLinearTeamUrl({ organizationUrlKey: 'acme inc', teamKey: 'A/B' })).toBe( - 'https://linear.app/acme%20inc/team/A%2FB/all' - ) - }) - - it('extracts the workspace URL key from Linear issue URLs', () => { - expect(getLinearOrganizationUrlKeyFromIssueUrl('https://linear.app/acme/issue/ENG-1')).toBe( - 'acme' - ) - }) - - it('builds organization-scoped API key settings URLs', () => { - expect(buildLinearPersonalApiKeySettingsUrl('acme inc')).toBe( - 'https://linear.app/acme%20inc/settings/account/security' - ) - expect(buildLinearWorkspaceApiSettingsUrl('acme/inc')).toBe( - 'https://linear.app/acme%2Finc/settings/api' - ) - }) - - it('falls back to global API settings URLs when no organization slug is available', () => { - expect(buildLinearPersonalApiKeySettingsUrl()).toBe( - 'https://linear.app/settings/account/security' - ) - expect(buildLinearWorkspaceApiSettingsUrl(' ')).toBe('https://linear.app/settings/api') - }) - - it('parses bare Linear issue identifiers', () => { - expect(parseLinearIssueInput('eng-123')).toEqual({ identifier: 'ENG-123' }) - expect(parseLinearIssueInput('2eng-123')).toEqual({ identifier: '2ENG-123' }) - }) - it('parses Linear team keys that start with a digit', () => { for (const identifier of ['2eng-123', '1pass-42', '3d-15', '4k-12']) { expect(parseLinearIssueInput(` ${identifier} `)).toEqual({ @@ -78,21 +31,6 @@ describe('linear links', () => { } }) - it('parses Linear issue URLs with organization URL keys', () => { - expect(parseLinearIssueInput('https://linear.app/acme/issue/eng-123/fix-auth')).toEqual({ - identifier: 'ENG-123', - organizationUrlKey: 'acme' - }) - expect(parseLinearIssueInput('https://linear.app/acme/issue/2eng-123/fix-auth')).toEqual({ - identifier: '2ENG-123', - organizationUrlKey: 'acme' - }) - expect(parseLinearIssueInput('https://linear.app/stably/issue/STA-335/test-issue')).toEqual({ - identifier: 'STA-335', - organizationUrlKey: 'stably' - }) - }) - it('rejects non-Linear issue input', () => { expect(parseLinearIssueInput('https://example.com/acme/issue/ENG-123')).toBeNull() expect(parseLinearIssueInput('not an issue')).toBeNull() @@ -110,27 +48,6 @@ describe('linear links', () => { }) }) -describe('buildLinearIssueUrl', () => { - it('builds issue URLs from an identifier and organization key', () => { - expect(buildLinearIssueUrl({ identifier: 'STA-335', organizationUrlKey: 'acme' })).toBe( - 'https://linear.app/acme/issue/STA-335' - ) - }) - - it('returns null when either part is missing or blank', () => { - expect(buildLinearIssueUrl({ identifier: 'STA-335' })).toBeNull() - expect(buildLinearIssueUrl({ organizationUrlKey: 'acme' })).toBeNull() - expect(buildLinearIssueUrl({ identifier: ' ', organizationUrlKey: 'acme' })).toBeNull() - expect(buildLinearIssueUrl({ identifier: 'STA-335', organizationUrlKey: null })).toBeNull() - }) - - it('encodes URL-unsafe path segments', () => { - expect(buildLinearIssueUrl({ identifier: 'A/B-1', organizationUrlKey: 'acme inc' })).toBe( - 'https://linear.app/acme%20inc/issue/A%2FB-1' - ) - }) -}) - describe('buildLinearIssueLinkUpdates', () => { function expectNoUndefinedValues(updates: Record): void { expect(Object.keys(updates).filter((key) => updates[key] === undefined)).toEqual([]) @@ -169,9 +86,4 @@ describe('buildLinearIssueLinkUpdates', () => { }) expectNoUndefinedValues(result as Record) }) - - it('returns null for unparseable input', () => { - expect(buildLinearIssueLinkUpdates('not an issue')).toBeNull() - expect(buildLinearIssueLinkUpdates('https://github.com/o/r/issues/12')).toBeNull() - }) }) diff --git a/src/shared/linear/workspace-types.test.ts b/src/shared/linear/workspace-types.test.ts index 6f6174d0870..901ac642f4d 100644 --- a/src/shared/linear/workspace-types.test.ts +++ b/src/shared/linear/workspace-types.test.ts @@ -2,40 +2,6 @@ import { describe, expect, it } from 'vitest' import { linearWorkspaceScopeSignature, type LinearConnectionStatus } from './workspace-types' describe('linearWorkspaceScopeSignature', () => { - it('ignores status metadata and workspace ordering', () => { - const first: LinearConnectionStatus = { - connected: true, - viewer: { displayName: 'Ada', email: 'ada@example.com', organizationName: 'Alpha' }, - selectedWorkspaceId: 'workspace-1', - workspaces: [ - { - id: 'workspace-1', - organizationId: 'org-1', - organizationName: 'Alpha', - displayName: 'Ada', - email: 'ada@example.com' - }, - { - id: 'workspace-2', - organizationId: 'org-2', - organizationName: 'Beta', - displayName: 'Ada', - email: 'ada@example.com' - } - ] - } - const second: LinearConnectionStatus = { - ...first, - viewer: { ...first.viewer!, organizationName: 'Renamed' }, - workspaces: [ - { ...first.workspaces![1], organizationName: 'Renamed Beta' }, - { ...first.workspaces![0], organizationName: 'Renamed Alpha' } - ] - } - - expect(linearWorkspaceScopeSignature(second)).toBe(linearWorkspaceScopeSignature(first)) - }) - it('changes when the selected workspace changes', () => { const first: LinearConnectionStatus = { connected: true, diff --git a/src/shared/linux-wayland-session.test.ts b/src/shared/linux-wayland-session.test.ts index b3e246066b7..7474d5e5c33 100644 --- a/src/shared/linux-wayland-session.test.ts +++ b/src/shared/linux-wayland-session.test.ts @@ -2,17 +2,6 @@ import { describe, expect, it } from 'vitest' import { isLinuxWaylandSession } from './linux-wayland-session' describe('native Wayland session', () => { - it.each([{ WAYLAND_DISPLAY: 'wayland-1' }, { XDG_SESSION_TYPE: 'wayland' }])( - 'recognizes the session from %j', - (env) => { - expect(isLinuxWaylandSession({ platform: 'linux', env })).toBe(true) - } - ) - it('recognizes a command-line Wayland backend without a session hint', () => { - expect(isLinuxWaylandSession({ platform: 'linux', env: {}, ozonePlatform: 'wayland' })).toBe( - true - ) - }) it('honors explicit X11 overrides on Wayland desktops', () => { const env = { WAYLAND_DISPLAY: 'wayland-1', XDG_SESSION_TYPE: 'wayland' } expect(isLinuxWaylandSession({ platform: 'linux', env, ozonePlatform: 'x11' })).toBe(false) @@ -24,20 +13,6 @@ describe('native Wayland session', () => { }) ).toBe(true) }) - it('ignores the environment hint removed in Electron 38', () => { - expect( - isLinuxWaylandSession({ - platform: 'linux', - env: { XDG_SESSION_TYPE: 'wayland', ELECTRON_OZONE_PLATFORM_HINT: 'x11' } - }) - ).toBe(true) - expect( - isLinuxWaylandSession({ - platform: 'linux', - env: { ELECTRON_OZONE_PLATFORM_HINT: 'wayland' } - }) - ).toBe(false) - }) it.each(['x11', 'headless'])( 'honors the explicit %s backend despite Wayland variables', (ozonePlatform) => { @@ -81,10 +56,4 @@ describe('native Wayland session', () => { } } ) - it.each(['darwin', 'win32', 'linux'] as const)( - 'keeps ordinary %s sessions on their existing backend', - (platform) => { - expect(isLinuxWaylandSession({ platform, env: {} })).toBe(false) - } - ) }) diff --git a/src/shared/local-windows-terminal-runtime.test.ts b/src/shared/local-windows-terminal-runtime.test.ts index a8e7eecfa0f..190e67917a1 100644 --- a/src/shared/local-windows-terminal-runtime.test.ts +++ b/src/shared/local-windows-terminal-runtime.test.ts @@ -42,9 +42,4 @@ describe('resolveLocalWindowsTerminalRuntimeOptions: OpenSSH login shell', () => ) expect(shellFor({ setting: 'cmd.exe', sshLoginShell: LOGIN_SHELL })).toBe('cmd.exe') }) - - it('changes nothing without a login shell', () => { - expect(shellFor({ setting: 'powershell.exe' })).toBe('powershell.exe') - expect(shellFor({ hostProjectRuntime: true })).toBe('C:\\Windows\\System32\\cmd.exe') - }) }) diff --git a/src/shared/locale-text-collators.test.ts b/src/shared/locale-text-collators.test.ts deleted file mode 100644 index 63a15ba5b63..00000000000 --- a/src/shared/locale-text-collators.test.ts +++ /dev/null @@ -1,77 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { compareBaseSensitivityLocaleText, compareNumericLocaleText } from './locale-text-collators' - -function expectComparatorParity( - values: readonly string[], - legacy: (a: string, b: string) => number, - current: (a: string, b: string) => number -): void { - for (const a of values) { - for (const b of values) { - expect(Math.sign(current(a, b))).toBe(Math.sign(legacy(a, b))) - } - } - expect([...values].sort(current)).toEqual([...values].sort(legacy)) -} - -describe('locale text collators', () => { - it('preserves base-sensitivity localeCompare ordering', () => { - const values = [ - 'zeta', - 'Zeta', - 'Álpha', - 'alpha', - 'BÉTA', - 'beta', - 'café', - 'Cafe', - 'a-b', - 'a b', - 'a_b', - 'Ångström', - 'alpha' - ] - const legacy = (a: string, b: string) => a.localeCompare(b, undefined, { sensitivity: 'base' }) - - expectComparatorParity(values, legacy, compareBaseSensitivityLocaleText) - }) - - it('preserves numeric localeCompare ordering and ties', () => { - const values = [ - 'TASK-10', - 'TASK-2', - 'TASK-02', - 'TASK-1', - 'TASK-20', - 'TASK-11', - 'TASK_2', - 'task-2', - 'TASK-2' - ] - const legacy = (a: string, b: string) => a.localeCompare(b, undefined, { numeric: true }) - - expectComparatorParity(values, legacy, compareNumericLocaleText) - }) - - it('constructs each collator only when its comparison mode is first used', async () => { - vi.resetModules() - const NativeCollator = Intl.Collator - const collatorSpy = vi - .spyOn(Intl, 'Collator') - .mockImplementation(function Collator(locales, options) { - return new NativeCollator(locales, options) - }) - try { - const comparison = await import('./locale-text-collators') - expect(collatorSpy).not.toHaveBeenCalled() - comparison.compareNumericLocaleText('TASK-2', 'TASK-10') - comparison.compareNumericLocaleText('TASK-3', 'TASK-11') - expect(collatorSpy).toHaveBeenCalledTimes(1) - comparison.compareBaseSensitivityLocaleText('café', 'Cafe') - comparison.compareBaseSensitivityLocaleText('Álpha', 'alpha') - expect(collatorSpy).toHaveBeenCalledTimes(2) - } finally { - collatorSpy.mockRestore() - } - }) -}) diff --git a/src/shared/localhost-worktree-labels.test.ts b/src/shared/localhost-worktree-labels.test.ts index d1eba6de29b..cf8c7e2c08f 100644 --- a/src/shared/localhost-worktree-labels.test.ts +++ b/src/shared/localhost-worktree-labels.test.ts @@ -1,20 +1,7 @@ import { describe, expect, it } from 'vitest' -import { - getLocalhostWorktreeHostLabel, - getLocalhostWorktreeRouteKey -} from './localhost-worktree-labels' +import { getLocalhostWorktreeRouteKey } from './localhost-worktree-labels' describe('localhost worktree labels', () => { - it('uses the worktree folder name over branch owner prefixes for non-main labels', () => { - expect( - getLocalhostWorktreeHostLabel({ - projectName: 'Snap Studio', - worktreeName: 'gatsby74/table-summary', - worktreePath: '/Users/example/orca/workspaces/snapstudio/ui-auth' - }) - ).toBe('ui-auth') - }) - it('keeps route keys unique for different ports in the same worktree', () => { const route = { projectName: 'Snap Studio', diff --git a/src/shared/loose-ref-count.test.ts b/src/shared/loose-ref-count.test.ts index 5a25d571c6d..1a3247b9698 100644 --- a/src/shared/loose-ref-count.test.ts +++ b/src/shared/loose-ref-count.test.ts @@ -73,35 +73,6 @@ describe('countLooseRefs', () => { }) }) - it('never has more than one directory read outstanding', async () => { - // Sequential reads occupy at most one shared libuv slot, leaving unrelated filesystem work unblocked. - const refs = await makeRefsTree({ - 'remotes/a': 3, - 'remotes/b': 3, - 'remotes/c': 3, - 'remotes/d': 3, - 'remotes/e/deep': 3 - }) - readdirCalls.peak = 0 - readdirCalls.count = 0 - - await countLooseRefs(refs, 1000) - - expect(readdirCalls.count).toBeGreaterThan(1) - expect(readdirCalls.peak).toBe(1) - }) - - it('reads each directory once rather than streaming it in batches', async () => { - // One round trip per directory measured ~8x faster than streaming on a degraded repository. - const refs = await makeRefsTree({ 'remotes/origin': 400 }) - readdirCalls.count = 0 - - await countLooseRefs(refs, 1000) - - // refs/ plus refs/remotes plus refs/remotes/origin. - expect(readdirCalls.count).toBe(3) - }) - it('does not follow directory symlinks into a loop', async () => { const refs = await makeRefsTree({ heads: 2 }) await symlink(refs, join(refs, 'loop'), 'dir') diff --git a/src/shared/machine-name.test.ts b/src/shared/machine-name.test.ts deleted file mode 100644 index 941ab2c2255..00000000000 --- a/src/shared/machine-name.test.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { normalizeMachineName } from './machine-name' - -describe('normalizeMachineName', () => { - it('trims surrounding whitespace', () => { - expect(normalizeMachineName(' Build server \n')).toBe('Build server') - }) - - it('caps the stored length after trimming', () => { - expect(normalizeMachineName(` ${'x'.repeat(255)} `)).toBe('x'.repeat(255)) - expect(normalizeMachineName(` ${'x'.repeat(256)} `)).toBe('x'.repeat(255)) - }) - - it('reads anything that is not a string as the detected-name default', () => { - expect(normalizeMachineName(undefined)).toBe('') - expect(normalizeMachineName(null)).toBe('') - expect(normalizeMachineName(42)).toBe('') - expect(normalizeMachineName(' ')).toBe('') - }) -}) diff --git a/src/shared/macos-symbolic-hotkeys.test.ts b/src/shared/macos-symbolic-hotkeys.test.ts index 40c87ed5941..1f1c965dacf 100644 --- a/src/shared/macos-symbolic-hotkeys.test.ts +++ b/src/shared/macos-symbolic-hotkeys.test.ts @@ -72,14 +72,6 @@ describe('capturedDigitRowChordsFromSymbolicHotkeysJson', () => { }) expect(chords).toEqual([]) }) - - it('returns empty for missing or non-object domains', () => { - expect(capturedDigitRowChordsFromSymbolicHotkeysJson(null)).toEqual([]) - expect(capturedDigitRowChordsFromSymbolicHotkeysJson({})).toEqual([]) - expect( - capturedDigitRowChordsFromSymbolicHotkeysJson({ AppleSymbolicHotKeys: 'bogus' }) - ).toEqual([]) - }) }) function physicalChord( @@ -149,10 +141,4 @@ describe('findMacSystemHotkeyConflicts', () => { { actionId: 'workspace.selectByIndex', binding: 'Ctrl+1', capturedBindings: ['Ctrl+3'] } ]) }) - - it('returns empty without captured chords', () => { - expect(findMacSystemHotkeyConflicts(KEYBINDING_DEFINITIONS, 'darwin', undefined, [])).toEqual( - [] - ) - }) }) diff --git a/src/shared/managed-orcad-execution-host.test.ts b/src/shared/managed-orcad-execution-host.test.ts index 67d4d1b3d8f..a547ccc73e8 100644 --- a/src/shared/managed-orcad-execution-host.test.ts +++ b/src/shared/managed-orcad-execution-host.test.ts @@ -148,19 +148,6 @@ describe('managed Orca server host merging', () => { ) }) - it('names the merged row with a rename saved on either id', () => { - const hosts = buildExecutionHostRegistry({ - repos: [], - settings: null, - hostSource: 'configured-only', - sshTargetLabels: SSH_TARGETS, - runtimeEnvironments: [MANAGED_SERVER], - hostLabelOverrides: new Map([['ssh:omarchy-target', 'Build box']]) - }) - - expect(hosts.find((host) => host.id === 'runtime:omarchy-server')?.label).toBe('Build box') - }) - it('widens a host scope an older build saved with only one id of the pair', () => { const hosts = registry({ kind: 'managed', environmentId: 'omarchy-server' }) diff --git a/src/shared/managed-orcad-ssh-owner.test.ts b/src/shared/managed-orcad-ssh-owner.test.ts index 4e4201def43..40ee7377346 100644 --- a/src/shared/managed-orcad-ssh-owner.test.ts +++ b/src/shared/managed-orcad-ssh-owner.test.ts @@ -2,8 +2,7 @@ import { describe, expect, it } from 'vitest' import { getLegacyManagedOrcadOwnerEnvironmentId, getManagedOrcadFenceEnvironmentId, - isEphemeralRuntimeSshOwner, - managedOrcadServerName + isEphemeralRuntimeSshOwner } from './managed-orcad-ssh-owner' describe('managed orcad SSH fence', () => { @@ -33,16 +32,4 @@ describe('managed orcad SSH fence', () => { expect(getLegacyManagedOrcadOwnerEnvironmentId(owner)).toBeNull() expect(isEphemeralRuntimeSshOwner(owner)).toBe(true) }) - - it("names a recipe VM's server after its runtime, so two VMs of one recipe never collide", () => { - const owner = { type: 'on-demand-runtime' as const, runtimeId: 'runtime-0123456789abcdef' } - expect(managedOrcadServerName({ label: 'Docker root', owner })).toBe('Docker root VM 89abcdef') - expect( - managedOrcadServerName({ - label: 'Docker root', - owner: { ...owner, runtimeId: 'runtime-fedcba9876543210' } - }) - ).toBe('Docker root VM 76543210') - expect(managedOrcadServerName({ label: 'Builder' })).toBe('Builder') - }) }) diff --git a/src/shared/manual-repo-order.test.ts b/src/shared/manual-repo-order.test.ts index 20d8b514aea..7ba44b45f69 100644 --- a/src/shared/manual-repo-order.test.ts +++ b/src/shared/manual-repo-order.test.ts @@ -24,34 +24,6 @@ const remoteCharlie = repo('charlie', 'runtime:node-b') const remoteDelta = repo('delta', 'runtime:node-b') describe('manual repo order', () => { - it('returns the input array when no overlay exists', () => { - const repos = [localBravo, localAlpha] - - expect(applyManualRepoOrder(repos, [])).toBe(repos) - }) - - it('returns the input array when the saved order moves nothing', () => { - const repos = [localAlpha, remoteCharlie, localBravo, remoteDelta] - - expect(applyManualRepoOrder(repos, getManualRepoOrder(repos))).toBe(repos) - }) - - it('returns a new array when the saved order actually reorders', () => { - const repos = [localBravo, localAlpha] - const reordered = applyManualRepoOrder(repos, getManualRepoOrder([localAlpha, localBravo])) - - expect(reordered).not.toBe(repos) - expect(reordered).toEqual([localAlpha, localBravo]) - }) - - it('restores a host-qualified cross-host interleaving', () => { - const order = getManualRepoOrder([localAlpha, remoteCharlie, localBravo, remoteDelta]) - - expect( - applyManualRepoOrder([remoteCharlie, remoteDelta, localAlpha, localBravo], order) - ).toEqual([localAlpha, remoteCharlie, localBravo, remoteDelta]) - }) - it('places a late host into its saved positions', () => { const order = getManualRepoOrder([localAlpha, remoteCharlie, localBravo, remoteDelta]) const localOnly = applyManualRepoOrder([localBravo, localAlpha], order) @@ -72,19 +44,6 @@ describe('manual repo order', () => { expect(applyManualRepoOrder([local, remote], order)).toEqual([remote, local]) }) - it('appends unranked repos in their source order', () => { - const newOne = repo('new-one', 'local') - const newTwo = repo('new-two', 'runtime:node-b') - const order = getManualRepoOrder([remoteCharlie, localAlpha]) - - expect(applyManualRepoOrder([newTwo, localAlpha, newOne, remoteCharlie], order)).toEqual([ - remoteCharlie, - localAlpha, - newTwo, - newOne - ]) - }) - it('normalizes malformed, invalid-host, and duplicate entries', () => { const value = [ null, diff --git a/src/shared/map-with-concurrency.test.ts b/src/shared/map-with-concurrency.test.ts index e966bd57299..9b3793cb2d0 100644 --- a/src/shared/map-with-concurrency.test.ts +++ b/src/shared/map-with-concurrency.test.ts @@ -76,23 +76,6 @@ describe('mapWithConcurrency', () => { expect(peak).toBe(8) }) - it('processes every item exactly once', async () => { - const seen: number[] = [] - await mapWithConcurrency([1, 2, 3, 4, 5], 2, async (n) => { - seen.push(n) - }) - expect(seen.sort((a, b) => a - b)).toEqual([1, 2, 3, 4, 5]) - }) - - it('returns an empty array for no items without spawning workers', async () => { - let calls = 0 - const results = await mapWithConcurrency([], 4, async () => { - calls += 1 - }) - expect(results).toEqual([]) - expect(calls).toBe(0) - }) - it('clamps a limit below one to a single worker instead of stalling', async () => { const results = await mapWithConcurrency([1, 2, 3], 0, async (n) => n * 2) expect(results).toEqual([2, 4, 6]) diff --git a/tests/e2e/agent-model-catalog-renderer-cache.unit.test.ts b/tests/e2e/agent-model-catalog-renderer-cache.unit.test.ts index cb0572b3a8e..8187d8d4abc 100644 --- a/tests/e2e/agent-model-catalog-renderer-cache.unit.test.ts +++ b/tests/e2e/agent-model-catalog-renderer-cache.unit.test.ts @@ -17,7 +17,6 @@ vi.mock('@/runtime/hosts/capabilities/local-runtime-capabilities', () => ({ readLocalRuntimeCapabilitiesOrUnknown: () => [] })) -import { discoverNativeChatCatalogModels } from '../../src/renderer/src/components/native-chat/native-chat-session-option-discovery' import type { AgentModelCatalogProbe } from '../../src/main/native-chat/agent-model-catalog/agent-model-catalog-discovery' import { createAgentModelCatalogService } from '../../src/main/native-chat/agent-model-catalog/agent-model-catalog-service' import { AgentModelCatalogStore } from '../../src/main/native-chat/agent-model-catalog/agent-model-catalog-store' @@ -172,40 +171,4 @@ describe('account catalog to renderer cache', () => { } } ) - - it.each(['claude', 'codex'] as const)( - 'terminal discovery consumes the real %s accepted response after a failed refresh', - async (agent) => { - const h = hostCatalog(agent) - h.listing.models.push({ - ...h.listing.models[0], - id: 'other-model', - label: 'Other', - isDefault: false - }) - try { - await h.service.demand({ agent }) - h.probe.resolve.mockRejectedValue(new Error('scope lookup failed')) - await h.service.demand({ agent }) - mocks.call.mockImplementation((_target, _method, params: { agent: string }) => - h.service.read(params) - ) - const models = await discoverNativeChatCatalogModels( - agent, - { target: LOCAL, worktreeId: null, worktreePath: '' }, - 'local' - ) - expect(mocks.call).toHaveBeenCalledWith(LOCAL, 'agentSession.modelCatalog', { agent }) - expect( - models?.map(({ id, label, isDefault }) => ({ id, label, isDefault: !!isDefault })) - ).toEqual([ - { id: 'account-model', label: 'Account model', isDefault: true }, - { id: 'other-model', label: 'Other', isDefault: false } - ]) - expect(mocks.cli).not.toHaveBeenCalled() - } finally { - h.service.stop() - } - } - ) }) diff --git a/tests/e2e/ai-vault-account-stream.unit.test.ts b/tests/e2e/ai-vault-account-stream.unit.test.ts index 00713c1ea35..42f57242d4f 100644 --- a/tests/e2e/ai-vault-account-stream.unit.test.ts +++ b/tests/e2e/ai-vault-account-stream.unit.test.ts @@ -1,5 +1,4 @@ // @vitest-environment happy-dom -import { renderToString } from 'react-dom/server' import { act, render } from '@testing-library/react' import { afterEach, expect, it, vi } from 'vitest' import * as fs from 'node:fs' @@ -9,11 +8,10 @@ import { nativeClient } from '@/components/right-sidebar/ai-vault/accounts/ai-va import type { AiVaultSession } from '../../src/shared/ai-vault/contracts/ai-vault-types' import { decodeAccountsSnapshot } from '../../mobile/src/components/accounts-snapshot' import { createRateLimitsApi } from '@/web/preload-api/web-rate-limits-api' -import { accountStreamFixture, P, Q, D, profile } from './ai-vault-account-stream-test-fixture' +import { accountStreamFixture, P, profile } from './ai-vault-account-stream-test-fixture' import { accountSettings, accountCards, - accountRenders, details, recordedSession, flushAccountWork, @@ -45,136 +43,6 @@ function dataSession(id = 'p', profileId = P): AiVaultSession { accountHome: { kind: 'opencode', locator: { kind: 'managed', managedProfileId: profileId } } } } -const oneProducer = { lists: 2, reads: 2, parses: 2, claude: 1, codex: 1, frames: 1, listData: 0 } - -it.each([2, 20])( - 'bounds real stream production and retirement at %i readers/reacquisitions', - async (count) => { - const source = (fixture = accountStreamFixture()) - const sessions = Array.from({ length: count }, (_, i) => dataSession(`p-${i}`)) - expect(renderToString(accountCards(sessions))).toContain('Unknown') - expect(source.subscribe).not.toHaveBeenCalled() - const panel = render(accountCards(sessions)) - await flushAccountWork() - expect(source.subscribe).toHaveBeenCalledTimes(1) - expect(source.listenerCounts()).toEqual([1, 1]) - expect(source.counters()).toEqual(oneProducer) - expect(source.refresh).toHaveBeenCalledTimes(1) - expect(panel.getByTestId('p-0').textContent).toContain('Work') - // Sequential acquires, including another binding, reuse the live source and ready proof. - const q = dataSession('q', Q) - panel.rerender(accountCards([...sessions, q])) - await flushAccountWork() - expect(source.subscribe).toHaveBeenCalledTimes(1) - expect(source.counters()).toEqual(oneProducer) - const events = [ - () => source.usage.publish(), - () => source.controller.selectData('devin', D), - () => { - source.seed('opencode', [profile(P, 'Work'), profile(Q, 'Other changed')]) - return source.controller.selectData('opencode', Q) - }, - () => source.controller.selectData('opencode', null) - ] - for (const event of events) { - source.observations.length = 0 - accountRenders.clear() - await act(async () => { - await event() - }) - expect(source.observations).toEqual([oneProducer]) - for (const session of sessions) { - expect(accountRenders.get(session.id) ?? 0).toBe(0) - } - expect(panel.getByTestId('p-0').textContent).toContain('Work') - } - accountRenders.clear() - const beforeReplay = source.counters() - await act(async () => source.slots[0]!.emit(source.frames.at(-1))) - expect(source.counters()).toEqual({ ...beforeReplay, frames: beforeReplay.frames + 1 }) - expect(accountRenders.size).toBe(0) - source.seed('opencode', [profile(P, 'Renamed'), profile(Q, 'Other changed')]) - await act(async () => { - await source.controller.selectData('opencode', Q) - }) - expect(panel.getByTestId('p-0').textContent).toContain('Renamed') - expect(accountRenders.get('q') ?? 0).toBe(0) - for (const session of sessions) { - expect(accountRenders.get(session.id)).toBeGreaterThan(0) - } - // Removing one reader does not close siblings; last reader removes both source listeners. - panel.rerender(accountCards(sessions.slice(1))) - await flushAccountWork() - expect(source.listenerCounts()).toEqual([1, 1]) - panel.unmount() - await flushAccountWork() - expect(source.listenerCounts()).toEqual([0, 0]) - expect(source.slots[0]!.unsubscribe).toHaveBeenCalledTimes(1) - expect(source.pendingStreams()).toBe(0) - expect(source.subscriptions).toHaveProperty('cleanups.size', 0) - - // Independent desktop subscribers share the document, never each other's registration. - const siblingFrames = vi.fn() - const sibling = await source.subscribe({ method: 'accounts.subscribe' }, siblingFrames) - await flushAccountWork() - for (let cycle = 0; cycle < count; cycle++) { - const reopened = render(accountCards([dataSession()])) - await flushAccountWork() - expect(source.listenerCounts()).toEqual([2, 2]) - expect(source.pendingStreams()).toBe(2) - expect(source.subscriptions).toHaveProperty('cleanups.size', 2) - source.seed('opencode', [profile(P, `Cycle ${cycle}`), profile(Q, 'Other')]) - source.observations.length = 0 - accountRenders.clear() - const siblingBefore = siblingFrames.mock.calls.length - await act(async () => { - await source.controller.selectData('opencode', null) - }) - expect(source.observations).toEqual([oneProducer, oneProducer]) - expect(reopened.getByTestId('p').textContent).toContain(`Cycle ${cycle}`) - expect(accountRenders.get('p')).toBeGreaterThan(0) - expect(siblingFrames.mock.calls.length).toBe(siblingBefore + 1) - reopened.unmount() - await flushAccountWork() - expect(source.listenerCounts()).toEqual([1, 1]) - expect(source.pendingStreams()).toBe(1) - expect(source.subscriptions).toHaveProperty('cleanups.size', 1) - expect(source.subscriptions).toHaveProperty('cleanupPromises.size', 0) - expect(source.transportListeners()).toBe(1) - source.observations.length = 0 - accountRenders.clear() - await act(async () => source.usage.publish()) - expect(source.observations).toEqual([oneProducer]) - expect(accountRenders.size).toBe(0) - } - sibling.unsubscribe() - await flushAccountWork() - expect(source.listenerCounts()).toEqual([0, 0]) - expect(source.pendingStreams()).toBe(0) - expect(source.transportListeners()).toBe(0) - expect(source.subscriptions).toMatchObject({ - cleanups: new Map(), - cleanupPromises: new Map(), - subscriptionsByConnection: new Map(), - connectionBySubscription: new Map(), - subscriptionsByRequest: new Map() - }) - const retired = source.counters() - source.observations.length = 0 - await act(async () => source.usage.publish()) - expect(source.counters()).toEqual(retired) - await act(async () => { - await source.controller.selectData('devin', D) - }) - expect(source.observations).toEqual([]) - expect(source.counters()).toMatchObject({ - claude: retired.claude, - codex: retired.codex, - frames: retired.frames - }) - expect(accountRenders.size).toBe(0) - } -) it('isolates real optional-registry failures in ready/data/usage while keeping strict and mobile/web consumers', async () => { const source = (fixture = accountStreamFixture())