From 3db779d412f5082d581a6982c772795ab8eaecb7 Mon Sep 17 00:00:00 2001 From: OrcaWin <293788423+OrcaWin@users.noreply.github.com> Date: Fri, 13 Nov 2026 20:32:28 -0800 Subject: [PATCH] test: remove mock-only suites and native text-entry harness --- config/reliability-gates.jsonc | 6 +- .../verify-computer-native.mjs | 13 -- .../runtime-text-entry.test.ps1 | 189 ------------------ src/main/ipc/agent-hooks.test.ts | 155 -------------- src/main/ipc/notebook-project-link.test.ts | 102 ---------- .../screencast/browser-screencasts.test.ts | 136 ------------- ...-runtime-browser-screencast-fanout.test.ts | 91 --------- .../useTabGroupCloseScopeCommands.test.tsx | 28 +-- .../src/web/web-file-mutation-methods.test.ts | 91 --------- 9 files changed, 4 insertions(+), 807 deletions(-) delete mode 100644 native/computer-use-windows/runtime-text-entry.test.ps1 delete mode 100644 src/main/ipc/agent-hooks.test.ts delete mode 100644 src/main/ipc/notebook-project-link.test.ts delete mode 100644 src/main/runtime/browser/screencast/browser-screencasts.test.ts delete mode 100644 src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts delete mode 100644 src/renderer/src/web/web-file-mutation-methods.test.ts diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index 25c17533c17..17cf1049340 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -5365,7 +5365,7 @@ "pnpm exec vitest run --config config/vitest.config.ts src/shared/remote-runtime/remote-runtime-client.test.ts src/main/ipc/runtime-environments/browser-hosting/runtime-environment-browser-client-host-handler.test.ts", "SKIP_BUILD=1 ORCA_CROSS_VERSION_PACKAGED_EXECUTABLE=/Applications/Orca.app/Contents/MacOS/Orca pnpm exec playwright test tests/e2e/packaged-mixed-version-browser-placement.spec.ts --config tests/playwright.config.ts --project electron-headless --workers=1", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/browser/network/browser-network-tunnel-paired-runtime.integration.test.ts src/main/browser/network/execution-routes/paired-runtime-browser-network-route.test.ts src/main/browser/network/execution-routes/browser-network-execution-route.test.ts src/main/browser/network/execution-routes/wsl-browser-network-execution-route.test.ts src/main/browser/network/execution-routes/wsl-browser-network-relay-launch.test.ts src/main/runtime/browser/network/runtime-browser-network-execution-host.test.ts", - "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/cdp/screencast/browser-screencast-stream.test.ts src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts", + "pnpm exec vitest run --config config/vitest.config.ts src/main/browser/cdp/screencast/browser-screencast-stream.test.ts", "ORCA_RUN_DOCKER_SSH_BROWSER_E2E=1 pnpm exec vitest run --config config/vitest.config.ts tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts", "Manual iOS 26.5 simulator: pair current mobile code to packaged Orca 1.4.184; create Browser; navigate to https://example.com; require one visible Example Domain tab on the server-hosted surface", "ORCA_RUN_DOCKER_SSH_BROWSER_E2E=1 node_modules/.bin/vitest run --config config/vitest.config.ts tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts" @@ -5384,7 +5384,6 @@ "src/main/browser/network/execution-routes/wsl-browser-network-relay-launch.test.ts", "src/main/runtime/browser/network/runtime-browser-network-execution-host.test.ts", "src/main/browser/cdp/screencast/browser-screencast-stream.test.ts", - "src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts", "tests/e2e/ssh-browser-network-execution-route.docker.unit.test.ts" ], "assertionRefs": [ @@ -6169,7 +6168,7 @@ "commands": [ "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/terminal/surface/orca-runtime-terminal-close-continuity.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/construction/orca-runtime.test.ts", - "pnpm dlx node@24 ./node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/agent-hooks/server/testing/authority/server-pane-authority.test.ts src/main/ipc/agent-hooks.test.ts src/main/ipc/agent-pane-authority-ownership.test.ts src/main/persistence/restoring-sessions/persistence-pane-identity-migration.test.ts src/main/persistence/loading-store/terminal-bindings/persistence-pty-binding-reconciliation.test.ts src/renderer/src/store/slices/agent-status/agent-pane-authority.test.ts src/renderer/src/store/terminals/layout/terminal-pane-detach-agent-identity.test.ts src/renderer/src/store/terminals/retirement/terminal-tab-retirement-store.test.ts src/renderer/src/components/shared/kill-all-terminal-surfaces.test.ts", + "pnpm dlx node@24 ./node_modules/vitest/vitest.mjs run --config config/vitest.config.ts src/main/agent-hooks/server/testing/authority/server-pane-authority.test.ts src/main/ipc/agent-pane-authority-ownership.test.ts src/main/persistence/restoring-sessions/persistence-pane-identity-migration.test.ts src/main/persistence/loading-store/terminal-bindings/persistence-pty-binding-reconciliation.test.ts src/renderer/src/store/slices/agent-status/agent-pane-authority.test.ts src/renderer/src/store/terminals/layout/terminal-pane-detach-agent-identity.test.ts src/renderer/src/store/terminals/retirement/terminal-tab-retirement-store.test.ts src/renderer/src/components/shared/kill-all-terminal-surfaces.test.ts", "pnpm exec vitest run --config config/vitest.config.ts src/main/pty/process-retirement/pty-descendant-termination.test.ts src/main/daemon/terminal-host/testing/terminal-host.test.ts src/main/providers/local-pty/local-pty-provider-shutdown.test.ts src/main/runtime/workspaces/removal/worktree-teardown.test.ts", "pnpm run test:e2e -- tests/e2e/terminal-tab-close-restart-persistence.spec.ts --workers=1", "pnpm run test:e2e -- tests/e2e/terminal-parked-close-retirement.spec.ts --workers=1", @@ -6181,7 +6180,6 @@ "src/main/runtime/terminal/surface/orca-runtime-terminal-close-continuity.test.ts", "src/main/runtime/construction/orca-runtime.test.ts", "src/main/agent-hooks/server/testing/authority/server-pane-authority.test.ts", - "src/main/ipc/agent-hooks.test.ts", "src/main/ipc/agent-pane-authority-ownership.test.ts", "src/main/persistence/restoring-sessions/persistence-pane-identity-migration.test.ts", "src/main/persistence/loading-store/terminal-bindings/persistence-pty-binding-reconciliation.test.ts", diff --git a/config/scripts/runtime-verification/desktop-transport/verify-computer-native.mjs b/config/scripts/runtime-verification/desktop-transport/verify-computer-native.mjs index 9c07d8a1e74..503a84fd04f 100644 --- a/config/scripts/runtime-verification/desktop-transport/verify-computer-native.mjs +++ b/config/scripts/runtime-verification/desktop-transport/verify-computer-native.mjs @@ -75,19 +75,6 @@ const checks = [ ], enabled: process.platform === 'win32' }, - { - name: 'Windows text entry tests', - command: 'powershell.exe', - args: [ - '-NoLogo', - '-NoProfile', - '-ExecutionPolicy', - 'Bypass', - '-File', - 'native/computer-use-windows/runtime-text-entry.test.ps1' - ], - enabled: process.platform === 'win32' - }, { name: 'Windows native control tests', command: 'powershell.exe', diff --git a/native/computer-use-windows/runtime-text-entry.test.ps1 b/native/computer-use-windows/runtime-text-entry.test.ps1 deleted file mode 100644 index f53961aad7b..00000000000 --- a/native/computer-use-windows/runtime-text-entry.test.ps1 +++ /dev/null @@ -1,189 +0,0 @@ -param([string]$RuntimePath = (Join-Path $PSScriptRoot "runtime.ps1")) - -$ErrorActionPreference = "Stop" - -function Assert-TestEqual($Actual, $Expected, [string]$Label) { - if ($Actual -cne $Expected) { throw "$Label expected '$Expected', received '$Actual'" } -} - -Add-Type -TypeDefinition @" -using System; -using System.Collections.Generic; - -public static class OrcaDesktopWin32 { - public static readonly List Calls = new List(); - public static IntPtr Foreground; - public static string EditText; - public static int[] Selection; - public static int EditOwner; - public static bool IgnoreInsertion; - public static long Limit; - - public static void Reset(string text, int start, int end) { - Calls.Clear(); - Foreground = new IntPtr(202); - EditText = text; - Selection = new[] { start, end }; - EditOwner = 4242; - IgnoreInsertion = false; - Limit = 30000; - } - public static int GetProcessIntegrityLevel(int processId) { return 0x2000; } - public static IntPtr GetForegroundWindow() { return Foreground; } - public static bool SetForegroundWindow(IntPtr hwnd) { Calls.Add("activate"); return false; } - public static bool IsIconic(IntPtr hwnd) { return false; } - public static bool ShowWindow(IntPtr hwnd, int command) { Calls.Add("restore"); return true; } - public static bool IsWindow(IntPtr hwnd) { return true; } - public static int GetWindowLong(IntPtr hwnd, int index) { return 0x0004; } - public static uint GetWindowThreadProcessId(IntPtr hwnd, out uint processId) { - processId = hwnd == new IntPtr(303) ? (uint)EditOwner : (hwnd == new IntPtr(101) ? 4242u : 1u); - return 1; - } - public static string GetEditText(IntPtr hwnd, int maxLength) { return EditText; } - public static int[] GetEditSelection(IntPtr hwnd) { return Selection; } - public static bool ReplaceEditSelection(IntPtr hwnd, string text) { - Calls.Add("replace:" + text); - if (!IgnoreInsertion) { - EditText = EditText.Substring(0, Selection[0]) + text + EditText.Substring(Selection[1]); - } - return true; - } - public static bool SendUnicodeText(string text) { Calls.Add("keys:" + text); return true; } - public static long? SendControlMessage(IntPtr hwnd, uint message, IntPtr wParam, IntPtr lParam) { return message == 0x00D5 ? Limit : 0; } -} -"@ - -$tokens = $null -$errors = $null -$ast = [System.Management.Automation.Language.Parser]::ParseFile($RuntimePath, [ref]$tokens, [ref]$errors) -if ($errors.Count) { throw ($errors | Out-String) } -$functions = @( - "Test-OrcaWindowFocused", "Wait-OrcaWindowFocused", "Assert-OrcaKeyboardFocus", "New-OrcaForegroundRefusal", - "Assert-OrcaWindowTarget", "Get-OrcaRequiredString", "Invoke-OrcaOperation", - "Assert-OrcaInputAllowed", "Test-OrcaTargetTookForeground", "Get-OrcaProperty", "Test-OrcaSensitiveElement", - "Test-OrcaEditClass", "Get-OrcaNativeEdit", "Assert-OrcaWindowOwner", "Test-OrcaNativeClass", "ConvertTo-OrcaEditNewlines", - "Invoke-OrcaEditTextInsertion", "Invoke-OrcaElementTextInsertion", "Send-OrcaText", - "Test-OrcaElementDisabled", "Assert-OrcaStillFocused" -) -foreach ($definition in $ast.FindAll({ param($node) $node -is [System.Management.Automation.Language.FunctionDefinitionAst] }, $false)) { - if ($definition.Name -in $functions) { . ([scriptblock]::Create($definition.Extent.Text)) } -} - -$EditReadbackLimit = 1048576 -function Find-OrcaProcess { [pscustomobject]@{ MainWindowHandle = 101; Id = 4242; ProcessName = "Fixture" } } -function Get-OrcaAppName($Process) { $Process.ProcessName } -function Get-OrcaRootElement { $null } -function Get-OrcaWindowFrame { @{ x = 100; y = 200 } } -function Find-OrcaElement($RootElement, $Record) { if ($null -eq $Record) { $null } else { $Record.live } } -function Invoke-OrcaValueTextInsertion { $script:valueWrites++; $null } -function Send-OrcaKey { [OrcaDesktopWin32]::Calls.Add("sendkeys") } -function Send-OrcaHotkey { [OrcaDesktopWin32]::Calls.Add("sendkeys") } -function Send-OrcaPasteText { [OrcaDesktopWin32]::Calls.Add("sendkeys") } -function New-OrcaSnapshot { [pscustomobject]@{} } -function Test-OrcaTextPatternReadOnly { $false } -function Restore-OrcaWindow { [OrcaDesktopWin32]::Calls.Add("activate"); $null } - -function New-TestElement([string]$ClassName, [int64]$Handle, [bool]$Enabled = $true, [string]$ControlType = "ControlType.Document") { - $live = [pscustomobject]@{ - Current = [pscustomobject]@{ - ClassName = $ClassName; NativeWindowHandle = $Handle; IsPassword = $false; IsEnabled = $Enabled; Name = "Body" - AutomationId = ""; LocalizedControlType = "document"; ControlType = [pscustomobject]@{ ProgrammaticName = $ControlType } - } - } - [pscustomobject]@{ index = 7; live = $live } -} - -function Invoke-TestOperation($Operation) { - $message = $null - $result = $null - try { $result = Invoke-OrcaOperation $Operation } catch { $message = $_.Exception.Message } - [pscustomobject]@{ result = $result; message = $message } -} - -# Background keyboard verbs refuse before any key leaves, and say how to enter text without the foreground. -foreach ($operation in @( - [pscustomobject]@{ tool = "type_text"; text = "hello" }, - [pscustomobject]@{ tool = "paste_text"; text = "hello" }, - [pscustomobject]@{ tool = "press_key"; key = "Return" }, - [pscustomobject]@{ tool = "hotkey"; key = "Ctrl+A" } -)) { - [OrcaDesktopWin32]::Reset("", 0, 0) - $operation | Add-Member -NotePropertyName app -NotePropertyValue "Fixture" - $outcome = Invoke-TestOperation $operation - if ($outcome.message -notlike "background_unavailable: *takes the user's keyboard; nothing was sent.*type-text --element-index*Ask the user before retrying with --restore-window.") { - throw "$($operation.tool) background refusal, received '$($outcome.message)'" - } - Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count) 0 "$($operation.tool) background refusal sends nothing" -} - -# Typing into a native edit replaces its selection in the background and reads the result back. -[OrcaDesktopWin32]::Reset("one`r`nthree", 3, 3) -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "`ntwo"; element = (New-TestElement "Edit" 303) }) -if ($null -ne $outcome.message) { throw "edit insertion failed: $($outcome.message)" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls -join "|") "replace:`r`ntwo" "edit insertion sends one EM_REPLACESEL with CRLF line breaks" -Assert-TestEqual ([OrcaDesktopWin32]::EditText) "one`r`ntwo`r`nthree" "edit insertion result" -Assert-TestEqual $outcome.result.action.actionName "EM_REPLACESEL" "edit insertion action" -Assert-TestEqual $outcome.result.action.delivery "background" "edit insertion delivery" -Assert-TestEqual $outcome.result.action.verification.state "verified" "edit insertion verification" - -# A field that ignores the insertion is an error, not a typed result. -[OrcaDesktopWin32]::Reset("same", 4, 4) -[OrcaDesktopWin32]::IgnoreInsertion = $true -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "x"; element = (New-TestElement "Edit" 303) }) -if ($outcome.message -notlike "text_insertion_unconfirmed:*") { throw "ignored insertion, received '$($outcome.message)'" } - -# Replacing a selection with the same text changes nothing yet is the requested result. -[OrcaDesktopWin32]::Reset("abc", 0, 3) -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "abc"; element = (New-TestElement "Edit" 303) }) -if ($null -ne $outcome.message) { throw "identical replacement failed: $($outcome.message)" } -Assert-TestEqual $outcome.result.action.verification.state "verified" "identical replacement verification" - -# An edit cuts text past its limit, so an insertion that would overflow it is refused before anything is sent. -[OrcaDesktopWin32]::Reset("old", 3, 3) -[OrcaDesktopWin32]::Limit = 5 -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "abc"; element = (New-TestElement "Edit" 303) }) -if ($outcome.message -notlike "element 7 text is not settable: the result would be 6 characters, past the field's 5-character limit") { throw "over-limit insertion, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::EditText) "old" "over-limit insertion leaves the field untouched" - -# A password field can't be read back, yet its limit still holds. -[OrcaDesktopWin32]::Reset("", 0, 0) -[OrcaDesktopWin32]::Limit = 2 -$secret = New-TestElement "Edit" 303 -$secret.live.Current.IsPassword = $true -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "abc"; element = $secret }) -if ($outcome.message -notlike "*past the field's 2-character limit") { throw "over-limit password insertion, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count) 0 "over-limit password insertion sends nothing" - -# Edit messages would bypass a disabled field's lock, so a disabled field is refused untouched. -[OrcaDesktopWin32]::Reset("", 0, 0) -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "x"; element = (New-TestElement "Edit" 303 $false) }) -if ($outcome.message -notlike "element 7 text is not settable: the field is disabled") { throw "disabled edit, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count) 0 "disabled edit sends nothing" - -# A recycled window handle owned by another process is never messaged. -[OrcaDesktopWin32]::Reset("", 0, 0) -[OrcaDesktopWin32]::EditOwner = 999 -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "x"; element = (New-TestElement "Edit" 303) }) -if ($outcome.message -notlike "stale element:*") { throw "recycled edit handle, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count) 0 "recycled edit handle sends nothing" - -# An element with no background text route refuses instead of typing at whatever has focus. -[OrcaDesktopWin32]::Reset("", 0, 0) -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "x"; element = (New-TestElement "Chrome_RenderWidgetHostHWND" 404) }) -if ($outcome.message -notlike "background_unavailable: element 7 accepts text only as keys*") { throw "no text route, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count) 0 "no text route sends nothing" - -# List and tree items take ValuePattern too, where a write would rename them, so they are refused untouched. -[OrcaDesktopWin32]::Reset("", 0, 0) -$script:valueWrites = 0 -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "x"; element = (New-TestElement "" 0 $true "ControlType.ListItem") }) -if ($outcome.message -notlike "element 7 text is not settable: it is not a text field") { throw "list item, received '$($outcome.message)'" } -Assert-TestEqual ([OrcaDesktopWin32]::Calls.Count + $script:valueWrites) 0 "list item sends nothing" - -# Foreground typing re-checks focus right before SendInput, so a user's switch never receives the text. -[OrcaDesktopWin32]::Reset("", 0, 0) -[OrcaDesktopWin32]::Foreground = [IntPtr]101 -$outcome = Invoke-TestOperation ([pscustomobject]@{ tool = "type_text"; app = "Fixture"; text = "caf$([char]0x00E9)"; restoreWindow = $true }) -if ($null -ne $outcome.message) { throw "foreground typing failed: $($outcome.message)" } -Assert-TestEqual (@([OrcaDesktopWin32]::Calls | Where-Object { $_ -like "keys:*" }) -join "|") "keys:caf$([char]0x00E9)" "foreground typing sends Unicode input" -Write-Output "windows-text-entry-tests-ok" diff --git a/src/main/ipc/agent-hooks.test.ts b/src/main/ipc/agent-hooks.test.ts deleted file mode 100644 index d0c28dd513f..00000000000 --- a/src/main/ipc/agent-hooks.test.ts +++ /dev/null @@ -1,155 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' - -import type * as AgentHookServerModule from '../agent-hooks/server/agent-hook-server' -import { makePaneKey } from '../../shared/workspace-layout/stable-pane-id' - -// Renderer dismissals must evict persisted status as well as the live row. - -const dropStatusEntry = vi.fn() -const dropPersistedStatusEntry = vi.fn() -const dropPersistedStatusEntries = vi.fn(() => [] as string[]) -const dropStatusEntriesByTabPrefix = vi.fn() -const retirePaneAuthority = vi.fn() -const transferPaneAuthority = vi.fn() -const canTransferPaneAuthority = vi.fn(() => true) -const getStatusSnapshot = vi.fn() -const inferInterrupt = vi.fn() -const clearMigrationUnsupportedPtysByTabPrefix = vi.fn() -const clearMigrationUnsupportedPtysForPaneKey = vi.fn() -const onHandlers = new Map void>() -const handleHandlers = new Map unknown>() -const removeHandler = vi.fn() -const removeAllListeners = vi.fn() -const PANE_KEY = makePaneKey('tab-1', '11111111-1111-4111-8111-111111111111') -const CHILD_PANE_KEY = makePaneKey('tab-2', '22222222-2222-4222-8222-222222222222') - -vi.mock('electron', () => ({ - ipcMain: { - handle: (channel: string, handler: (event: unknown, ...args: unknown[]) => unknown) => { - handleHandlers.set(channel, handler) - }, - on: (channel: string, handler: (event: unknown, ...args: unknown[]) => void) => { - onHandlers.set(channel, handler) - }, - removeHandler, - removeAllListeners - } -})) - -vi.mock('../agent-hooks/server/agent-hook-server', async () => { - // Use the real pane-key validator so invalid-input coverage tracks its constraints. - const actual = await vi.importActual( - '../agent-hooks/server/agent-hook-server' - ) - return { - ...actual, - agentHookServer: { - dropStatusEntry, - dropPersistedStatusEntry, - dropPersistedStatusEntries, - dropStatusEntriesByTabPrefix, - retirePaneAuthority, - transferPaneAuthority, - canTransferPaneAuthority, - getStatusSnapshot, - inferInterrupt - } - } -}) - -vi.mock('../agent-hooks/observations/migration-unsupported-pty-state', () => ({ - clearMigrationUnsupportedPtysByTabPrefix, - clearMigrationUnsupportedPtysForPaneKey, - getMigrationUnsupportedPtySnapshot: vi.fn(() => []) -})) - -vi.mock('../claude/hook-service', () => ({ - claudeHookService: { getStatus: vi.fn(() => ({ agent: 'claude', state: 'absent' })) } -})) -vi.mock('../openclaude/hook-service', () => ({ - openClaudeHookService: { getStatus: vi.fn(() => ({ agent: 'openclaude', state: 'absent' })) } -})) -vi.mock('../codex/hooks/installation/hook-service', () => ({ - codexHookService: { getStatus: vi.fn(() => ({ agent: 'codex', state: 'absent' })) } -})) -vi.mock('../gemini/hook-service', () => ({ - geminiHookService: { getStatus: vi.fn(() => ({ agent: 'gemini', state: 'absent' })) } -})) -vi.mock('../antigravity/hook-service', () => ({ - antigravityHookService: { getStatus: vi.fn(() => ({ agent: 'antigravity', state: 'absent' })) } -})) -vi.mock('../amp/hook-service', () => ({ - ampHookService: { getStatus: vi.fn(() => ({ agent: 'amp', state: 'absent' })) } -})) -vi.mock('../cursor/hook-service', () => ({ - cursorHookService: { getStatus: vi.fn(() => ({ agent: 'cursor', state: 'absent' })) } -})) -vi.mock('../droid/hook-service', () => ({ - droidHookService: { getStatus: vi.fn(() => ({ agent: 'droid', state: 'absent' })) } -})) -vi.mock('../command-code/hook-service', () => ({ - commandCodeHookService: { getStatus: vi.fn(() => ({ agent: 'command-code', state: 'absent' })) } -})) -vi.mock('../grok/hook-service', () => ({ - grokHookService: { getStatus: vi.fn(() => ({ agent: 'grok', state: 'absent' })) } -})) -vi.mock('../copilot/hook-service', () => ({ - copilotHookService: { getStatus: vi.fn(() => ({ agent: 'copilot', state: 'absent' })) } -})) -vi.mock('../hermes/hook-service', () => ({ - hermesHookService: { getStatus: vi.fn(() => ({ agent: 'hermes', state: 'absent' })) } -})) -vi.mock('../devin/hook-service', () => ({ - devinHookService: { getStatus: vi.fn(() => ({ agent: 'devin', state: 'absent' })) } -})) -vi.mock('../kimi/hook-service', () => ({ - kimiHookService: { getStatus: vi.fn(() => ({ agent: 'kimi', state: 'absent' })) } -})) - -beforeEach(() => { - dropStatusEntry.mockReset() - dropPersistedStatusEntry.mockReset() - dropPersistedStatusEntries.mockReset() - dropPersistedStatusEntries.mockReturnValue([]) - dropStatusEntriesByTabPrefix.mockReset() - retirePaneAuthority.mockReset() - transferPaneAuthority.mockReset() - canTransferPaneAuthority.mockReset() - canTransferPaneAuthority.mockReturnValue(true) - getStatusSnapshot.mockReset() - inferInterrupt.mockReset() - clearMigrationUnsupportedPtysByTabPrefix.mockReset() - clearMigrationUnsupportedPtysForPaneKey.mockReset() - onHandlers.clear() - handleHandlers.clear() - removeHandler.mockReset() - removeAllListeners.mockReset() -}) - -afterEach(() => { - vi.resetModules() -}) - -describe('agent pane authority IPC', () => { - it('rejects unowned and oversized pane authority transfers', async () => { - const { registerAgentHookHandlers } = await import('./agent-hooks') - registerAgentHookHandlers() - const transfer = onHandlers.get('agentStatus:transferPaneAuthority')! - - canTransferPaneAuthority.mockReturnValue(false) - transfer({}, { fromPaneKey: PANE_KEY, toPaneKey: CHILD_PANE_KEY, ptyId: 'forged-pty' }) - transfer({}, { fromPaneKey: PANE_KEY, toPaneKey: CHILD_PANE_KEY }) - canTransferPaneAuthority.mockReturnValue(true) - transfer({}, { fromPaneKey: PANE_KEY, toPaneKey: CHILD_PANE_KEY, ptyId: 'x'.repeat(513) }) - transfer( - {}, - { - fromPaneKey: `${'x'.repeat(180)}:11111111-1111-4111-8111-111111111111`, - toPaneKey: CHILD_PANE_KEY, - ptyId: 'pty-1' - } - ) - - expect(transferPaneAuthority).not.toHaveBeenCalled() - }) -}) diff --git a/src/main/ipc/notebook-project-link.test.ts b/src/main/ipc/notebook-project-link.test.ts deleted file mode 100644 index 7860f599293..00000000000 --- a/src/main/ipc/notebook-project-link.test.ts +++ /dev/null @@ -1,102 +0,0 @@ -import { EventEmitter } from 'node:events' -import { mkdir, mkdtemp, realpath, rm, symlink, writeFile } from 'node:fs/promises' -import { tmpdir } from 'node:os' -import { join } from 'node:path' -import { afterEach, beforeEach, expect, it, vi } from 'vitest' -import type { Store } from '../persistence/loading-store/store' -import type * as RepoWorktrees from '../workspaces/catalog/repo-worktrees' -import { invalidateAuthorizedRootsCache } from './worktrees/removal/registered-worktree-roots-cache' - -type Handler = (event: unknown, args: unknown) => unknown - -const { handlers, startNotebookKernelMock, userData } = vi.hoisted(() => ({ - handlers: new Map(), - startNotebookKernelMock: vi.fn(), - userData: { path: '' } -})) - -vi.mock('electron', () => ({ - app: { getPath: () => userData.path }, - ipcMain: { handle: (channel: string, handler: Handler) => handlers.set(channel, handler) } -})) -vi.mock('../workspaces/catalog/repo-worktrees', async () => { - const actual = await vi.importActual('../workspaces/catalog/repo-worktrees') - return { ...actual, listRepoWorktreeGraph: vi.fn(async () => []) } -}) -vi.mock('../notebook/notebook-kernel', () => ({ startNotebookKernel: startNotebookKernelMock })) - -import { registerNotebookHandlers } from './notebook' - -let base: string -let project: string - -function storeWithProject(projectPath: string): Store { - // oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: authorization reads only these Store members. - return { - getRepos: () => [ - { id: 'repo', path: projectPath, displayName: 'project', badgeColor: '#000', addedAt: 0 } - ], - getProjects: () => [], - getProjectGroups: () => [], - getFolderWorkspaces: () => [], - getSettings: () => ({ nestWorkspaces: false, workspaceDir: '' }) - } as unknown as Store -} - -beforeEach(async () => { - invalidateAuthorizedRootsCache() - handlers.clear() - startNotebookKernelMock.mockReset().mockReturnValue({ - kernel: { execute: vi.fn(), interrupt: vi.fn(), shutdown: vi.fn() }, - ready: Promise.resolve({ status: 'ready' }), - exited: new Promise(() => {}) - }) - base = await mkdtemp(join(await realpath(tmpdir()), 'orca-notebook-link-')) - project = join(base, 'project') - userData.path = join(base, 'user-data') - await mkdir(join(project, 'analysis'), { recursive: true }) - await mkdir(join(userData.path, 'floating-workspace'), { recursive: true }) - await writeFile(join(project, 'analysis', 'real.ipynb'), '{}') - registerNotebookHandlers(storeWithProject(project)) -}) - -afterEach(async () => { - await rm(base, { recursive: true, force: true }) -}) - -it.skipIf(process.platform === 'win32')( - 'runs a notebook opened through a project link in its real folder, as the project check resolves it', - async () => { - await symlink(join(project, 'analysis', 'real.ipynb'), join(project, 'nb.ipynb')) - const owner = Object.assign(new EventEmitter(), { send: vi.fn(), isDestroyed: () => false }) - - await handlers.get('notebook:startKernel')!( - { sender: owner }, - { filePath: join(project, 'nb.ipynb'), python: '/py' } - ) - - expect(startNotebookKernelMock).toHaveBeenCalledWith( - expect.objectContaining({ cwd: join(project, 'analysis') }) - ) - } -) - -it.skipIf(process.platform === 'win32')( - 'runs a linked notebook outside every project in its real folder, as before', - async () => { - const notes = join(base, 'notes') - await mkdir(join(notes, 'analysis'), { recursive: true }) - await writeFile(join(notes, 'analysis', 'real.ipynb'), '{}') - await symlink(join(notes, 'analysis', 'real.ipynb'), join(notes, 'nb.ipynb')) - const owner = Object.assign(new EventEmitter(), { send: vi.fn(), isDestroyed: () => false }) - - await handlers.get('notebook:startKernel')!( - { sender: owner }, - { filePath: join(notes, 'nb.ipynb'), python: '/py' } - ) - - expect(startNotebookKernelMock).toHaveBeenCalledWith( - expect.objectContaining({ cwd: join(notes, 'analysis') }) - ) - } -) diff --git a/src/main/runtime/browser/screencast/browser-screencasts.test.ts b/src/main/runtime/browser/screencast/browser-screencasts.test.ts deleted file mode 100644 index e39c3086635..00000000000 --- a/src/main/runtime/browser/screencast/browser-screencasts.test.ts +++ /dev/null @@ -1,136 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import type { WebContents } from 'electron' -import type { - BrowserScreencastOptions, - BrowserScreencastSession -} from '../../../browser/cdp/screencast/browser-screencast-stream-types' -import { - createSinglePageBrowserCommandsHost, - createStreamedGuest -} from '../client-pages/single-page-browser-commands-host-test-double' -import { RuntimeBrowserCommands } from '../commands/browser-commands' - -const { webContentsFromId, startBrowserScreencast } = vi.hoisted(() => ({ - webContentsFromId: vi.fn(), - startBrowserScreencast: - vi.fn< - (guest: WebContents, options: BrowserScreencastOptions) => Promise - >() -})) - -vi.mock('electron', () => ({ - ipcMain: { on: vi.fn(), removeListener: vi.fn() }, - webContents: { fromId: webContentsFromId } -})) -vi.mock('../../../browser/cdp/screencast/browser-screencast-stream', () => ({ - startBrowserScreencast -})) - -function createSession() { - let close!: () => void - const done = new Promise((resolve) => { - close = resolve - }) - return { - stop: vi.fn(() => close()), - done, - updateViewport: async () => {}, - updateFrameBudget: async () => {} - } -} - -const params = { page: 'page-1', format: 'jpeg' } as const - -describe('screencast ownership', () => { - beforeEach(() => { - webContentsFromId.mockReset() - webContentsFromId.mockReturnValue(createStreamedGuest()) - startBrowserScreencast.mockReset() - }) - - afterEach(() => { - vi.useRealTimers() - }) - - it.each(['older', 'newer'])( - 'keeps the newer viewer when the %s reconnect finishes first', - async (firstReady) => { - const session = createSession() - let finishUpdate = (): void => {} - let updateStarted = (): void => {} - const started = new Promise((resolve) => { - updateStarted = resolve - }) - vi.spyOn(session, 'updateFrameBudget').mockImplementationOnce( - () => - new Promise((resolve) => { - finishUpdate = resolve - updateStarted() - }) - ) - startBrowserScreencast.mockResolvedValue(session) - const commands = new RuntimeBrowserCommands(createSinglePageBrowserCommandsHost()) - const device = { pairedDeviceId: 'phone-1' } - const first = await commands.browserScreencast(params, { ...device, sendBinary: () => true }) - const olderSend = vi.fn(() => true) - const newerSend = vi.fn(() => true) - const reconnectParams = { ...params, maxWidth: 640 } - const olderJoin = commands.browserScreencast(reconnectParams, { - ...device, - sendBinary: olderSend - }) - let finishViewport = (): void => {} - let viewportStarted = (): void => {} - const viewportPending = new Promise((resolve) => { - viewportStarted = resolve - }) - if (firstReady === 'older') { - vi.spyOn(session, 'updateViewport').mockImplementationOnce( - () => - new Promise((resolve) => { - finishViewport = resolve - viewportStarted() - }) - ) - } - - try { - await started - const newerJoin = commands.browserScreencast( - { - ...reconnectParams, - ...(firstReady === 'older' ? { viewportWidth: 640, viewportHeight: 480 } : {}) - }, - { - ...device, - sendBinary: newerSend - } - ) - if (firstReady === 'older') { - await viewportPending - finishUpdate() - await olderJoin - finishViewport() - } - const newer = await newerJoin - await first.session.done - finishUpdate() - const older = await olderJoin - await older.session.done - const frame = new Uint8Array([1, 2, 3]) - startBrowserScreencast.mock.calls[0]?.[1].onFrame(frame) - expect(olderSend).not.toHaveBeenCalled() - expect(newerSend).toHaveBeenCalledWith(frame, { dropWhenBacklogged: true }) - expect(session.stop).not.toHaveBeenCalled() - newer.session.stop() - await newer.session.done - expect(session.stop).toHaveBeenCalledOnce() - } finally { - finishUpdate() - finishViewport() - session.stop() - await session.done - } - } - ) -}) diff --git a/src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts b/src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts deleted file mode 100644 index 0b8c2f9f184..00000000000 --- a/src/main/runtime/browser/screencast/orca-runtime-browser-screencast-fanout.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { - createSinglePageBrowserCommandsHost, - createStreamedGuest -} from '../client-pages/single-page-browser-commands-host-test-double' - -const { webContentsFromId, startBrowserScreencast } = vi.hoisted(() => ({ - webContentsFromId: vi.fn(), - startBrowserScreencast: vi.fn() -})) - -vi.mock('electron', () => ({ - ipcMain: { on: vi.fn(), removeListener: vi.fn() }, - webContents: { fromId: webContentsFromId } -})) -vi.mock('../../../browser/cdp/screencast/browser-screencast-stream', () => ({ - startBrowserScreencast -})) - -function deferred() { - let resolve!: () => void - const promise = new Promise((done) => { - resolve = done - }) - return { promise, resolve } -} - -describe('RuntimeBrowserCommands screencast fanout', () => { - beforeEach(() => { - webContentsFromId.mockReset() - webContentsFromId.mockReturnValue(createStreamedGuest()) - startBrowserScreencast.mockReset() - }) - - it('replays the joiner snapshot that its pre-ready gate refused', async () => { - const { RuntimeBrowserCommands } = await import('../commands/browser-commands') - const done = deferred() - const snapshot = new Uint8Array([9, 9, 9]) - let onFrame: (bytes: Uint8Array) => boolean | void = () => true - // updateViewport emits before the joining viewer's ready gate opens. - const updateViewport = vi.fn(async () => { - onFrame(snapshot) - }) - startBrowserScreencast.mockImplementation(async (_guest: unknown, options: never) => { - onFrame = (options as { onFrame: typeof onFrame }).onFrame - return { - stop: vi.fn(() => done.resolve()), - done: done.promise, - updateViewport, - updateFrameBudget: vi.fn(async () => {}) - } - }) - const commands = new RuntimeBrowserCommands(createSinglePageBrowserCommandsHost()) - const creatorSend = vi.fn(() => true) - await commands.browserScreencast( - { - worktree: 'id:wt-1', - page: 'page-1', - format: 'jpeg', - viewportWidth: 1200, - viewportHeight: 800 - }, - { sendBinary: creatorSend } - ) - let gateOpen = false - const joinerSend = vi.fn(() => gateOpen) - const joiner = await commands.browserScreencast( - { - worktree: 'id:wt-1', - page: 'page-1', - format: 'jpeg', - viewportWidth: 800, - viewportHeight: 600 - }, - { sendBinary: joinerSend } - ) - - expect(creatorSend).toHaveBeenCalledWith(snapshot, { dropWhenBacklogged: true }) - expect(joinerSend).toHaveBeenCalledWith(snapshot, { dropWhenBacklogged: true }) - joinerSend.mockClear() - gateOpen = true - joiner.flushPendingFrame() - expect(joinerSend).toHaveBeenCalledExactlyOnceWith(snapshot, { dropWhenBacklogged: true }) - - joinerSend.mockClear() - joiner.flushPendingFrame() - expect(joinerSend).not.toHaveBeenCalled() - joiner.session.stop() - await joiner.session.done - }) -}) diff --git a/src/renderer/src/components/tab-group/useTabGroupCloseScopeCommands.test.tsx b/src/renderer/src/components/tab-group/useTabGroupCloseScopeCommands.test.tsx index fbf53109dd7..6732db83c7d 100644 --- a/src/renderer/src/components/tab-group/useTabGroupCloseScopeCommands.test.tsx +++ b/src/renderer/src/components/tab-group/useTabGroupCloseScopeCommands.test.tsx @@ -64,26 +64,13 @@ function request(scope: BulkTabCloseScope) { act(actions[scope]) } -async function confirmRequest(confirmed = true) { +async function confirmRequest() { await act(async () => { - settle(confirmed) + settle(true) }) } describe('group bulk close confirmation', () => { - it.each(['editors', 'others', 'right', 'left'] as const)( - 'waits for confirmation and leaves tabs untouched on cancelling %s', - async (scope) => { - request(scope) - expect(confirm).toHaveBeenCalledOnce() - expect(closeItem).not.toHaveBeenCalled() - expect(closeMany).not.toHaveBeenCalled() - await confirmRequest(false) - expect(closeItem).not.toHaveBeenCalled() - expect(closeMany).not.toHaveBeenCalled() - } - ) - it.each(['others', 'right', 'left'] as const)( 'abandons %s when the anchor is removed while the dialog is open', async (scope) => { @@ -100,17 +87,6 @@ describe('group bulk close confirmation', () => { } ) - it.each(['editors', 'others', 'right', 'left'] as const)( - 'abandons %s when the original group disappears', - async (scope) => { - request(scope) - act(() => useAppStore.setState({ groupsByWorktree: {} })) - await confirmRequest() - expect(closeMany).not.toHaveBeenCalled() - expect(closeItem).not.toHaveBeenCalled() - } - ) - it('skips editors pinned while confirmation is pending', async () => { request('editors') act(() => diff --git a/src/renderer/src/web/web-file-mutation-methods.test.ts b/src/renderer/src/web/web-file-mutation-methods.test.ts deleted file mode 100644 index 205165340ea..00000000000 --- a/src/renderer/src/web/web-file-mutation-methods.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import type { SshConnectionState } from '../../../shared/ssh-types' -import type { Worktree } from '../../../shared/worktree/types' -import { createWebFileMutationMethods } from './web-file-mutation-methods' - -function resolvedFile( - id: string, - hostId: Worktree['hostId'], - relativePath: string -): { worktree: Pick; relativePath: string } { - return { worktree: { id, hostId }, relativePath } -} - -function connectedSshState(targetId: string, connectionGeneration: number): SshConnectionState { - return { - targetId, - status: 'connected', - error: null, - reconnectAttempt: 0, - connectionGeneration - } -} - -describe('paired web file mutation methods', () => { - const assertMutationSupported = vi.fn(async (): Promise => []) - const callRuntimeResult = vi.fn(async () => ({ ok: true })) - const getSshState = vi.fn(async () => connectedSshState('hub-private-target', 17)) - const filesByPath = new Map([ - ['/hub/repo/readme.md', resolvedFile('wt-local', 'local', 'readme.md')], - ['/hub/repo/new.md', resolvedFile('wt-local', 'local', 'new.md')], - ['/hub/repo/copy.md', resolvedFile('wt-local', 'local', 'copy.md')], - ['/hub/repo/new-dir', resolvedFile('wt-local', 'local', 'new-dir')], - ['/ssh/repo/source.md', resolvedFile('wt-ssh', 'ssh:hub-private-target', 'source.md')], - ['/ssh/repo/renamed.md', resolvedFile('wt-ssh', 'ssh:hub-private-target', 'renamed.md')], - ['/ssh/repo/copy.md', resolvedFile('wt-ssh', 'ssh:hub-private-target', 'copy.md')], - ['/ssh/repo/dir', resolvedFile('wt-ssh', 'ssh:hub-private-target', 'dir')] - ]) - const resolveFilePath = vi.fn(async (filePath: string) => { - const file = filesByPath.get(filePath) - if (!file) { - throw new Error(`Unknown test path: ${filePath}`) - } - return file - }) - const captureSession = vi.fn(() => ({ - assertMutationSupported, - callRuntimeResult, - getSshState, - resolveFilePath - })) - - beforeEach(() => { - assertMutationSupported.mockClear() - callRuntimeResult.mockClear() - getSshState.mockClear() - resolveFilePath.mockClear() - captureSession.mockClear() - }) - - it('keeps path resolution, capability, and mutation on one captured pairing session', async () => { - const replacementCall = vi.fn(async () => ({ ok: true })) - const replacementSession = { - assertMutationSupported: vi.fn(async (): Promise => []), - callRuntimeResult: replacementCall, - getSshState, - resolveFilePath - } - const capturedSession = { - assertMutationSupported: vi.fn(async (): Promise => { - captureSession.mockReturnValue(replacementSession) - return [] - }), - callRuntimeResult, - getSshState, - resolveFilePath - } - captureSession.mockReturnValueOnce(capturedSession) - const methods = createWebFileMutationMethods({ captureSession }) - - await methods.writeFile({ filePath: '/hub/repo/readme.md', content: 'bound' }) - - expect(captureSession).toHaveBeenCalledTimes(1) - expect(callRuntimeResult).toHaveBeenCalledWith('files.write', { - worktree: 'id:wt-local', - relativePath: 'readme.md', - content: 'bound', - expectedExecutionHostId: 'local' - }) - expect(replacementCall).not.toHaveBeenCalled() - }) -})