From de93f326eaff6157bc5be4cceafb0bec19810d65 Mon Sep 17 00:00:00 2001 From: OrcaWin Date: Sun, 25 Oct 2026 23:41:49 -0700 Subject: [PATCH] test: remove low-value inventories, passthroughs and redundant cases (#33796) * test: remove low-value inventories, passthroughs and redundant cases * style: format test suites after pruning redundant cases * test: remove obsolete workflow and flaky-test references * test: prune deleted builder test from Windows shim allowlist --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com> --- .github/workflows/computer-e2e.yml | 1 - config/flaky-test-pattern-baseline.txt | 1 - config/scripts/ci-background-steps.test.mjs | 92 -------- config/scripts/ci-e2e-job-selection.test.mjs | 210 ------------------ .../scripts/electron-builder-config.test.mjs | 178 --------------- ...lectron-builder-runtime-resources.test.mjs | 121 +--------- ...web-app-session-dictation-capture.test.mjs | 52 +---- ...-web-app-session-terminal-closure.test.mjs | 36 --- config/scripts/orcad-entry-build.test.mjs | 12 - ...package-electron-runtime-contract.test.mjs | 144 +----------- .../replace-cached-nsis-elevate.test.mjs | 48 +--- config/scripts/resolve-7za-path.test.mjs | 13 -- config/scripts/run-audit-tool.test.mjs | 34 +-- .../vitest-sqlite-runtime-boundary.test.ts | 9 +- .../windows-cmd-shim-spawn-boundary.test.mjs | 1 - .../bridge/bridge-audio-verbs.test.ts | 22 +- ...bileNativeChatSessionOptionPickers.test.ts | 7 - .../session/MobileNativeChatToolRun.test.tsx | 23 -- ...obile-native-chat-pending-baseline.test.ts | 13 -- .../mobile-native-chat-tool-summary.test.ts | 43 +--- .../mobile-native-chat-unsent-notices.test.ts | 16 -- ...uctured-agent-session-host-support.test.ts | 90 -------- ...bile-native-chat-image-attachments.test.ts | 12 - .../use-mobile-native-chat-controller.test.ts | 113 +--------- ...se-mobile-native-chat-message-send.test.ts | 17 -- ...mobile-native-chat-session-options.test.ts | 16 -- .../use-mobile-native-chat-stop.test.ts | 17 +- ...ile-structured-agent-session-send.test.tsx | 15 -- .../bridged-parity/c5-page-closure.test.ts | 96 +------- .../bridged-parity/divergence-classes.test.ts | 42 ---- .../divergence-evidence.test.ts | 4 - ...transcript-record-parser-prefilter.test.ts | 25 --- ...puter-provider-unavailable-message.test.ts | 26 --- src/main/daemon/daemon-restart-state.test.ts | 4 - src/main/dock/unread-badge.test.ts | 44 ---- .../git-command-timeout.test.ts | 4 - .../hang-watchdog-worker-path.test.ts | 26 --- .../main-thread-hang-telemetry.test.ts | 18 -- .../host/safe-storage-import-ratchet.test.ts | 30 --- .../deferred-emoji-shortcode-dataset.test.ts | 24 -- src/main/ipc/freebuff-detection.test.ts | 38 ---- ...ronment-control-socket-close-trace.test.ts | 36 --- ...ntime-environment-recovery-handler.test.ts | 29 --- .../ipc/skill-install-progress-ipc.test.ts | 19 +- .../worktree-watcher-removal-binding.test.ts | 31 --- .../json-string-shortening.test.ts | 5 - ...code-status-plugin-startup-refresh.test.ts | 37 --- .../provider-process-launch.test.ts | 9 - .../pty/windows-path-registry-change.test.ts | 22 +- src/main/ripgrep/bundled-ripgrep-stop.test.ts | 36 --- .../relayed-stream-carriers.test.ts | 24 -- .../relayed-stream-carriers.ts | 2 +- .../orca-runtime-tail-wait-memo.test.ts | 17 +- .../rpc/methods/repo-badge-color.test.ts | 39 ---- .../runtime-rpc-mobile-method-routing.test.ts | 12 +- ...gent-runtime-registration-identity.test.ts | 32 --- .../speech-model-download-response.test.ts | 9 - .../sqlite/node-sqlite-reader-api.test.ts | 6 - src/main/ssh/relay-install-artifacts.test.ts | 25 --- src/main/worker-thread-entry-path.test.ts | 28 --- src/main/workspace-space-repo-scan.test.ts | 31 --- .../zcode/interactive-capability.live.test.ts | 30 --- .../browser-download-progress.test.ts | 37 --- .../remote-browser-keyboard.test.ts | 4 - .../comment-reply-target-state.test.ts | 32 --- .../diff-section-comment-submit.test.ts | 40 ---- .../components/editor/editor-labels.test.ts | 41 ---- .../components/github-link-copy-state.test.ts | 16 +- .../github-project/ProjectViewStates.test.tsx | 26 --- .../linear-api-key-dialog-state.test.ts | 34 --- .../native-chat-split-shortcut.test.ts | 38 ---- ...ourceControl.push-failure-recovery.test.ts | 27 --- .../ai-vault-search-hit-hosts.test.ts | 33 --- .../file-explorer-refresh-concurrency.test.ts | 36 --- .../right-sidebar/right-sidebar-width.test.ts | 28 --- ...source-control-created-review-link.test.ts | 25 --- .../settings/FloatingWorkspacePane.test.tsx | 31 --- .../PluginKeybindingConsentPreview.test.ts | 30 --- .../sidebar/project-filter-reveal.test.ts | 32 --- .../sidebar/worktree-card-dom-events.test.ts | 29 --- .../terminal-http-link-activation.test.ts | 30 --- .../terminal-process-exit-restart.test.ts | 11 - ...e-manual-terminal-worktree-parking.test.ts | 35 --- .../components/ui/repo-multi-combobox.test.ts | 28 --- .../src/components/ui/scroll-area.test.tsx | 39 ---- .../src/components/ui/switch.test.tsx | 19 +- .../src/hooks/useResetCountdownClock.test.ts | 10 - .../hooks/useVirtualizedScrollAnchor.test.ts | 39 ---- src/renderer/src/lib/agent-type-icon.test.tsx | 29 --- .../option-key-location-state.test.ts | 6 - .../src/lib/linked-work-item-provider.test.ts | 42 ---- src/renderer/src/lib/orca-hook-trust.test.ts | 29 --- .../pane-manager/pane-pointer-focus.test.ts | 37 --- src/shared/session-tab-placement.test.ts | 27 --- .../workspace-review-facts.test.ts | 15 +- src/shared/skill-delete-contract.test.ts | 66 +----- src/shared/skill-path-containment.test.ts | 16 -- ...source-control-ai-action-variables.spec.ts | 40 +--- src/shared/synthetic-agent-title.test.ts | 24 -- src/shared/task-providers.test.ts | 19 +- .../terminal-agent-status-processor.test.ts | 7 - ...al-partial-escape-tail-ground-scan.test.ts | 20 -- ...terminal-title-classification-memo.test.ts | 12 - .../windows-command-line-budget.test.ts | 21 +- ...e-cleanup-browse-state-persistence.test.ts | 5 - src/shared/workspace-doc-history.test.ts | 5 - .../workspace-layout-simulator-tab.test.ts | 7 +- ...rkspace-linked-item-source-context.test.ts | 20 -- .../workspace-view-options.test.ts | 81 ------- src/shared/worktree-name-suggestion.test.ts | 30 +-- src/shared/worktree/base-ref.test.ts | 19 -- 111 files changed, 26 insertions(+), 3517 deletions(-) delete mode 100644 config/scripts/ci-background-steps.test.mjs delete mode 100644 mobile/src/session/mobile-structured-agent-session-host-support.test.ts delete mode 100644 src/main/computer/computer-provider-unavailable-message.test.ts delete mode 100644 src/main/dock/unread-badge.test.ts delete mode 100644 src/main/hang-watchdog/hang-watchdog-worker-path.test.ts delete mode 100644 src/main/host/safe-storage-import-ratchet.test.ts delete mode 100644 src/main/ipc/deferred-emoji-shortcode-dataset.test.ts delete mode 100644 src/main/ipc/freebuff-detection.test.ts delete mode 100644 src/main/ipc/runtime-environments/runtime-environment-control-socket-close-trace.test.ts delete mode 100644 src/main/ipc/runtime-environments/runtime-environment-recovery-handler.test.ts delete mode 100644 src/main/ipc/worktree-watcher-removal-binding.test.ts delete mode 100644 src/main/opencode/opencode-status-plugin-startup-refresh.test.ts delete mode 100644 src/main/ripgrep/bundled-ripgrep-stop.test.ts delete mode 100644 src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.test.ts delete mode 100644 src/main/runtime/rpc/methods/repo-badge-color.test.ts delete mode 100644 src/main/runtime/structured-agent-runtime-registration-identity.test.ts delete mode 100644 src/main/ssh/relay-install-artifacts.test.ts delete mode 100644 src/main/worker-thread-entry-path.test.ts delete mode 100644 src/main/workspace-space-repo-scan.test.ts delete mode 100644 src/main/zcode/interactive-capability.live.test.ts delete mode 100644 src/renderer/src/components/browser-pane/navigate/browser-download-progress.test.ts delete mode 100644 src/renderer/src/components/comment-reply-target-state.test.ts delete mode 100644 src/renderer/src/components/editor/diff-section-comment-submit.test.ts delete mode 100644 src/renderer/src/components/editor/editor-labels.test.ts delete mode 100644 src/renderer/src/components/github-project/ProjectViewStates.test.tsx delete mode 100644 src/renderer/src/components/linear-api-key-dialog-state.test.ts delete mode 100644 src/renderer/src/components/native-chat/native-chat-split-shortcut.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/SourceControl.push-failure-recovery.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/ai-vault-search-hit-hosts.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/file-explorer-refresh-concurrency.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts delete mode 100644 src/renderer/src/components/right-sidebar/source-control-created-review-link.test.ts delete mode 100644 src/renderer/src/components/settings/FloatingWorkspacePane.test.tsx delete mode 100644 src/renderer/src/components/settings/PluginKeybindingConsentPreview.test.ts delete mode 100644 src/renderer/src/components/sidebar/project-filter-reveal.test.ts delete mode 100644 src/renderer/src/components/sidebar/worktree-card-dom-events.test.ts delete mode 100644 src/renderer/src/components/terminal-pane/terminal-http-link-activation.test.ts delete mode 100644 src/renderer/src/components/terminal-pane/use-manual-terminal-worktree-parking.test.ts delete mode 100644 src/renderer/src/components/ui/repo-multi-combobox.test.ts delete mode 100644 src/renderer/src/components/ui/scroll-area.test.tsx delete mode 100644 src/renderer/src/hooks/useVirtualizedScrollAnchor.test.ts delete mode 100644 src/renderer/src/lib/agent-type-icon.test.tsx delete mode 100644 src/renderer/src/lib/linked-work-item-provider.test.ts delete mode 100644 src/renderer/src/lib/orca-hook-trust.test.ts delete mode 100644 src/renderer/src/lib/pane-manager/pane-pointer-focus.test.ts delete mode 100644 src/shared/workspace-view/workspace-view-options.test.ts diff --git a/.github/workflows/computer-e2e.yml b/.github/workflows/computer-e2e.yml index 11c877c9952..46ca14284bb 100644 --- a/.github/workflows/computer-e2e.yml +++ b/.github/workflows/computer-e2e.yml @@ -95,7 +95,6 @@ jobs: config/scripts/macos-computer-helper-owner-loss-processes.test.mjs config/scripts/computer-use-smoke.test.mjs src/main/computer/computer-provider-lifecycle.test.ts - src/main/computer/computer-provider-unavailable-message.test.ts src/main/computer/sidecar-client.test.ts src/main/computer/macos-native-provider-client.test.ts src/main/computer/macos-native-provider-socket.test.ts diff --git a/config/flaky-test-pattern-baseline.txt b/config/flaky-test-pattern-baseline.txt index 7e82d9e469b..eada623d9b7 100644 --- a/config/flaky-test-pattern-baseline.txt +++ b/config/flaky-test-pattern-baseline.txt @@ -1333,7 +1333,6 @@ 6 test-timeout-needs-reason:src/main/windows/windows-pty-job.win32.test.ts 8 test-timeout-needs-reason:src/main/worker-thread-child-process/worker-thread-child-process.test.ts 6 test-timeout-needs-reason:src/main/wsl/wsl-runner.wsl.test.ts -3 test-timeout-needs-reason:src/main/zcode/interactive-capability.live.test.ts 4 test-timeout-needs-reason:src/packages/process-host/src/run-process.test.ts 5 test-timeout-needs-reason:src/renderer/src/components/sidebar/WorktreeCard.compact-hover.test.tsx 2 test-timeout-needs-reason:src/renderer/src/components/sidebar/WorktreeCard.host-badge-toggle.test.tsx diff --git a/config/scripts/ci-background-steps.test.mjs b/config/scripts/ci-background-steps.test.mjs deleted file mode 100644 index d3a639acefd..00000000000 --- a/config/scripts/ci-background-steps.test.mjs +++ /dev/null @@ -1,92 +0,0 @@ -import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs' -import { join } from 'node:path' -import { parse } from 'yaml' -import { expect, it } from 'vitest' - -// Runner truncates/rewrites GITHUB_EVENT_PATH at each step start; background JS payload imports/composite inner steps race foreground starts and parse empty JSON. -const workflowFiles = readdirSync('.github/workflows') - .filter((name) => /\.ya?ml$/.test(name)) - .map((name) => join('.github/workflows', name)) -const actionFiles = readdirSync('.github/actions') - .map((name) => join('.github/actions', name, 'action.yml')) - .filter((file) => existsSync(file)) - -// Single-step JavaScript actions whose bundle never reads the payload (checked by searching dist/index.js). -const payloadFreeActions = ['ruby/setup-ruby@v1'] -// The runner runs 10 at once; a queued step starts (and rewrites the payload) mid-foreground-step. -const backgroundSlots = 10 - -function stepLists(file) { - const document = parse(readFileSync(file, 'utf8')) - return document.jobs - ? Object.entries(document.jobs).map(([job, value]) => [job, value.steps ?? []]) - : [['composite', document.runs?.steps ?? []]] -} - -function backgroundSteps() { - const found = [] - for (const file of [...workflowFiles, ...actionFiles]) { - for (const [job, steps] of stepLists(file)) { - for (const step of steps) { - if (step.background) { - found.push({ where: `${file} ${job} ${step.id ?? step.name}`, step }) - } - } - } - } - return found -} - -function readsEventPayload(run) { - const scripts = [...run.matchAll(/(?:config\/scripts|\.github\/actions)\/[\w./-]+/g)].map( - (match) => match[0] - ) - return ( - run.includes('GITHUB_EVENT_PATH') || - scripts.some( - (file) => - existsSync(file) && - statSync(file).isFile() && - readFileSync(file, 'utf8').includes('GITHUB_EVENT_PATH') - ) - ) -} - -it('finds the background steps it guards', () => { - expect(backgroundSteps().length).toBeGreaterThan(0) -}) - -it('backgrounds only single run steps, never actions that start later steps or parse the payload', () => { - const actions = backgroundSteps() - .filter(({ step }) => typeof step.run !== 'string' && !payloadFreeActions.includes(step.uses)) - .map(({ where }) => where) - expect(actions).toEqual([]) -}) - -it('keeps the event payload out of background run steps', () => { - const readers = backgroundSteps() - .filter(({ step }) => typeof step.run === 'string' && readsEventPayload(step.run)) - .map(({ where }) => where) - expect(readers).toEqual([]) -}) - -it('never queues a background step behind a full slot pool', () => { - const crowded = [] - for (const file of workflowFiles) { - for (const [job, steps] of stepLists(file)) { - const open = new Set() - for (const [index, step] of steps.entries()) { - if (step.background) { - open.add(step.id ?? index) - } - for (const id of [step.wait ?? []].flat()) { - open.delete(id) - } - if (open.size > backgroundSlots) { - crowded.push(`${file} ${job}`) - } - } - } - } - expect(crowded).toEqual([]) -}) diff --git a/config/scripts/ci-e2e-job-selection.test.mjs b/config/scripts/ci-e2e-job-selection.test.mjs index 5f1f1796703..3e83fb7243a 100644 --- a/config/scripts/ci-e2e-job-selection.test.mjs +++ b/config/scripts/ci-e2e-job-selection.test.mjs @@ -6,64 +6,13 @@ import { classifyE2eJobs, DEDICATED_E2E_SPECS, generalE2eShards, - MANAGED_SSH_E2E_SPEC_PREFIX, NATIVE_IME_E2E_SPEC, NODE_NETWORK_E2E_SPEC, selectGeneralE2eSpecs } from './ci-e2e-job-selection.mjs' import { selectPrE2eSpecs } from './pr-e2e-source-routing.mjs' -it.each([ - 'src/main/runtime/runtime-browser-commands-factory.ts', - 'src/main/runtime/orca-runtime-get-status.ts', - 'src/main/orcad/orcad-browser-startup.ts', - 'src/main/runtime/browser/browser-client-page-opening.ts' -])('routes the managed browser capability oracle from %s', (path) => { - expect(selectPrE2eSpecs([path])).toContain('tests/e2e/ssh-orcad-browser-capabilities.spec.ts') -}) - -it.each(['errors', 'status', 'lifecycle', 'restart-attempt'])( - 'routes the real browser service status check from %s changes', - (name) => { - expect( - selectPrE2eSpecs([ - `src/renderer/src/components/browser-pane/stream-remote/remote-browser-stream-${name}.ts` - ]) - ).toContain('tests/e2e/ssh-orcad-browser-service-status.spec.ts') - } -) - -it.each([ - 'src/renderer/src/lib/ssh-workspace-browser-route-eligibility.ts', - 'src/renderer/src/components/browser-pane/use-ssh-workspace-browser-route.ts', - 'src/main/browser/local-ssh-browser-route.ts', - 'src/renderer/src/store/repos/converted-ssh-browser-pages.ts', - 'src/renderer/src/store/slices/browser/browser-tab-actions.ts', - 'src/renderer/src/hooks/ipc-events/ssh-managed-server-state-effects.ts' -])('routes the managed browser routing oracle from %s', (path) => { - expect(selectPrE2eSpecs([path])).toContain('tests/e2e/ssh-orcad-browser-routing.spec.ts') -}) - -it.each([ - 'src/renderer/src/lib/workspace-browser-tab-open.ts', - 'src/renderer/src/lib/http-link-destinations.ts', - 'src/renderer/src/components/terminal-pane/terminal-http-link-source-owner.ts' -])('routes the managed terminal link oracle from %s', (path) => { - expect(selectPrE2eSpecs([path])).toContain('tests/e2e/ssh-orcad-terminal-browser-link.spec.ts') -}) - -it.each([ - 'src/shared/desktop-browser-bridge-protocol.ts', - 'src/main/runtime/desktop-browser-bridge/desktop-browser-bridge-route.ts', - 'src/main/browser/desktop-browser-bridge/desktop-browser-bridge-executor.ts', - 'src/main/ipc/desktop-browser-bridge-wiring.ts', - 'src/main/runtime/rpc/methods/desktop-browser-bridge.ts' -])('routes the managed desktop browser bridge oracle from %s', (path) => { - expect(selectPrE2eSpecs([path])).toContain('tests/e2e/ssh-orcad-desktop-browser-bridge.spec.ts') -}) - const workflow = parse(readFileSync('.github/workflows/e2e.yml', 'utf8')) -const prWorkflow = parse(readFileSync('.github/workflows/pr.yml', 'utf8')) const classify = (specs) => classifyE2eJobs(JSON.stringify(specs)) it('scales broad general selections without charging extra VMs for duplicate or dedicated specs', () => { @@ -85,34 +34,6 @@ it('scales broad general selections without charging extra VMs for duplicate or } }) -function expectManagedSshLane(spec) { - expect(classify([spec])).toEqual({ e2e_run_changed: false, e2e_needs_build: true }) - expect(spec.startsWith(MANAGED_SSH_E2E_SPEC_PREFIX)).toBe(true) - const lane = workflow.jobs['orcad-ssh-docker'] - expect(lane.if).toContain(`contains(inputs.test_files, '${MANAGED_SSH_E2E_SPEC_PREFIX}')`) - expect( - lane.steps.some( - (step) => - step.run?.includes('selection.selectManagedSshE2eSpecs') && - step.env?.ORCA_E2E_SSH_DOCKER === '1' - ) - ).toBe(true) -} - -it('runs real browser file-drop ownership in the template-building Docker job', () => { - const spec = 'tests/e2e/ssh-orcad-browser-drop-owner.spec.ts' - expectManagedSshLane(spec) - for (const source of [ - 'src/renderer/src/lib/file-preview.ts', - 'src/renderer/src/lib/workspace-file-drag.ts', - 'src/renderer/src/components/browser-pane/navigate/use-browser-page-navigation-downloads.ts', - 'src/renderer/src/components/right-sidebar/FileExplorerRow.tsx', - 'tests/e2e/helpers/browser-split-guest-probes.ts' - ]) { - expect(selectPrE2eSpecs([source]), source).toContain(spec) - } -}) - it('skips the general consumer only when every requested spec has a dedicated owner', () => { for (const spec of DEDICATED_E2E_SPECS) { expect(classify([spec]).e2e_run_changed, spec).toBe(false) @@ -164,28 +85,6 @@ it('preserves the requested specs across source-routed and mixed selections', () } }) -it('applies allocation hints only to PRs and retains other callers and full references', () => { - for (const name of ['run_changed_e2e', 'needs_build']) { - expect(workflow.on.workflow_call.inputs[name]).toMatchObject({ - type: 'boolean', - required: false, - default: true - }) - } - expect(workflow.jobs.build.if).toBe( - "inputs.test_files == '' || github.event_name != 'pull_request' || inputs.needs_build" - ) - expect(workflow.jobs.e2e.if).toBe("inputs.test_files == ''") - const changed = workflow.jobs['changed-e2e'] - expect(changed.if).toContain("github.event_name != 'pull_request' || inputs.run_changed_e2e") - const command = changed.steps.find((step) => step.name === 'Run changed E2E specs').run - expect(command).toContain('node config/scripts/ci-e2e-job-selection.mjs >') - expect(command).not.toContain('mapfile -t TEST_FILES < <(') - const fallback = [...command.matchAll(/\. != "([^"]+)"/g)].map((match) => match[1]) - expect(fallback).toEqual(DEDICATED_E2E_SPECS) - expect(command).toContain(`(startswith("${MANAGED_SSH_E2E_SPEC_PREFIX}") | not)`) -}) - it('publishes conservative hints for malformed evidence and refuses a malformed consumer list', async () => { const program = 'config/scripts/ci-e2e-job-selection.mjs' const consumer = await runProcess({ @@ -206,112 +105,3 @@ it('publishes conservative hints for malformed evidence and refuses a malformed 'e2e_run_changed=true\ne2e_needs_build=true\ne2e_ssh_shards=["1/2","2/2"]\n' ) }) - -it('classifies PR consumers in the existing detector and passes conservative allocation hints', () => { - const detector = prWorkflow.jobs.code_paths - expect(detector.steps[0].with['sparse-checkout']).toContain( - '/config/scripts/ci-e2e-job-selection.mjs' - ) - for (const name of ['e2e_run_changed', 'e2e_needs_build']) { - expect(detector.outputs[name]).toBe(`\${{ steps.e2e_filter.outputs.${name} }}`) - } - const command = detector.steps.find((step) => step.id === 'e2e_filter').run - expect(command).toContain('ci-e2e-job-selection.mjs --job-outputs >> "$GITHUB_OUTPUT"') - expect(prWorkflow.jobs.e2e.with.run_changed_e2e).toBe( - "${{ needs.code_paths.outputs.e2e_run_changed != 'false' }}" - ) - expect(prWorkflow.jobs.e2e.with.needs_build).toBe( - "${{ needs.code_paths.outputs.e2e_needs_build != 'false' }}" - ) -}) - -it.each([ - 'src/renderer/src/runtime/web-session-tabs-sync/mirrored-editor-file-identity.ts', - 'src/renderer/src/runtime/web-session-tabs-sync/tab-builders.ts', - 'src/renderer/src/runtime/web-session-tabs-sync/apply-preparation-browser.ts', - 'src/renderer/src/runtime/web-session-existing-tab-index.ts' -])('routes %s to the template-building editor ownership lane', (file) => { - const spec = 'tests/e2e/ssh-orcad-editor-ownership.spec.ts' - expect(selectPrE2eSpecs([file])).toContain(spec) - expectManagedSshLane(spec) -}) - -const MARKDOWN_CONVERSION_SPEC = 'tests/e2e/ssh-orcad-markdown-conversion.spec.ts' -const MARKDOWN_LINK_REFRESH_SPEC = 'tests/e2e/ssh-orcad-markdown-link-refresh.spec.ts' -const MARKDOWN_LIVE_DOCUMENTS_SPEC = 'tests/e2e/ssh-orcad-markdown-live-documents.spec.ts' - -it.each([ - ['src/renderer/src/components/editor/useMarkdownDocuments.ts', MARKDOWN_CONVERSION_SPEC], - [ - 'src/renderer/src/components/editor/restored-editor-workspace-runtime-owner.ts', - MARKDOWN_CONVERSION_SPEC - ], - [ - 'src/renderer/src/components/editor/migrate-restored-editor-file-owner.ts', - MARKDOWN_CONVERSION_SPEC - ], - ['src/renderer/src/components/editor/rich-markdown-doc-link.ts', MARKDOWN_LINK_REFRESH_SPEC], - [ - 'src/renderer/src/components/editor/useRichMarkdownProgrammaticSync.ts', - MARKDOWN_LINK_REFRESH_SPEC - ], - ['src/renderer/src/components/editor/useMarkdownDocuments.ts', MARKDOWN_LIVE_DOCUMENTS_SPEC], - [ - 'src/renderer/src/components/editor/use-markdown-document-watch-refresh.ts', - MARKDOWN_LIVE_DOCUMENTS_SPEC - ], - [ - 'src/renderer/src/components/editor/markdown-document-list-request.ts', - MARKDOWN_LIVE_DOCUMENTS_SPEC - ] -])('routes %s to the template-building Markdown lane %s', (file, spec) => { - expect(selectPrE2eSpecs([file])).toContain(spec) - expectManagedSshLane(spec) -}) - -it.each([ - 'src/renderer/src/hooks/useEditorExternalWatch.ts', - 'src/renderer/src/hooks/editor-runtime-file-watch.ts' -])('routes %s to the template-building editor watch recovery lane', (file) => { - const spec = 'tests/e2e/ssh-orcad-editor-watch-recovery.spec.ts' - expect(selectPrE2eSpecs([file])).toContain(spec) - expectManagedSshLane(spec) -}) - -it.each([ - 'src/renderer/src/components/right-sidebar/useFileExplorerWatch.ts', - 'src/renderer/src/hooks/worktree-file-change-event.ts' -])('routes %s to the template-building explorer watch recovery lane', (file) => { - const spec = 'tests/e2e/ssh-orcad-explorer-watch-recovery.spec.ts' - expect(selectPrE2eSpecs([file])).toContain(spec) - expectManagedSshLane(spec) -}) - -it.each([ - 'src/renderer/src/components/right-sidebar/useFileExplorerWatch.ts', - 'src/renderer/src/components/right-sidebar/file-explorer-operation-owner.ts', - 'src/renderer/src/components/right-sidebar/FileExplorer.tsx', - 'src/renderer/src/hooks/editor-external-watch-targets.ts', - 'src/renderer/src/components/right-sidebar/useFileExplorerTree.ts', - 'src/renderer/src/components/right-sidebar/use-file-explorer-tree-load-effects.ts' -])('routes %s to the template-building selected-host explorer lane', (file) => { - const spec = 'tests/e2e/ssh-orcad-explorer-selected-host.spec.ts' - expect(selectPrE2eSpecs([file])).toContain(spec) - expectManagedSshLane(spec) -}) - -it('runs managed terminal root ownership in the Docker conversion lane', () => { - const spec = 'tests/e2e/ssh-orcad-terminal-root-owner.spec.ts' - expectManagedSshLane(spec) - for (const source of [ - 'src/renderer/src/components/terminal-pane/terminal-worktree-path-link.ts', - 'src/renderer/src/components/terminal-pane/terminal-file-open-routing.ts', - 'src/renderer/src/components/terminal-pane/terminal-file-link-actions.ts', - 'src/renderer/src/components/terminal-pane/terminal-file-link-hit-testing.ts', - 'src/renderer/src/components/terminal-pane/terminal-link-handlers.ts', - 'src/renderer/src/lib/worktree-owner-route.ts', - 'tests/e2e/helpers/terminal-workspace-root-link.ts' - ]) { - expect(selectPrE2eSpecs([source]), source).toContain(spec) - } -}) diff --git a/config/scripts/electron-builder-config.test.mjs b/config/scripts/electron-builder-config.test.mjs index f3ee220137a..98c4397cbfa 100644 --- a/config/scripts/electron-builder-config.test.mjs +++ b/config/scripts/electron-builder-config.test.mjs @@ -11,16 +11,8 @@ const REPO_ROOT = join(import.meta.dirname, '..', '..') const require = createRequire(import.meta.url) const electronBuilderConfig = require('../electron-builder.config.cjs') const { copyFiles, FileMatcher } = require('app-builder-lib/out/fileMatcher') -const FpmTarget = require('app-builder-lib/out/targets/FpmTarget').default -const electronBuilderNativeRebuild = require('./electron-builder-native-rebuild.cjs') describe('electron-builder config', () => { - it('keeps the packaged app identity aligned with local-build validation', () => { - expect(electronBuilderConfig.appId).toBe( - require('../../src/shared/local-build-compatibility-contract.json').appId - ) - }) - it('excludes repo-only source trees from app.asar', () => { const matcher = new FileMatcher('/app', '/dest', (value) => value, electronBuilderConfig.files) matcher.prependPattern('**/*') @@ -215,64 +207,6 @@ describe('electron-builder config', () => { } }) - it('keeps runtime resources available through extraResources', () => { - const bundledPluginResources = expect.objectContaining({ - from: 'resources/plugins/launch', - to: 'plugins/launch' - }) - for (const platform of ['mac', 'linux', 'win']) { - expect(electronBuilderConfig[platform].extraResources).toContainEqual({ - from: 'resources/skills', - to: 'skills' - }) - expect(electronBuilderConfig[platform].extraResources).toEqual( - expect.arrayContaining([bundledPluginResources]) - ) - } - expect(electronBuilderConfig.mac.extraResources).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'native/computer-use-macos/.build/release/Orca Computer Use.app', - to: 'Orca Computer Use.app' - }) - ]) - ) - expect(electronBuilderConfig.linux.extraResources).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'native/computer-use-linux/runtime.py', - to: 'computer-use-linux/runtime.py' - }) - ]) - ) - expect(electronBuilderConfig.win.extraResources).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'native/computer-use-windows/runtime.ps1', - to: 'computer-use-windows/runtime.ps1' - }), - expect.objectContaining({ - from: 'native/windows-cli-launcher/.build/orca.exe', - to: 'bin/orca.exe' - }), - expect.objectContaining({ - from: 'native/windows-cli-launcher/.build/orca-administrator-restart.exe', - to: 'bin/orca-administrator-restart.exe' - }) - ]) - ) - }) - - it('ships one macOS serve-sim package through the runtime closure', () => { - const serveSimResources = electronBuilderConfig.mac.extraResources.filter((resource) => - [join('node_modules', 'serve-sim'), 'serve-sim'].includes(resource.to) - ) - - expect(serveSimResources).toEqual([ - expect.objectContaining({ to: join('node_modules', 'serve-sim') }) - ]) - }) - it.each(['mac', 'linux'])( 'loads Codex TOML parsing after %s runtime pruning', async (platform) => { @@ -305,84 +239,12 @@ describe('electron-builder config', () => { ) // Why: serve-sim's addon is a Mach-O, and Windows signing rejects every *.node that is not PE. - it('keeps serve-sim out of the Windows and Linux runtime closures', () => { - const { - PACKAGED_RUNTIME_PACKAGE_ROOTS, - createPackagedRuntimeNodeModuleResources - } = require('../packaged-runtime-node-modules.cjs') - expect(PACKAGED_RUNTIME_PACKAGE_ROOTS).not.toContain('serve-sim') - const serveSimTarget = join('node_modules', 'serve-sim') - expect(createPackagedRuntimeNodeModuleResources('linux').map((r) => r.to)).not.toContain( - serveSimTarget - ) - expect(electronBuilderConfig.linux.extraResources.map((r) => r.to)).not.toContain( - serveSimTarget - ) - expect(electronBuilderConfig.win.extraResources.map((r) => r.to)).not.toContain(serveSimTarget) - }) // Source shim unpacked under resources/win32/bin lacks adjacent orca.exe (#7351); only extraResources/bin copy works. - it('keeps the Windows CLI shim source tree out of app.asar', () => { - expect(electronBuilderConfig.files).toEqual( - expect.arrayContaining(['!resources/win32{,/**/*}']) - ) - // Regression guard: the working shim must still ship via extraResources. - expect(electronBuilderConfig.win.extraResources).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'resources/win32/bin/orca.cmd', - to: 'bin/orca.cmd' - }) - ]) - ) - }) // macOS 26 UNUserNotificationCenter aborts helpers launched from Resources; ship under MacOS (#7929). - it('ships the mac notification-status helper in Contents/MacOS, not Resources', () => { - expect(electronBuilderConfig.mac.extraFiles).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'native/notification-status-macos/.build/release/orca-notification-status', - to: 'MacOS/orca-notification-status' - }) - ]) - ) - expect(electronBuilderConfig.mac.extraResources).not.toEqual( - expect.arrayContaining([expect.objectContaining({ to: 'orca-notification-status' })]) - ) - }) - - it('ships the mac keyboard-layout helper in Contents/MacOS, not Resources', () => { - expect(electronBuilderConfig.mac.extraFiles).toEqual( - expect.arrayContaining([ - expect.objectContaining({ - from: 'native/keyboard-layout-macos/.build/release/orca-keyboard-layout', - to: 'MacOS/orca-keyboard-layout' - }) - ]) - ) - expect(electronBuilderConfig.mac.extraResources).not.toEqual( - expect.arrayContaining([expect.objectContaining({ to: 'orca-keyboard-layout' })]) - ) - }) - - it('unpacks the compiled CommonJS boundary with CLI runtime files', () => { - expect(electronBuilderConfig.asarUnpack).toEqual( - expect.arrayContaining(['out/package.json', 'out/cli/**', 'out/shared/**']) - ) - }) // Missing unpacked entry silently restores in-process watcher and #7547 main crashes. - it('unpacks the forked parcel-watcher process entry', () => { - expect(electronBuilderConfig.asarUnpack).toEqual( - expect.arrayContaining(['out/main/parcel-watcher-process-entry.js']) - ) - }) - - it('unpacks the replaceable WSL transcript filesystem process entry', async () => { - const entryFilename = 'wsl-transcript-fs-process-entry.js' - expect(electronBuilderConfig.asarUnpack).toContain(`out/main/${entryFilename}`) - }) // CLI Node mode cannot read asar; packed entry sends orca serve to Electron (#27307). it('unpacks the orcad serve-selection entry the CLI runs', async () => { @@ -425,41 +287,6 @@ describe('electron-builder config', () => { } }) - it('keeps the worker-thread hang watchdog inside app.asar', () => { - expect(electronBuilderConfig.asarUnpack).not.toContain( - 'out/main/main-thread-hang-watchdog-entry.js' - ) - }) - - it('uses the multi-size icon source for Linux packages', () => { - expect(electronBuilderConfig.linux.icon).toBe('resources/build/icon.icns') - }) - - it('matches the Linux desktop entry to Electron window class', () => { - expect(electronBuilderConfig.linux.desktop.entry.StartupWMClass).toBe('orca') - }) - - it('uses the release artifact set as local Linux targets without changing existing names', () => { - expect(electronBuilderConfig.linux.target).toEqual(['AppImage', 'deb', 'rpm']) - expect(electronBuilderConfig.toolsets).toEqual({ appimage: '1.0.3' }) - expect(electronBuilderConfig.appImage.artifactName).toBe('orca-linux.${ext}') - expect(electronBuilderConfig.deb.artifactName).toBe('orca-ide_${version}_${arch}.${ext}') - expect(electronBuilderConfig.rpm).toMatchObject({ - packageName: 'orca-ide', - artifactName: 'orca-ide-${version}.${arch}.${ext}' - }) - }) - - it('retains electron-builder runtime dependencies in deb and rpm packages', () => { - for (const target of ['deb', 'rpm']) { - const dependencies = electronBuilderConfig[target].depends - expect(dependencies).toEqual( - expect.arrayContaining(FpmTarget.prototype.getDefaultDepends(target)) - ) - expect(new Set(dependencies).size).toBe(dependencies.length) - } - }) - it('validates each AppImage before electron-builder publishes it', async () => { const root = await mkdtemp(join(tmpdir(), 'orca-electron-builder-appimage-')) try { @@ -548,11 +375,6 @@ describe('electron-builder config', () => { require('../electron-builder.config.cjs') } }) - - it('uses Orca native rebuild hook instead of electron-builder default rebuild', () => { - expect(electronBuilderConfig.beforeBuild).toBe(electronBuilderNativeRebuild) - expect(electronBuilderConfig.npmRebuild).toBe(true) - }) }) describe('arch-aware packaging guard', () => { diff --git a/config/scripts/electron-builder-runtime-resources.test.mjs b/config/scripts/electron-builder-runtime-resources.test.mjs index 77a63230d23..d545526f6d4 100644 --- a/config/scripts/electron-builder-runtime-resources.test.mjs +++ b/config/scripts/electron-builder-runtime-resources.test.mjs @@ -1,8 +1,7 @@ -import { existsSync, readFileSync, readdirSync } from 'node:fs' import { cp, mkdir, mkdtemp, readFile, readdir, stat, writeFile } from 'node:fs/promises' import { createRequire } from 'node:module' import { tmpdir } from 'node:os' -import { delimiter, dirname, join, relative, resolve } from 'node:path' +import { delimiter, dirname, join, resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { removeTree } from '../../src/shared/windows-transient-lock-removal.ts' @@ -10,10 +9,6 @@ const require = createRequire(import.meta.url) const projectRoot = resolve(import.meta.dirname, '..', '..') const electronBuilderConfig = require('../electron-builder.config.cjs') const { - createPackagedRuntimeNodeModuleResources, - findAsarEntry, - isPackagedExternalSpecifier, - packageNameFromSpecifier, prunePackagedNodePty, prunePackagedParcelWatcher, prunePackagedSherpaOnnx, @@ -22,11 +17,6 @@ const { verifyPackagedMainRuntimeDeps } = require('../packaged-runtime-node-modules.cjs') -// Only os:win32 process-tree presence selects Windows plan; universal registry workspace link proves no binary exists. -const windowsAddonsInstalled = existsSync( - join(projectRoot, 'node_modules', '@vscode', 'windows-process-tree', 'package.json') -) - describe('packaged runtime resources', () => { it('verifies packaged main runtime deps from Windows-style asar entries', async () => { const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-runtime-deps-')) @@ -176,13 +166,6 @@ describe('packaged runtime resources', () => { } }) - it('normalizes host-specific asar entry separators', () => { - expect(findAsarEntry(['\\out\\main\\index.js'], 'out/main/index.js')).toBe( - '\\out\\main\\index.js' - ) - expect(findAsarEntry(['/out/main/index.js'], 'out/main/index.js')).toBe('/out/main/index.js') - }) - it('prunes non-target node-pty architecture outputs from packaged runtime resources', async () => { const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-node-pty-prune-')) try { @@ -251,30 +234,6 @@ describe('packaged runtime resources', () => { } }) - it('includes external main dependencies in the packaged runtime closure', () => { - // Without packaged @parcel/watcher, serve silently stops propagating file changes (#4851). - const packaged = createPackagedRuntimeNodeModuleResources() - const packagedTargets = packaged.map((resource) => resource.to) - expect(packagedTargets).toContain(join('node_modules', '@parcel', 'watcher')) - expect( - packagedTargets.some((target) => - target.startsWith(join('node_modules', '@parcel', 'watcher-')) - ) - ).toBe(true) - expect(packagedTargets).toContain(join('node_modules', 'proper-lockfile')) - }) - - it('includes the Claude agent SDK in every desktop package plan', () => { - for (const platform of windowsAddonsInstalled - ? ['darwin', 'linux', 'win32'] - : ['darwin', 'linux']) { - const packagedTargets = createPackagedRuntimeNodeModuleResources(platform).map( - (resource) => resource.to - ) - expect(packagedTargets).toContain(join('node_modules', '@anthropic-ai', 'claude-agent-sdk')) - } - }) - it('prunes non-target @parcel/watcher architecture subpackages', async () => { const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-parcel-watcher-prune-')) try { @@ -573,85 +532,7 @@ async function seedBundledRipgrep(resourcesDir) { } } -// Bundler renames createRequire result, hiding these from bare-require scans; source-anchor or packaging passes before runtime MODULE_NOT_FOUND. -function collectLazyRequireSpecifiers(directory, found = new Map()) { - for (const entry of readdirSync(directory, { withFileTypes: true })) { - const entryPath = join(directory, entry.name) - if (entry.isDirectory()) { - collectLazyRequireSpecifiers(entryPath, found) - continue - } - if (!entry.isFile() || !entry.name.endsWith('.ts') || entry.name.includes('.test.')) { - continue - } - const source = readFileSync(entryPath, 'utf8') - if (!source.includes('createRequire(')) { - continue - } - for (const match of source.matchAll(/\brequire[A-Za-z0-9_]*\(\s*'([^']+)'\s*\)/g)) { - if (isPackagedExternalSpecifier(match[1])) { - found.set(match[1], relative(projectRoot, entryPath).replaceAll('\\', '/')) - } - } - } - return found -} - -function packagedResourceDestinations(platform) { - return new Set( - (electronBuilderConfig[platform].extraResources ?? []).map((resource) => - String(resource.to).replaceAll('\\', '/') - ) - ) -} - describe('lazily required packages reach Resources/node_modules', () => { - it('excludes runtime builtins while retaining ordinary lazy dependencies', async () => { - const sourceDir = await mkdtemp(join(tmpdir(), 'orca-lazy-builtins-')) - try { - await writeFile( - join(sourceDir, 'runtime.ts'), - [ - 'const requireFromMain = createRequire(import.meta.url)', - "requireFromMain('node:fs')", - "requireFromMain('zod')" - ].join('\n') - ) - expect([...collectLazyRequireSpecifiers(sourceDir).keys()]).toEqual(['zod']) - } finally { - await removeTree(sourceDir) - } - }) - - it('copies every createRequire specifier main uses into the packaged resource plan', () => { - const specifiers = collectLazyRequireSpecifiers(join(projectRoot, 'src', 'main')) - expect(specifiers.size).toBeGreaterThan(0) - - const destinations = { - win: packagedResourceDestinations('win'), - mac: packagedResourceDestinations('mac'), - linux: packagedResourceDestinations('linux') - } - for (const [specifier, source] of specifiers) { - const packageName = packageNameFromSpecifier(specifier) - const covered = (platform) => - destinations[platform].has(`node_modules/${packageName}`) || - destinations[platform].has(`node_modules/${specifier}`) - // The Windows CI lane checks the full closure with its native addons installed. - if (windowsAddonsInstalled) { - expect( - covered('win'), - `${source} lazily requires '${specifier}', but nothing copies it to Resources/node_modules` - ).toBe(true) - } - if (covered('mac') && covered('linux')) { - continue - } - // Only the Windows-native loaders may be absent from the mac/linux plans. - expect(source, `'${specifier}' is packaged for Windows only`).toContain('windows') - } - }) - it('resolves the copied emoji dataset the way the packaged main bundle does', async () => { const resourcesDir = await mkdtemp(join(tmpdir(), 'orca-lazy-require-')) try { diff --git a/config/scripts/mobile-web-app/mobile-web-app-session-dictation-capture.test.mjs b/config/scripts/mobile-web-app/mobile-web-app-session-dictation-capture.test.mjs index 23f274a2cc7..c7c485d67ed 100644 --- a/config/scripts/mobile-web-app/mobile-web-app-session-dictation-capture.test.mjs +++ b/config/scripts/mobile-web-app/mobile-web-app-session-dictation-capture.test.mjs @@ -2,15 +2,11 @@ // Web seam removes native audio/keep-awake: their web stubs deny microphone and do nothing, rather than capturing through shell. // Resolve package names before absence checks to catch typos; assert eight excluded vendored modules, not drifting total closure size. import { createRequire } from 'node:module' -import { fileURLToPath } from 'node:url' import { describe, expect, it } from 'vitest' import { mobileWebAppRouteClosure } from '../build-mobile-web-app-bundle.mjs' import { mobileWebAppDependenciesPresent } from './mobile-web-app-bundle-dependencies.mjs' import { MOBILE_WEB_PAGE_ROUTES } from '../mobile-web-page-routes.mjs' -import { - PAGE_ROUTE_MODULES, - pageRouteModulesCoverTheManifest -} from './mobile-web-app-page-route-modules.mjs' +import { PAGE_ROUTE_MODULES } from './mobile-web-app-page-route-modules.mjs' import { MobileWebBundleRouteSchema } from '../../../src/shared/mobile-web-bundle/manifest-contract.ts' // Gate mobile transforms too: nearest tsconfig extends Expo package absent from root-only shards. @@ -21,7 +17,6 @@ const SEAM = 'src/platform/dictation-capture.web.ts' const NATIVE_SEAM = 'src/platform/dictation-capture.ts' -// Use census’s verb set; bridge-audio-verbs.test.ts checks it against shell table. const DICTATION_GRANTS = ['native.audio.start', 'native.audio.read', 'native.audio.stop'] // Native modules reach JSI; browser substitutes denied microphone and no-op wake lock. @@ -74,24 +69,6 @@ describeClosure( expect(await grantsMissingForRoutes(MOBILE_WEB_PAGE_ROUTES)).toEqual([]) }) - it('finds the seam in exactly one closure, which is the session route', async () => { - const reaching = [] - for (const route of MOBILE_WEB_PAGE_ROUTES) { - const module = PAGE_ROUTE_MODULES.get(route.pathname) - if (module === undefined) { - throw new Error(`No route module for ${route.pathname}`) - } - const closure = await closureOf(module) - if (closure.local.includes(SEAM)) { - reaching.push(route.pathname) - } - } - // Require session route reaches seam; absence checks must not pass because dictation left page. - expect(reaching).toEqual([SESSION_PATHNAME]) - const session = await closureOf(SESSION) - expect(session.local).toContain(SEAM) - }) - it('reds the same rule when the session route is registered without them', async () => { // Drive same rule over under-granted entry to prove missing grants are detected. expect( @@ -133,30 +110,3 @@ describeClosure( }, 240_000 ) - -describe('the census rule itself', () => { - it('names a route module for every registered pathname', () => { - const { mapped, declared } = pageRouteModulesCoverTheManifest(MOBILE_WEB_PAGE_ROUTES) - expect(mapped).toEqual(declared) - }) - - // Dynamic import delays load but still transforms mobile tsconfig extending absent Expo; dependency gate must enclose import on root-only shards. - it.skipIf(!bundles)( - 'names only verbs the shell actually serves, read from its own table', - async () => { - // Require shell verb-table entries; route census agreeing with its own copied names proves nothing. - const { BRIDGE_NATIVE_VERB_NAMES } = - await import('../../../mobile/src/mobile-web-shell/bridge/bridge-native-verbs.ts') - expect(new Set(DICTATION_GRANTS).size).toBe(3) - for (const grant of DICTATION_GRANTS) { - expect(BRIDGE_NATIVE_VERB_NAMES, grant).toContain(grant) - expect( - MobileWebBundleRouteSchema.safeParse({ pathname: '/h', grants: [grant] }).success, - grant - ).toBe(true) - } - } - ) -}) - -export const MOBILE_DIR = fileURLToPath(new URL('../../../mobile/', import.meta.url)) diff --git a/config/scripts/mobile-web-app/mobile-web-app-session-terminal-closure.test.mjs b/config/scripts/mobile-web-app/mobile-web-app-session-terminal-closure.test.mjs index ffd08ea779e..442b9c3d04d 100644 --- a/config/scripts/mobile-web-app/mobile-web-app-session-terminal-closure.test.mjs +++ b/config/scripts/mobile-web-app/mobile-web-app-session-terminal-closure.test.mjs @@ -1,27 +1,13 @@ -import { join } from 'node:path' -import { fileURLToPath } from 'node:url' import { beforeAll, describe, expect, it } from 'vitest' import { mobileWebAppRouteClosure } from '../build-mobile-web-app-bundle.mjs' import { mobileWebAppDependenciesPresent } from './mobile-web-app-bundle-dependencies.mjs' import { mobileWebAppRouteChunkClosure } from './mobile-web-app-route-chunk-closure.mjs' -import { - editableHostFontSizeOffenders, - editableHostsIn, - unresolvedEditableHostStyles -} from './platform-seams/mobile-web-app-editable-host-font-size.mjs' -import { - textInputFontSizeOffenders, - unresolvedTextInputStyles -} from './platform-seams/mobile-web-app-text-input-font-size-seam.mjs' // Require terminal source modules/xterm, excluding WebView engine strings and generated document/factory to avoid shipping document twice. // Remeasure closure after generators and upstream merges; shared inputs make summed historical module deltas unreliable. // Input metafile includes dynamic imports: only emitted static import-statement edges prove Mermaid is deferred. // Prebundle Mermaid as one artifact; package splitting once emitted 103 scripts against shell’s 256-asset limit. Deferral saves fetch/evaluation, not OTA download. -const projectDir = fileURLToPath(new URL('../../..', import.meta.url)) -const mobileDir = join(projectDir, 'mobile') - const SESSION_ROUTE = 'app/h/[hostId]/session/[worktreeId].tsx' // WebView-only generated programs cannot execute in page. @@ -49,9 +35,6 @@ const GAINED_OUTSIDE_THE_DOCUMENT = [ const XTERM_PACKAGES = ['@xterm/xterm', '@xterm/addon-unicode11', '@xterm/addon-webgl'] -// Keep all route text inputs above focus-zoom floor, including newly imported terminal inputs. -const EXPECTED_OFFENDERS = 0 - const MERMAID_PAGE_ENGINE = 'src/components/pr-sidebar/mermaid-page-engine.generated.ts' const MERMAID_PACKAGE = 'node_modules/mermaid/' @@ -123,25 +106,6 @@ describeClosure( // Require route chunk in walk so empty static download cannot pass. expect(download.staticChunks).toContain(download.routeChunk) }, 600_000) - - it('leaves the 16px seam census exactly where C7.2 left it', async () => { - // Require seam reachable and every style resolved before interpreting zero offenders. - expect(closure.local).toContain('src/platform/text-input-font-size.web.ts') - expect(unresolvedTextInputStyles(mobileDir, closure)).toEqual([]) - expect(textInputFontSizeOffenders(mobileDir, closure)).toHaveLength(EXPECTED_OFFENDERS) - expect(closure.local).toContain('src/session/mobile-native-chat-input-styles.web.ts') - expect(closure.local).not.toContain('src/session/mobile-native-chat-input-styles.ts') - }, 300_000) - - it('holds the editables the TextInput census cannot see to the same floor', async () => { - // Rich editor contenteditable lives in markup/CSS, invisible to JSX text-input census; check same font floor through markup. - expect(editableHostsIn(mobileDir, closure)).toContainEqual({ - file: 'src/components/rich-markdown/document-markup.ts', - id: 'editor' - }) - expect(unresolvedEditableHostStyles(mobileDir, closure)).toEqual([]) - expect(editableHostFontSizeOffenders(mobileDir, closure)).toEqual([]) - }, 300_000) }, 900_000 ) diff --git a/config/scripts/orcad-entry-build.test.mjs b/config/scripts/orcad-entry-build.test.mjs index d925ebe2d80..a72189fa61a 100644 --- a/config/scripts/orcad-entry-build.test.mjs +++ b/config/scripts/orcad-entry-build.test.mjs @@ -8,7 +8,6 @@ import { buildOrcadEntry, escapeLegalCommentTail, findNonAsciiSource, - moduleAtOffset, ORCAD_COMMONJS_MODULE_OPTIONS } from './orcad-entry-build.mjs' import { runProcessSync } from '@orca/process-host' @@ -111,11 +110,6 @@ it('keeps the server bundle ASCII, so V8 stores its source one byte per characte expect(findNonAsciiSource(readFileSync(bundle, 'utf8'))).toBeNull() }) -it('names the line of a non-ASCII character a regex literal or tagged template left', () => { - expect(findNonAsciiSource('a=1\nb=/[\\u2726]/')).toBeNull() - expect(findNonAsciiSource('a=1\nb=/[\u2726]/')).toMatchObject({ offset: 8, line: 2 }) -}) - it('escapes only the trailing license comment, never code', () => { const code = 'a=/[\u2726]/;' const escaped = escapeLegalCommentTail( @@ -127,12 +121,6 @@ it('escapes only the trailing license comment, never code', () => { expect(escapeLegalCommentTail(code)).toBe(code) }) -it('names the module an unminified build placed an offset in', () => { - const source = 'x\n// src/a.ts\nvar a = 1;\n// node_modules/b/index.js\nvar b = /\u2726/;\n' - expect(moduleAtOffset(source, source.indexOf('\u2726'))).toBe('node_modules/b/index.js') - expect(moduleAtOffset(source, source.indexOf('var a'))).toBe('src/a.ts') -}) - it('keeps a build with every dark switch turned on ASCII', () => { const darkBundle = join(directory, 'orcad-server-dark.js') const built = runProcessSync({ diff --git a/config/scripts/package-electron-runtime-contract.test.mjs b/config/scripts/package-electron-runtime-contract.test.mjs index 5921f7f6727..2d6024dbac3 100644 --- a/config/scripts/package-electron-runtime-contract.test.mjs +++ b/config/scripts/package-electron-runtime-contract.test.mjs @@ -1,155 +1,13 @@ -import { existsSync, readFileSync } from 'node:fs' -import { createRequire } from 'node:module' +import { readFileSync } from 'node:fs' import { join, resolve } from 'node:path' import { runInNewContext } from 'node:vm' import { describe, expect, it } from 'vitest' import { parse } from 'yaml' -import { compileAggregateExpression } from './pr-aggregate-gate-context.mjs' const projectDir = resolve(import.meta.dirname, '../..') -const require = createRequire(import.meta.url) -const { createPackagedRuntimeNodeModuleResources } = require('../packaged-runtime-node-modules.cjs') const readProject = (file) => readFileSync(join(projectDir, file), 'utf8') -const packageJson = JSON.parse(readProject('package.json')) -const pnpmWorkspace = parse(readProject('pnpm-workspace.yaml')) -// Resolve the win32 plan wherever its OS-gated addon is installed; windows-registry is a workspace link on every platform. -const windowsAddonsInstalled = existsSync( - join(projectDir, 'node_modules', '@vscode', 'windows-process-tree', 'package.json') -) describe('Electron runtime package contract', () => { - const packageTargets = { - win32: windowsAddonsInstalled ? createPackagedRuntimeNodeModuleResources('win32') : [], - darwin: createPackagedRuntimeNodeModuleResources('darwin'), - linux: createPackagedRuntimeNodeModuleResources('linux') - } - - it('keeps the native Windows registry addon optional and platform-gated', () => { - expect(packageJson.optionalDependencies['@orca/windows-registry']).toBe('workspace:*') - // allowBuilds suppresses install-time node-gyp; the Windows rebuild owns the addon’s runtime ABI. - expect(pnpmWorkspace.allowBuilds['@orca/windows-registry']).toBe(false) - if (windowsAddonsInstalled) { - expect(packageTargets.win32).toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@orca', 'windows-registry') }), - expect.objectContaining({ to: join('node_modules', 'node-addon-api') }) - ]) - ) - } - for (const platform of ['darwin', 'linux']) { - expect(packageTargets[platform]).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@orca', 'windows-registry') }) - ]) - ) - } - }) - - // Without it the secure-file writes report unrestricted and orcad's privacy check fails closed. - it('ships the native Windows ACL addon on Windows only, built by the Windows rebuild', () => { - expect(packageJson.optionalDependencies['@orca/windows-security']).toBe('workspace:*') - expect(pnpmWorkspace.allowBuilds['@orca/windows-security']).toBe(false) - if (windowsAddonsInstalled) { - expect(packageTargets.win32).toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@orca', 'windows-security') }) - ]) - ) - } - for (const platform of ['darwin', 'linux']) { - expect(packageTargets[platform]).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@orca', 'windows-security') }) - ]) - ) - } - }) - - it('keeps the native Windows process-table addon optional and platform-gated', () => { - expect(packageJson.optionalDependencies['@vscode/windows-process-tree']).toBe('0.8.0') - // As with registry, suppress install-time node-gyp so the Windows rebuild selects the runtime ABI. - expect(pnpmWorkspace.allowBuilds['@vscode/windows-process-tree']).toBe(false) - // Patch removes unavailable Spectre-library requirement and 1024-process enumeration cap that hides descendants on busy hosts. - expect(pnpmWorkspace.patchedDependencies['@vscode/windows-process-tree@0.8.0']).toBe( - 'config/patches/@vscode__windows-process-tree@0.8.0.patch' - ) - if (windowsAddonsInstalled) { - expect(packageTargets.win32).toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@vscode', 'windows-process-tree') }) - ]) - ) - } - for (const platform of ['darwin', 'linux']) { - expect(packageTargets[platform]).not.toEqual( - expect.arrayContaining([ - expect.objectContaining({ to: join('node_modules', '@vscode', 'windows-process-tree') }) - ]) - ) - } - }) - - it('keeps release-cut signing provenance on GitHub-hosted runners', () => { - const releaseWorkflow = parse( - readFileSync(join(projectDir, '.github/workflows/release-cut.yml'), 'utf8') - ) - const buildMatrixRunners = releaseWorkflow.jobs.build.strategy.matrix.include.map( - ({ os }) => os - ) - const releaseWorkflowText = readFileSync( - join(projectDir, '.github/workflows/release-cut.yml'), - 'utf8' - ) - const macDispatchStep = releaseWorkflow.jobs['build-mac'].steps.find( - (step) => step.name === 'Run isolated macOS release build' - ) - - expect(releaseWorkflowText).not.toContain('blacksmith-') - for (const caller of Object.values(releaseWorkflow.jobs)) { - if (!caller.uses?.startsWith('./.github/workflows/')) { - continue - } - const child = parse(readProject(caller.uses)) - const inputs = { - ...Object.fromEntries( - Object.entries(child.on.workflow_call.inputs).map(([name, input]) => [ - name, - input.default ?? '' - ]) - ), - ...caller.with - } - for (const job of Object.values(child.jobs)) { - if (!job['runs-on']) { - continue - } - const runner = job['runs-on'].startsWith('${{') - ? compileAggregateExpression(job['runs-on'], ['inputs'])({ inputs }).coerceString() - : job['runs-on'] - expect(runner).not.toMatch(/^(blacksmith-|orca-)/) - } - } - expect(releaseWorkflow.jobs['build-mac']['runs-on']).toBe('ubuntu-latest') - expect(releaseWorkflow.jobs['build-mac'].permissions.actions).toBe('write') - expect(macDispatchStep.run).toBe( - 'node config/scripts/run-release-mac-build-workflow.mjs dispatch' - ) - expect(macDispatchStep.env.RELEASE_MAC_BUILD_WORKFLOW).toBe('release-mac-build.yml') - expect(macDispatchStep.env.RELEASE_MAC_BUILD_TAG).toBe('${{ needs.cut.outputs.tag }}') - expect(buildMatrixRunners).not.toContain('blacksmith-6vcpu-macos-15') - expect(releaseWorkflow.jobs['publish-release'].needs).toContain('build') - expect(releaseWorkflow.jobs['publish-release'].needs).toContain('build-mac') - expect(releaseWorkflow.jobs['publish-release'].needs).toContain('verify-mac-build') - const macVerification = releaseWorkflow.jobs['verify-mac-build'] - expect(macVerification.needs).toEqual(['cut', 'build-mac', 'build']) - expect(macVerification.if).toContain('!cancelled()') - expect(macVerification.if).not.toContain('needs.build.result') - expect(macVerification.permissions).toEqual({ actions: 'read', contents: 'read' }) - expect(releaseWorkflow.jobs['publish-release'].if).toContain( - "needs.verify-mac-build.result == 'success'" - ) - }) - it('qualifies macOS after failed sibling builds and publishes only complete successful builds', () => { const { jobs } = parse(readProject('.github/workflows/release-cut.yml')) const evaluate = (source, needs, cancelled) => diff --git a/config/scripts/replace-cached-nsis-elevate.test.mjs b/config/scripts/replace-cached-nsis-elevate.test.mjs index c815bd47bc2..ace7a7715d1 100644 --- a/config/scripts/replace-cached-nsis-elevate.test.mjs +++ b/config/scripts/replace-cached-nsis-elevate.test.mjs @@ -1,13 +1,5 @@ import { spawnSync } from 'node:child_process' -import { - existsSync, - mkdirSync, - mkdtempSync, - readdirSync, - readFileSync, - rmSync, - writeFileSync -} from 'node:fs' +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs' import { tmpdir } from 'node:os' import { join, resolve } from 'node:path' import { afterEach, beforeEach, describe, expect, it } from 'vitest' @@ -15,7 +7,6 @@ import { afterEach, beforeEach, describe, expect, it } from 'vitest' import { findCachedElevatePaths, replaceCachedElevateHelpers, - resolveElectronBuilderCacheDir, summarizeSwap } from './replace-cached-nsis-elevate.mjs' @@ -116,44 +107,7 @@ describe('cached elevate.exe swap covers the real electron-builder layouts', () ).toEqual([join(overrideDir, 'elevate.exe')]) }) - it('resolves the cache root the same way app-builder-lib does', () => { - expect( - resolveElectronBuilderCacheDir({ - env: { LOCALAPPDATA: 'C:\\Users\\runneradmin\\AppData\\Local' }, - platform: 'win32' - }) - ).toBe(join('C:\\Users\\runneradmin\\AppData\\Local', 'electron-builder', 'Cache')) - expect(resolveElectronBuilderCacheDir({ env: {}, platform: 'darwin', home: '/Users/a' })).toBe( - join('/Users/a', 'Library', 'Caches', 'electron-builder') - ) - expect(resolveElectronBuilderCacheDir({ env: { ELECTRON_BUILDER_CACHE: '/mnt/cache' } })).toBe( - '/mnt/cache' - ) - }) - // Compare real cache scan against independent unbounded walk to catch vacuous empty matches; skip only if no bundle is cached. - it('finds every elevate.exe the real electron-builder cache holds', (ctx) => { - const cacheDir = resolveElectronBuilderCacheDir() - if (!existsSync(cacheDir)) { - // Report missing real cache as skipped, never passed; fixture-only coverage cannot validate unknown layouts. - ctx.skip() - return - } - const walk = (dir) => - readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { - const path = join(dir, entry.name) - if (entry.isDirectory()) { - return walk(path) - } - return entry.name.toLowerCase() === 'elevate.exe' ? [path] : [] - }) - const onDisk = walk(cacheDir) - if (onDisk.length === 0) { - ctx.skip() - return - } - expect(findCachedElevatePaths(cacheDir, { env: {} }).sort()).toEqual(onDisk.sort()) - }) }) describe('the probe, not the scan, decides whether the swap worked', () => { diff --git a/config/scripts/resolve-7za-path.test.mjs b/config/scripts/resolve-7za-path.test.mjs index 2e47e68fed6..88f75fede66 100644 --- a/config/scripts/resolve-7za-path.test.mjs +++ b/config/scripts/resolve-7za-path.test.mjs @@ -10,19 +10,6 @@ const projectRoot = resolve(import.meta.dirname, '../..') describe('7za path resolution for the Windows signing gates (#6487)', () => { // Match upstream mac/win/linux architecture dirs; darwin/ or collapsed-arch guesses silently fail to resolve. - it.each([ - ['darwin', 'arm64', 'mac/arm64/7za'], - ['darwin', 'x64', 'mac/x64/7za'], - ['win32', 'x64', 'win/x64/7za.exe'], - ['win32', 'ia32', 'win/ia32/7za.exe'], - ['win32', 'arm64', 'win/arm64/7za.exe'], - ['linux', 'x64', 'linux/x64/7za'], - ['linux', 'arm64', 'linux/arm64/7za'] - ])('maps the %s/%s legacy layout to %s', (platform, arch, expected) => { - expect(legacy7zaRelativePath(platform, arch).join('/')).toBe( - `node_modules/7zip-bin/${expected}` - ) - }) it('prefers an existing legacy file over the downloaded toolset', async () => { const scratch = mkdtempSync(join(tmpdir(), 'orca 7za legacy ')) diff --git a/config/scripts/run-audit-tool.test.mjs b/config/scripts/run-audit-tool.test.mjs index 7d3ad7b606f..507897c4ae9 100644 --- a/config/scripts/run-audit-tool.test.mjs +++ b/config/scripts/run-audit-tool.test.mjs @@ -1,11 +1,9 @@ -import { readFileSync } from 'node:fs' import { join, resolve } from 'node:path' import { runProcessSync } from '@orca/process-host' import { DEFAULT_MAX_OUTPUT_BYTES } from '@orca/process-host/process-spec' import { describe, expect, it, vi } from 'vitest' -import { parseAllDocuments } from 'yaml' + import { auditToolEntry, runAuditTool } from './run-audit-tool.mjs' -import { classifyPrJobs } from './pr-code-change-scope.mjs' const root = resolve(import.meta.dirname, '../..') const success = { code: 0, signal: null, timedOut: false } @@ -97,34 +95,4 @@ describe('locked audit tool execution', () => { expect(() => runAuditTool('../arbitrary-package', [], { run })).toThrow('Unknown audit tool') expect(run).not.toHaveBeenCalled() }) - - it.each(['package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml'])( - 'selects the real-tool CI smoke for an isolated %s update', - (file) => { - expect(classifyPrJobs([`config/audit-tools/${file}`]).static_analysis).toBe(true) - } - ) - - it('keeps the tool workspace isolated, exact and integrity-locked', () => { - const manifest = JSON.parse(readFileSync(join(root, 'config/audit-tools/package.json'), 'utf8')) - const rootManifest = JSON.parse(readFileSync(join(root, 'package.json'), 'utf8')) - expect(manifest.packageManager).toBe(rootManifest.packageManager) - const [policy] = parseAllDocuments( - readFileSync(join(root, 'config/audit-tools/pnpm-workspace.yaml'), 'utf8') - ).map((document) => document.toJS()) - expect(policy).toMatchObject({ minimumReleaseAge: 4320, ignoreScripts: true, allowBuilds: {} }) - const documents = parseAllDocuments( - readFileSync(join(root, 'config/audit-tools/pnpm-lock.yaml'), 'utf8') - ).map((document) => document.toJS()) - const lock = documents.find((document) => document.importers?.['.']?.dependencies) - expect(Object.keys(lock.importers)).toEqual(['.']) - for (const [name, version] of Object.entries(manifest.dependencies)) { - expect(version).toMatch(/^\d+\.\d+\.\d+$/) - expect(lock.importers['.'].dependencies[name].specifier).toBe(version) - expect(rootManifest.dependencies[name] ?? rootManifest.devDependencies[name]).toBeUndefined() - } - for (const entry of Object.values(lock.packages)) { - expect(entry.resolution.integrity).toMatch(/^sha512-/) - } - }) }) diff --git a/config/scripts/vitest-sqlite-runtime-boundary.test.ts b/config/scripts/vitest-sqlite-runtime-boundary.test.ts index dfa86f7a60e..b9f78c00233 100644 --- a/config/scripts/vitest-sqlite-runtime-boundary.test.ts +++ b/config/scripts/vitest-sqlite-runtime-boundary.test.ts @@ -1,11 +1,6 @@ -import { existsSync, readFileSync } from 'node:fs' +import { readFileSync } from 'node:fs' import { expect, it } from 'vitest' -import { importsSqliteRuntime, SQLITE_MODULES } from './vitest-sqlite-runtime-scan.mjs' - -// A moved module would silently send its importers back to Bun. -it.each(SQLITE_MODULES)('scans for a SQLite module that still exists: %s', (module) => { - expect(existsSync(`${module}.ts`)).toBe(true) -}) +import { importsSqliteRuntime } from './vitest-sqlite-runtime-scan.mjs' it.each([ ['import { createRestTestRig } from "./structured-agent-session-rest-test-rig"', true], diff --git a/config/scripts/windows-cmd-shim-spawn-boundary.test.mjs b/config/scripts/windows-cmd-shim-spawn-boundary.test.mjs index 2fc8c37cc49..3bed0b77625 100644 --- a/config/scripts/windows-cmd-shim-spawn-boundary.test.mjs +++ b/config/scripts/windows-cmd-shim-spawn-boundary.test.mjs @@ -29,7 +29,6 @@ const WINDOWS_SHIM_SPAWN_ALLOWLIST = [ // Write or assert on shim files rather than spawning one. 'config/scripts/dev-cli-terminal-wrapper.mjs', 'config/scripts/dev-cli-terminal-wrapper.test.mjs', - 'config/scripts/electron-builder-config.test.mjs', 'config/scripts/live-remote-freeze-rpc.mjs', 'config/scripts/pty-transcript-secret-scan.test.mjs', 'config/scripts/remote-agent-session-authority-repro.mjs', diff --git a/mobile/src/mobile-web-shell/bridge/bridge-audio-verbs.test.ts b/mobile/src/mobile-web-shell/bridge/bridge-audio-verbs.test.ts index 460d086bf4f..a6a285d6785 100644 --- a/mobile/src/mobile-web-shell/bridge/bridge-audio-verbs.test.ts +++ b/mobile/src/mobile-web-shell/bridge/bridge-audio-verbs.test.ts @@ -1,6 +1,6 @@ // Exercise table-listed audio verbs through the engine seam; denied permission, full rings and post-stop reads are device-independent conditions expensive to force in simulators. import { afterEach, describe, expect, it } from 'vitest' -import { MobileWebBundleRouteSchema } from '../../../../src/shared/mobile-web-bundle/manifest-contract' + import { BridgeNativeVerbRefusedError } from '../bridge-host-errors' import { createNativeAudioCapture, type NativeAudioEngine } from '../../platform/native-audio' import { @@ -36,8 +36,6 @@ function gate() { return { promise, release: () => release() } } -const AUDIO_VERBS = ['native.audio.start', 'native.audio.read', 'native.audio.stop'] as const - function createTestEngine( overrides: Partial<{ permission: NativeAudioEngine['requestPermission'] @@ -121,24 +119,6 @@ function decode(base64: string): Uint8Array { return bytes } -describe('the audio verbs in the table', () => { - it('accepts the audio verbs as route grants', () => { - for (const verb of AUDIO_VERBS) { - expect( - MobileWebBundleRouteSchema.safeParse({ pathname: '/h', grants: [verb] }).success, - verb - ).toBe(true) - } - }) - - it('refuses the camel-cased spelling of the read, which is what makes the name load-bearing', () => { - expect( - MobileWebBundleRouteSchema.safeParse({ pathname: '/h', grants: ['native.audio.readChunk'] }) - .success - ).toBe(false) - }) -}) - describe('what the audio schemas refuse', () => { it('refuses a start with no rate, a rate off the grid, and an unknown param', () => { expect(audioStartParamsSchema.safeParse({}).success).toBe(false) diff --git a/mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts b/mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts index 26346fd9d2d..8e12e76f211 100644 --- a/mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts +++ b/mobile/src/session/MobileNativeChatSessionOptionPickers.test.ts @@ -178,13 +178,6 @@ describe('MobileNativeChatSessionOptionPickers', () => { }) }) - it('lets the pill shrink so a long label never pushes the composer buttons off the row', () => { - mount([MODEL_DESCRIPTOR, EFFORT_DESCRIPTOR]) - expect(findAllByHostType(renderer!.root, 'View')[0]!.props.style).toMatchObject({ - flexShrink: 1 - }) - }) - it('opens the model sheet and applies a picked model', async () => { mount([MODEL_DESCRIPTOR, EFFORT_DESCRIPTOR]) await act(async () => pill('Model').props.onPress()) diff --git a/mobile/src/session/MobileNativeChatToolRun.test.tsx b/mobile/src/session/MobileNativeChatToolRun.test.tsx index b04b17bb99b..565242d550b 100644 --- a/mobile/src/session/MobileNativeChatToolRun.test.tsx +++ b/mobile/src/session/MobileNativeChatToolRun.test.tsx @@ -480,12 +480,6 @@ describe('ToolRun', () => { }) }) - it('lets a tap inside the run land while the keyboard is up, as the transcript list does', () => { - const tree = render([{ type: 'tool-call', name: 'Bash', input: { command: 'ls' } }]) - const boxes = tree.root.findAll((node) => String(node.type) === 'ScrollView') - expect(boxes.map((box) => box.props.keyboardShouldPersistTaps)).toEqual(['handled']) - }) - it('follows new work at the end of a live run, but holds still when the reader opens a row', () => { const live = (blocks: NativeChatBlock[]) => createElement(ToolRun, { @@ -530,23 +524,6 @@ describe('ToolRun', () => { expect(scrolls.toEnd).toHaveBeenCalledTimes(1) }) - it("keeps a row's output out of inline selection where the platform forbids it", () => { - const tree = render([ - { type: 'tool-call', name: 'Bash', input: { command: 'ls' } }, - { type: 'tool-result', output: 'a.ts' } - ]) - act(() => { - tree.root - .findAll((node) => String(node.type) === 'Pressable') - .findLast((node) => textIn(node).includes('ls'))! - .props.onPress() - }) - const output = tree.root.findAll( - (node) => String(node.type) === 'Text' && textIn(node)[0] === 'a.ts' - )[0]! - expect(output.props.selectable).toBe(false) - }) - it('does not save a follow for a later row opening when new work left the height unchanged', () => { const live = (blocks: NativeChatBlock[]) => createElement(ToolRun, { diff --git a/mobile/src/session/mobile-native-chat-pending-baseline.test.ts b/mobile/src/session/mobile-native-chat-pending-baseline.test.ts index e4b984729fc..d301b811bb9 100644 --- a/mobile/src/session/mobile-native-chat-pending-baseline.test.ts +++ b/mobile/src/session/mobile-native-chat-pending-baseline.test.ts @@ -28,19 +28,6 @@ function unresolved( describe('rebaseMobileNativeChatPendingBaselines', () => { const history = [userTurn('m1', 'run the tests', 1000), assistantTurn('m2', 'passed', 1100)] - it('returns the same array when every baseline is already resolved', () => { - const pending: MobileNativeChatPendingMessage[] = [ - { - id: 'p1', - text: 'hi', - expectedOccurrence: 1, - baselineTailMessageId: 'm2', - baselineResolved: true - } - ] - expect(rebaseMobileNativeChatPendingBaselines(history, pending)).toBe(pending) - }) - it('gives an unresolved send the loaded tail as its glue boundary', () => { expect( rebaseMobileNativeChatPendingBaselines(history, [unresolved('p1', 'run the tests')]) diff --git a/mobile/src/session/mobile-native-chat-tool-summary.test.ts b/mobile/src/session/mobile-native-chat-tool-summary.test.ts index 7fa212b3218..52d4b47a9ca 100644 --- a/mobile/src/session/mobile-native-chat-tool-summary.test.ts +++ b/mobile/src/session/mobile-native-chat-tool-summary.test.ts @@ -1,34 +1,7 @@ import { describe, expect, it, vi } from 'vitest' -import { - summarizeToolInput, - toolFilePath -} from '../../../src/shared/native-chat/tools/native-chat-tool-summary' +import { summarizeToolInput } from '../../../src/shared/native-chat/tools/native-chat-tool-summary' describe('summarizeToolInput', () => { - it('passes short strings through, collapsing whitespace', () => { - expect(summarizeToolInput('ls -la\n/tmp')).toBe('ls -la /tmp') - }) - - it('serializes objects to compact JSON', () => { - expect(summarizeToolInput({ path: 'a.ts', limit: 5 })).toBe('{"path":"a.ts","limit":5}') - }) - - it('truncates long previews with an ellipsis', () => { - const long = `prefix ${'x'.repeat(200)}` - const out = summarizeToolInput(long) - expect(out).toBe(`prefix ${'x'.repeat(72)}…`) - }) - - it('returns empty string for null/undefined', () => { - expect(summarizeToolInput(null)).toBe('') - expect(summarizeToolInput(undefined)).toBe('') - }) - - it('handles numbers and booleans', () => { - expect(summarizeToolInput(42)).toBe('42') - expect(summarizeToolInput(true)).toBe('true') - }) - it('does not traverse an unbounded tool-input object for a short preview', () => { const input: Record = Object.fromEntries( Array.from({ length: 8 }, (_unused, index) => [`key${index}`, index]) @@ -40,17 +13,3 @@ describe('summarizeToolInput', () => { expect(lateGetter).not.toHaveBeenCalled() }) }) - -describe('toolFilePath', () => { - it('extracts file_path / filePath / path / notebook_path', () => { - expect(toolFilePath({ file_path: 'src/a.ts' })).toBe('src/a.ts') - expect(toolFilePath({ filePath: 'src/b.ts' })).toBe('src/b.ts') - expect(toolFilePath({ path: 'src/c.ts' })).toBe('src/c.ts') - expect(toolFilePath({ notebook_path: 'n.ipynb' })).toBe('n.ipynb') - }) - it('returns null when there is no file target', () => { - expect(toolFilePath({ command: 'ls' })).toBeNull() - expect(toolFilePath('x')).toBeNull() - expect(toolFilePath(null)).toBeNull() - }) -}) diff --git a/mobile/src/session/mobile-native-chat-unsent-notices.test.ts b/mobile/src/session/mobile-native-chat-unsent-notices.test.ts index 321c4177222..cd3481dc86a 100644 --- a/mobile/src/session/mobile-native-chat-unsent-notices.test.ts +++ b/mobile/src/session/mobile-native-chat-unsent-notices.test.ts @@ -48,22 +48,6 @@ const startRow: AgentJournalRenderItem = { } describe("the phone's line under a not-sent message", () => { - it.each([ - ['claude', 'Claude'], - ['codex', 'Codex'] - ])('names %s when its terminal holds the conversation', (agent, name) => { - const notices = mobileNativeChatUnsentNotices( - { - items: [], - submissions: [submission('held', { rejection: { kind: 'conversationOpenInTerminal' } })] - }, - agent - ) - expect(notices.get(agentJournalSubmissionKey('held'))).toBe( - `${name} is already running this conversation in another terminal. Quit ${name} there or close that terminal to continue here.` - ) - }) - it("words each rejected message as the desktop does, naming the chat's agent", () => { const notices = mobileNativeChatUnsentNotices( { diff --git a/mobile/src/session/mobile-structured-agent-session-host-support.test.ts b/mobile/src/session/mobile-structured-agent-session-host-support.test.ts deleted file mode 100644 index ddaaee059c2..00000000000 --- a/mobile/src/session/mobile-structured-agent-session-host-support.test.ts +++ /dev/null @@ -1,90 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { AGENT_SESSION_COHERENT_MODEL_CATALOG_CAPABILITY } from '../../../src/shared/structured-agent-session-surface-capabilities' -import { - AGENT_SESSION_ATTACHMENTS_RUNTIME_CAPABILITY, - AGENT_SESSION_ITEM_DETAIL_RUNTIME_CAPABILITY, - AGENT_SESSION_CONVERSATION_STOP_RUNTIME_CAPABILITY, - AGENT_SESSION_PHONE_ATTACHMENTS_RUNTIME_CAPABILITY, - AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY, - AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY, - AGENT_SESSION_QUEUED_COMMANDS_RUNTIME_CAPABILITY, - AGENT_SESSION_QUEUED_MESSAGE_EDIT_RUNTIME_CAPABILITY, - AGENT_SESSION_QUEUED_MESSAGE_IMAGE_EDIT_RUNTIME_CAPABILITY, - AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY, - AGENT_SESSION_STATUS_FEED_RUNTIME_CAPABILITY, - AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY -} from '../../../src/shared/protocol-version' -import { AGENT_SESSION_SEND_OPTIONS_RUNTIME_CAPABILITY } from '../../../src/shared/agent-session-create-capabilities' -import { AGENT_SESSION_PERMISSION_MODES_RUNTIME_CAPABILITY } from '../../../src/shared/agent-session-permission-modes-capability' -import { structuredAgentSessionHostSupport } from './mobile-structured-agent-session-host-support' - -describe('structuredAgentSessionHostSupport', () => { - it('reads each structured-session feature from the host capability list', () => { - const none = { - coherentModelCatalog: false, - promptCancel: false, - questionAnswers: false, - queuedMessages: false, - queuedCommands: false, - queuedMessageEdit: false, - queuedMessageImageEdit: false, - quietRepeatedStop: false, - statusFeed: false, - sendOptions: false, - conversationStop: false, - permissionModes: false, - permissionOwn: false, - itemDetail: false, - phoneAttachments: false - } - expect(structuredAgentSessionHostSupport([])).toEqual(none) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_COHERENT_MODEL_CATALOG_CAPABILITY]) - ).toEqual({ ...none, coherentModelCatalog: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_QUESTION_ANSWERS_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, questionAnswers: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_PROMPT_CANCEL_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, promptCancel: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_QUEUED_MESSAGES_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, queuedMessages: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_QUEUED_COMMANDS_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, queuedCommands: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_QUEUED_MESSAGE_EDIT_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, queuedMessageEdit: true }) - expect( - structuredAgentSessionHostSupport([ - AGENT_SESSION_QUEUED_MESSAGE_IMAGE_EDIT_RUNTIME_CAPABILITY - ]) - ).toEqual({ ...none, queuedMessageImageEdit: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_REPEATED_STOP_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, quietRepeatedStop: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_STATUS_FEED_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, statusFeed: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_SEND_OPTIONS_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, sendOptions: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_CONVERSATION_STOP_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, conversationStop: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_PERMISSION_MODES_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, permissionModes: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_PHONE_ATTACHMENTS_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, phoneAttachments: true }) - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_ITEM_DETAIL_RUNTIME_CAPABILITY]) - ).toEqual({ ...none, itemDetail: true }) - // A host with the store but from before phones could upload into it offers them nothing. - expect( - structuredAgentSessionHostSupport([AGENT_SESSION_ATTACHMENTS_RUNTIME_CAPABILITY]) - ).toEqual(none) - }) -}) diff --git a/mobile/src/session/native-chat/composer/use-mobile-native-chat-image-attachments.test.ts b/mobile/src/session/native-chat/composer/use-mobile-native-chat-image-attachments.test.ts index 2e408040bd1..f8adfe3f6a3 100644 --- a/mobile/src/session/native-chat/composer/use-mobile-native-chat-image-attachments.test.ts +++ b/mobile/src/session/native-chat/composer/use-mobile-native-chat-image-attachments.test.ts @@ -294,18 +294,6 @@ describe('useMobileNativeChatImageAttachments', () => { expect(hook!.attachments).toEqual([]) }) - it('delegates straight to baseSend when there are no attachments', async () => { - const client = makeClient([]) - const baseSend = vi.fn().mockResolvedValue('accepted') - mount(baseArgs({ client: client as unknown as RpcClient, baseSend })) - - await act(async () => { - await hook!.sendNativeChat('just text') - }) - expect(baseSend).toHaveBeenCalledWith(...textSend('just text')) - expect(client.calls).toHaveLength(0) - }) - it('keeps the chips and does not submit when the image paste is rejected', async () => { pick.mockResolvedValue([{ base64: 'AAAA', uri: 'file:///a.jpg' }]) const client = makeClient([ diff --git a/mobile/src/session/use-mobile-native-chat-controller.test.ts b/mobile/src/session/use-mobile-native-chat-controller.test.ts index 63375cdd20d..e98921c7dd9 100644 --- a/mobile/src/session/use-mobile-native-chat-controller.test.ts +++ b/mobile/src/session/use-mobile-native-chat-controller.test.ts @@ -11,7 +11,6 @@ const clearDraftForSend = vi.fn() const restoreRejectedDraft = vi.fn() const holdUnconfirmedSend = vi.fn() -// Mutable resolution/transcript doubles let launch-draft cases reuse the send-seam harness. const viewMode = { isTabChatView: (_tabId: string) => true } const sessionState = { messages: [] as unknown[], status: 'ready', transcriptLoading: false } const structuredSendWithOutcome = vi.fn() @@ -67,7 +66,6 @@ const structuredSessionState = { loadingEarlier: false, loadEarlier: vi.fn() } -const draftsArgs: Record[] = [] const promptsState = { permission: null as unknown, question: null as unknown, @@ -107,8 +105,7 @@ vi.mock('./use-mobile-structured-agent-session', () => ({ }) })) vi.mock('./use-mobile-native-chat-drafts', () => ({ - useMobileNativeChatDrafts: (args: Record) => { - draftsArgs.push(args) + useMobileNativeChatDrafts: () => { return { composerText: '', setComposerText: vi.fn(), @@ -245,10 +242,6 @@ describe('useMobileNativeChatController handleNativeChatSend', () => { controller = null }) - it('leaves structured prompt cancellation unavailable on the legacy bridge lane', () => { - expect(controller?.handleNativeChatCancelPrompt).toBeUndefined() - }) - it('clears an orphaned image paste before a question-card answer (#10228)', async () => { markMobileNativeChatInputStale('term-1') clientStub.sendRequest.mockResolvedValue({ @@ -317,19 +310,6 @@ describe('useMobileNativeChatController handleNativeChatSend', () => { expect(onSendResolved).not.toHaveBeenCalled() }) - it('threads the optimistic-echo image URIs into acceptSend on an accepted send', async () => { - sendWithOutcome.mockResolvedValue('accepted') - let accepted = false - await act(async () => { - accepted = await controller!.handleNativeChatSend('look', ['file:///a.jpg']) - }) - expect(accepted).toBe(true) - expect(acceptSend).toHaveBeenCalledWith(ORIGIN, 'look', ['file:///a.jpg']) - expect(controller!.nativeChatAcceptsImages).toBe(true) - expect(clearDraftForSend).toHaveBeenCalledWith(ORIGIN, 'look') - expect(restoreRejectedDraft).not.toHaveBeenCalled() - }) - it('routes structured agent-session sends away from terminal/nativeChat transports', async () => { await act(async () => { renderer?.update(createElement(Harness, structuredTab('codex'))) @@ -511,97 +491,6 @@ describe('useMobileNativeChatController handleNativeChatSend', () => { }) }) -describe('useMobileNativeChatController launch-draft wiring', () => { - let renderer: ReactTestRenderer | null = null - const clientStub = { sendRequest: vi.fn() } - - const chatTab = { - type: 'terminal', - id: 'tab-1', - title: 'Claude', - terminal: 'term-1', - launchAgent: 'claude', - launchDraft: 'https://github.com/o/r/issues/12', - launchDraftCreatedAt: 7, - isActive: true - } - - function Harness({ tab }: { tab: unknown }): null { - useMobileNativeChatController({ - client: clientStub as unknown as RpcClient, - connState: 'connected', - hostId: 'h', - worktreeId: 'w', - activeSessionTab: tab as never, - activeSessionTabId: 'tab-1', - activeHandleRef: { current: 'term-1' }, - deviceTokenRef: { current: null }, - nativeChatTranscriptIsLocalReadable: true, - nativeChatInputLeaseReady: true, - onSendError: vi.fn(), - onSendResolved: vi.fn() - }) - return null - } - - function render(tab: unknown): void { - act(() => { - renderer = create(createElement(Harness, { tab })) - }) - } - - beforeEach(() => { - draftsArgs.length = 0 - viewMode.isTabChatView = () => true - sessionState.messages = [] - sessionState.status = 'ready' - sessionState.transcriptLoading = false - }) - - afterEach(() => { - act(() => renderer?.unmount()) - renderer = null - }) - - it('forwards the tab launch draft and chat-active flag for a chat-resolved tab', () => { - render(chatTab) - - expect(draftsArgs.at(-1)).toMatchObject({ - tabId: 'tab-1', - launchDraft: 'https://github.com/o/r/issues/12', - launchDraftCreatedAt: 7, - chatActive: true, - transcriptLoading: false - }) - }) - - it('forwards the raw draft with chatActive false when the tab shows the terminal', () => { - // Keep off-chat distinct from host retraction so toggling cannot permanently decline launch prefill. - viewMode.isTabChatView = () => false - render(chatTab) - - expect(draftsArgs.at(-1)).toMatchObject({ - launchDraft: 'https://github.com/o/r/issues/12', - chatActive: false - }) - }) - - it('forwards the session hook’s transcriptLoading, not its status', () => { - // Working status masks loading; only read-phase state establishes transcript trust. - sessionState.status = 'working' - sessionState.transcriptLoading = true - render(chatTab) - - expect(draftsArgs.at(-1)).toMatchObject({ transcriptLoading: true }) - }) - - it('forwards a null draft for a tab that publishes none', () => { - render({ ...chatTab, launchDraft: undefined }) - - expect(draftsArgs.at(-1)).toMatchObject({ launchDraft: null, chatActive: true }) - }) -}) - describe('useMobileNativeChatController ask dismissal across a transcript reload', () => { let renderer: ReactTestRenderer | null = null let controller: MobileNativeChatController | null = null diff --git a/mobile/src/session/use-mobile-native-chat-message-send.test.ts b/mobile/src/session/use-mobile-native-chat-message-send.test.ts index f8d76d91d17..caae4e05282 100644 --- a/mobile/src/session/use-mobile-native-chat-message-send.test.ts +++ b/mobile/src/session/use-mobile-native-chat-message-send.test.ts @@ -107,14 +107,6 @@ describe('useMobileNativeChatMessageSend', () => { api = null }) - it('sizes the pre-clear to every line of a parked launch draft', async () => { - mount(() => ({ text: DRAFT, createdAt: 1 })) - await act(async () => { - await api!.send('hello') - }) - expect(clearArgs().clearInput).toBe(buildAgentTuiClearInputForText(DRAFT)) - }) - it('issues the burst as its OWN write, before the body', async () => { mount(() => ({ text: DRAFT, createdAt: 1 })) await act(async () => { @@ -204,15 +196,6 @@ describe('useMobileNativeChatMessageSend', () => { expect(sentArgs().resolvedLaunchDraft).toBeUndefined() }) - it('creates an optimistic echo for an ordinary chat send', async () => { - mount(() => null) - await act(async () => { - await api!.send('hello') - }) - expect(acceptSend).toHaveBeenCalledTimes(1) - expect(onCommandSend).not.toHaveBeenCalled() - }) - // TUI commands never echo as user turns; optimistic bubbles would remain queued forever. it('never creates an optimistic echo for a catalog command send', async () => { mount(() => null) diff --git a/mobile/src/session/use-mobile-native-chat-session-options.test.ts b/mobile/src/session/use-mobile-native-chat-session-options.test.ts index 5b0ea34c9a9..cbadc0c3e78 100644 --- a/mobile/src/session/use-mobile-native-chat-session-options.test.ts +++ b/mobile/src/session/use-mobile-native-chat-session-options.test.ts @@ -57,22 +57,6 @@ describe('useMobileNativeChatSessionOptions', () => { api = null }) - it('serves the shared catalog snapshot for the agent', () => { - mount() - expect(api!.snapshot[0]).toMatchObject({ id: 'model', category: 'model' }) - expect(api!.snapshot[0]!.kind).toMatchObject({ type: 'select' }) - }) - - it('returns an empty snapshot for agents without a catalog', () => { - mount({ agent: 'amp' }) - expect(api!.snapshot).toEqual([]) - }) - - it('does not expose catalog-backed agents outside the Claude and Codex scope', () => { - mount({ agent: 'gemini' }) - expect(api!.snapshot).toEqual([]) - }) - it('shows an OMP session under the model its hook reported', () => { mount({ agent: 'omp' }) expect(api!.snapshot).toEqual([]) diff --git a/mobile/src/session/use-mobile-native-chat-stop.test.ts b/mobile/src/session/use-mobile-native-chat-stop.test.ts index 18455f41f07..c6539e236e4 100644 --- a/mobile/src/session/use-mobile-native-chat-stop.test.ts +++ b/mobile/src/session/use-mobile-native-chat-stop.test.ts @@ -3,7 +3,7 @@ import { act, create, type ReactTestRenderer } from 'react-test-renderer' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import type { RpcClient } from '../transport/rpc-client' import { markRpcDeliveryUnknown } from '../transport/rpc-delivery-ambiguity' -import { MOBILE_NATIVE_CHAT_SEND_TIMEOUT_MS } from './native-chat/mobile-native-chat-send' + import { useMobileNativeChatStop } from './use-mobile-native-chat-stop' const reportWorkerTerminalUserInput = vi.fn() @@ -157,21 +157,6 @@ describe('useMobileNativeChatStop', () => { expect(onSendError).not.toHaveBeenCalled() }) - it('bounds the Escape on a reconnect wait instead of parking forever', async () => { - await render(true, 'stream-1') - - act(() => stop?.()) - - expect(sendRequest).toHaveBeenCalledWith( - 'terminal.send', - expect.anything(), - expect.objectContaining({ - timeoutMs: MOBILE_NATIVE_CHAT_SEND_TIMEOUT_MS, - budgetSpansConnect: true - }) - ) - }) - it('suppresses an older Stop verdict after a newer Stop succeeds', async () => { let rejectFirst!: (error: Error) => void const first = new Promise((_, reject) => { diff --git a/mobile/src/session/use-mobile-structured-agent-session-send.test.tsx b/mobile/src/session/use-mobile-structured-agent-session-send.test.tsx index 28121a38153..23ae08f9da4 100644 --- a/mobile/src/session/use-mobile-structured-agent-session-send.test.tsx +++ b/mobile/src/session/use-mobile-structured-agent-session-send.test.tsx @@ -534,21 +534,6 @@ describe('mobile structured send actions', () => { expect(new Set(sentIds()).size).toBe(2) }) - it('never reads an old phone journal, even when storage is full or unreadable', async () => { - asyncStorage.getItem.mockRejectedValue(new Error('unreadable old journal')) - asyncStorage.setItem.mockRejectedValue(new Error('disk full')) - sendRequest.mockImplementation(async (method) => - method === 'agentSession.send' ? sendResult('accepted') : ok({ models: [], current: {} }) - ) - await mountSession() - await act(async () => { - expect(await hook!.sendWithOutcome('new action')).toBe('accepted') - }) - expect(asyncStorage.getItem).not.toHaveBeenCalled() - expect(asyncStorage.setItem).not.toHaveBeenCalled() - expect(onSendError).not.toHaveBeenCalled() - }) - it('sends nothing once the action budget expires', async () => { await mountSession() await act(async () => { diff --git a/mobile/src/test-support/bridged-parity/c5-page-closure.test.ts b/mobile/src/test-support/bridged-parity/c5-page-closure.test.ts index 0b703448cca..84ab32b1292 100644 --- a/mobile/src/test-support/bridged-parity/c5-page-closure.test.ts +++ b/mobile/src/test-support/bridged-parity/c5-page-closure.test.ts @@ -1,18 +1,6 @@ -import { readdirSync } from 'node:fs' -import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { C5_PAGE_CLOSURE } from './c5-page-closure' -import { - pageClosureDrift, - pageClosureExclusions, - pageClosureTotals, - type PageClosureObservation -} from './page-closure' -import { C1_PAGE_CLOSURE } from './c1-page-closure' -import { BRIDGED_PARITY_EXCLUSIONS } from './divergence-classes' -import { readGolden } from '../rpc-recording/golden-recording' - -const GOLDENS = resolve(import.meta.dirname, '../../../rpc-foundation/goldens') +import { pageClosureDrift, type PageClosureObservation } from './page-closure' function asPinned(): Map { const run = new Map() @@ -24,89 +12,7 @@ function asPinned(): Map { return run } -describe('the C5 page closure', () => { - it('assigns each pinned golden to one closure family', () => { - const goldens = Object.values(C5_PAGE_CLOSURE).flatMap((family) => Object.keys(family)) - expect(new Set(goldens).size).toBe(goldens.length) - }) - - // Assert class totals beside per-id pins; a self-consistent misderived table can satisfy each pin while losing wrapped entries. - it('pins how many goldens land in each class, which a per-id walk cannot see move', () => { - expect(pageClosureTotals(C5_PAGE_CLOSURE)).toEqual({ - identical: 61, - 'result-absent-settlement': 49, - 'params-undefined': 7, - 'result-absent-stream-release': 3, - 'write-ordinal': 7 - }) - }) - - it("inherits C1's families whole, with the verdicts C1 committed", () => { - // C5 inlines its pins, so compare imported C1 directly; composed spread tables need source parsing to detect overwritten inherited entries. - for (const [family, pinned] of Object.entries(C1_PAGE_CLOSURE)) { - expect(C5_PAGE_CLOSURE[family], family).toEqual(pinned) - } - expect(Object.keys(C1_PAGE_CLOSURE).length).toBe(20) - }) - - it('adds five families and nothing else, all of them AI Vault', () => { - const added = Object.keys(C5_PAGE_CLOSURE).filter((family) => !(family in C1_PAGE_CLOSURE)) - expect(added.sort()).toEqual([ - 'aiVault.history', - 'aiVault.history-screen', - 'aiVault.resume-launch', - 'aiVault.resume-preparation', - 'settings.resume-metadata' - ]) - }) - - it('keeps byte-identical controls outside History and strict ordinal controls within it', () => { - const added = Object.entries(C5_PAGE_CLOSURE).filter(([family]) => !(family in C1_PAGE_CLOSURE)) - const wholly = added - .filter(([, pins]) => !Object.values(pins).includes('identical')) - .map(([family]) => family) - expect(wholly.sort()).toEqual(['aiVault.history', 'aiVault.history-screen']) - for (const family of wholly) { - expect(Object.values(C5_PAGE_CLOSURE[family] ?? {})).toContain('write-ordinal') - } - }) - - it('pins goldens that exist, in the family the corpus records them under', () => { - for (const [family, goldens] of Object.entries(C5_PAGE_CLOSURE)) { - for (const id of Object.keys(goldens)) { - // Use the corpus decoder instead of inventing another golden-shape check. - const recorded = readGolden(GOLDENS, id) - expect({ id, family: recorded.family }).toEqual({ id, family }) - } - } - }) - - it('claims no golden the corpus does not have', () => { - const corpus = new Set( - readdirSync(GOLDENS) - .filter((name) => name.endsWith('.json')) - .map((name) => name.replace(/\.json$/, '')) - ) - const missing = Object.values(C5_PAGE_CLOSURE) - .flatMap((family) => Object.keys(family)) - .filter((id) => !corpus.has(id)) - expect(missing).toEqual([]) - }) - - it('excludes a closure golden only into a class that has a reason', () => { - const exclusions = pageClosureExclusions(C5_PAGE_CLOSURE) - expect(exclusions.length).toBe(66) - expect(exclusions.filter(([, name]) => BRIDGED_PARITY_EXCLUSIONS[name] === undefined)).toEqual( - [] - ) - }) -}) - describe('reading a run against the C5 pin', () => { - it('says nothing when the run is the pin', () => { - expect(pageClosureDrift(C5_PAGE_CLOSURE, asPinned())).toEqual([]) - }) - it('names a closure golden that changed verdict', () => { const run = asPinned() const found = [...run].find(([, seen]) => seen.verdict !== 'params-undefined') diff --git a/mobile/src/test-support/bridged-parity/divergence-classes.test.ts b/mobile/src/test-support/bridged-parity/divergence-classes.test.ts index c04f3f98a1a..006054b3fac 100644 --- a/mobile/src/test-support/bridged-parity/divergence-classes.test.ts +++ b/mobile/src/test-support/bridged-parity/divergence-classes.test.ts @@ -1,14 +1,10 @@ -import { readdirSync } from 'node:fs' -import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { bridgedParityMembershipDrift, bridgedParityTallyDrift, classifyBridgedParity, BRIDGED_PARITY_BASELINE, - BRIDGED_PARITY_EXCLUSIONS, BRIDGED_PARITY_MEMBERS, - BRIDGED_PARITY_NAMEABLE, type BridgedParityClass, type BridgedParityEvidence, type BridgedParityTally @@ -142,35 +138,6 @@ describe('what the pin still admits', () => { (name): name is BridgedParityClass => name !== 'identical' ) - it('gives every class it still counts a reason, and every closed one none', () => { - const reasoned = classes.filter((name) => BRIDGED_PARITY_EXCLUSIONS[name] !== undefined) - const counted = classes.filter((name) => BRIDGED_PARITY_BASELINE[name] > 0) - expect([...reasoned].sort()).toEqual([...counted].sort()) - }) - - it('accounts for every golden in the corpus, once each', () => { - // Pin the class sum to corpus size so a partial run cannot satisfy per-class expectations. - const goldens = readdirSync(resolve(import.meta.dirname, '../../../rpc-foundation/goldens')) - const counted = Object.values(BRIDGED_PARITY_BASELINE).reduce((sum, count) => sum + count, 0) - expect({ counted }).toEqual({ - counted: goldens.filter((name) => name.endsWith('.json')).length - }) - }) - - it('names the goldens in a class small enough to name, and as many as it counts', () => { - const nameable = classes.filter( - (name) => - BRIDGED_PARITY_BASELINE[name] > 0 && - BRIDGED_PARITY_BASELINE[name] <= BRIDGED_PARITY_NAMEABLE - ) - expect(nameable.length).toBeGreaterThan(0) - for (const name of nameable) { - const pinned = BRIDGED_PARITY_MEMBERS[name] ?? [] - expect({ [name]: pinned.length }).toEqual({ [name]: BRIDGED_PARITY_BASELINE[name] }) - expect({ [name]: new Set(pinned).size }).toEqual({ [name]: pinned.length }) - } - }) - function asPinned(): Map { const run = new Map() for (const name of classes) { @@ -216,10 +183,6 @@ describe('what the pin still admits', () => { return { identical: BRIDGED_PARITY_BASELINE.identical, counts } } - it('says nothing about the run the numbers were taken from', () => { - expect(bridgedParityTallyDrift(asCounted())).toEqual([]) - }) - it('goes red on a golden that stopped diverging, which every other check lets through', () => { // Excluded-to-identical moves leave broad parity gates satisfied; exact tallies must detect that direction too. const tally = asCounted() @@ -250,9 +213,4 @@ describe('what the pin still admits', () => { `identical: pinned ${tally.identical}, ran ${tally.identical - 1}` ]) }) - - it('leaves nothing for the reader to close: the `_meta` class is zero', () => { - expect(BRIDGED_PARITY_BASELINE['reply-meta-required']).toBe(0) - expect(BRIDGED_PARITY_EXCLUSIONS['reply-meta-required']).toBeUndefined() - }) }) diff --git a/mobile/src/test-support/bridged-parity/divergence-evidence.test.ts b/mobile/src/test-support/bridged-parity/divergence-evidence.test.ts index 39bfe3831e9..ab7ed9fe0d2 100644 --- a/mobile/src/test-support/bridged-parity/divergence-evidence.test.ts +++ b/mobile/src/test-support/bridged-parity/divergence-evidence.test.ts @@ -366,10 +366,6 @@ describe('the fields that diverged', () => { }) ).toEqual(['checkpoints']) }) - - it('is empty when the two agree', () => { - expect(divergingFields(recording({}), recording({}))).toEqual([]) - }) }) describe('reading the scenario', () => { diff --git a/src/main/claude-usage/transcript-record-parser-prefilter.test.ts b/src/main/claude-usage/transcript-record-parser-prefilter.test.ts index 992b4ba8fd3..7d7c514b36f 100644 --- a/src/main/claude-usage/transcript-record-parser-prefilter.test.ts +++ b/src/main/claude-usage/transcript-record-parser-prefilter.test.ts @@ -1,32 +1,7 @@ import { describe, expect, it } from 'vitest' import { parseClaudeUsageRecord } from './transcript-record-parser' -function assistantLine(overrides: Record = {}): string { - return JSON.stringify({ - type: 'assistant', - sessionId: 'session-1', - timestamp: '2026-01-01T00:00:00.000Z', - message: { usage: { input_tokens: 3, output_tokens: 5 } }, - ...overrides - }) -} - describe('assistant-record prefilter', () => { - it('still parses an ordinary assistant record', () => { - expect(parseClaudeUsageRecord(assistantLine())?.inputTokens).toBe(3) - }) - - it('rejects a user record that never mentions assistant', () => { - const userLine = JSON.stringify({ - type: 'user', - sessionId: 'session-1', - timestamp: '2026-01-01T00:00:00.000Z', - message: { content: 'x'.repeat(200) } - }) - - expect(parseClaudeUsageRecord(userLine)).toBeNull() - }) - it('rejects a non-assistant record that happens to contain the word assistant', () => { const userLine = JSON.stringify({ type: 'user', diff --git a/src/main/computer/computer-provider-unavailable-message.test.ts b/src/main/computer/computer-provider-unavailable-message.test.ts deleted file mode 100644 index 4cd4710ea22..00000000000 --- a/src/main/computer/computer-provider-unavailable-message.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { computerProviderUnavailableMessage } from './computer-provider-unavailable-message' - -describe('computerProviderUnavailableMessage', () => { - it('gives macOS developers the helper build and restart step', () => { - expect(computerProviderUnavailableMessage('darwin')).toContain( - 'run pnpm build:computer-macos and restart Orca from this worktree' - ) - expect(computerProviderUnavailableMessage('darwin')).toContain( - 'Orca Computer Use.app was not found or this macOS version is unsupported' - ) - }) - - it('names the runtime file a Linux or Windows install is missing', () => { - expect(computerProviderUnavailableMessage('linux')).toContain('computer-use-linux/runtime.py') - expect(computerProviderUnavailableMessage('win32')).toContain( - 'computer-use-windows/runtime.ps1' - ) - }) - - it('keeps unsupported platforms explicit', () => { - expect(computerProviderUnavailableMessage('freebsd')).toBe( - 'computer-use has no native provider for freebsd' - ) - }) -}) diff --git a/src/main/daemon/daemon-restart-state.test.ts b/src/main/daemon/daemon-restart-state.test.ts index f9280702050..66d9453662b 100644 --- a/src/main/daemon/daemon-restart-state.test.ts +++ b/src/main/daemon/daemon-restart-state.test.ts @@ -2,10 +2,6 @@ import { describe, expect, it } from 'vitest' import { runCoalescedDaemonRestart, settledDaemonRestart } from './daemon-restart-state' describe('settledDaemonRestart', () => { - it('is undefined with no restart running', () => { - expect(settledDaemonRestart()).toBeUndefined() - }) - it('holds until the running restart settles, whether it succeeds or fails', async () => { for (const outcome of ['resolve', 'reject'] as const) { let finish!: () => void diff --git a/src/main/dock/unread-badge.test.ts b/src/main/dock/unread-badge.test.ts deleted file mode 100644 index a997a214cd2..00000000000 --- a/src/main/dock/unread-badge.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' - -const { setBadgeMock } = vi.hoisted(() => ({ - setBadgeMock: vi.fn() -})) - -vi.mock('electron', () => ({ - app: { - dock: { - setBadge: setBadgeMock - } - } -})) - -describe('unread Dock badge', () => { - const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform') - - afterEach(() => { - if (originalPlatform) { - Object.defineProperty(process, 'platform', originalPlatform) - } - setBadgeMock.mockReset() - vi.resetModules() - }) - - it('clears the native badge when unread count is zero', async () => { - Object.defineProperty(process, 'platform', { configurable: true, value: 'darwin' }) - const { setUnreadDockBadgeCount } = await import('./unread-badge') - - setUnreadDockBadgeCount(5) - expect(setBadgeMock).toHaveBeenLastCalledWith('5') - - setUnreadDockBadgeCount(0) - expect(setBadgeMock).toHaveBeenLastCalledWith('') - }) - - it('caps unread counts', async () => { - Object.defineProperty(process, 'platform', { configurable: true, value: 'darwin' }) - const { setUnreadDockBadgeCount } = await import('./unread-badge') - - setUnreadDockBadgeCount(104) - expect(setBadgeMock).toHaveBeenLastCalledWith('99+') - }) -}) diff --git a/src/main/git/command-runner/git-command-timeout.test.ts b/src/main/git/command-runner/git-command-timeout.test.ts index f5361532176..59ac198530a 100644 --- a/src/main/git/command-runner/git-command-timeout.test.ts +++ b/src/main/git/command-runner/git-command-timeout.test.ts @@ -17,10 +17,6 @@ describe('gitCommandTimeoutMs', () => { expect(gitCommandTimeoutMs(['status'], 7)).toBe(7) expect(gitCommandTimeoutMs(['fetch'], 7)).toBe(7) }) - - it('provides a deterministic read-timeout seam', () => { - expect(gitCommandTimeoutMs(['status'], undefined, 25)).toBe(25) - }) }) describe('GitCommandTimeoutError', () => { diff --git a/src/main/hang-watchdog/hang-watchdog-worker-path.test.ts b/src/main/hang-watchdog/hang-watchdog-worker-path.test.ts deleted file mode 100644 index 3ade5b1cbf3..00000000000 --- a/src/main/hang-watchdog/hang-watchdog-worker-path.test.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { join } from 'node:path' -import { describe, expect, it, vi } from 'vitest' -import { resolveHangWatchdogWorkerPath } from './hang-watchdog-worker-path' - -describe('resolveHangWatchdogWorkerPath', () => { - it('resolves packaged workers inside app.asar', () => { - const appPath = join('/apps', 'orca', 'app.asar') - expect(resolveHangWatchdogWorkerPath(appPath, true)).toBe( - join(appPath, 'out', 'main', 'main-thread-hang-watchdog-entry.js') - ) - }) - - it('uses an adjacent entry when the dev app path is out/main', () => { - const appPath = join('/repo', 'out', 'main') - const adjacent = join(appPath, 'main-thread-hang-watchdog-entry.js') - const pathExists = vi.fn((candidate: string) => candidate === adjacent) - expect(resolveHangWatchdogWorkerPath(appPath, false, pathExists)).toBe(adjacent) - }) - - it('resolves through out/main from a dev project root', () => { - const appPath = join('/repo', 'orca') - expect(resolveHangWatchdogWorkerPath(appPath, false, () => false)).toBe( - join(appPath, 'out', 'main', 'main-thread-hang-watchdog-entry.js') - ) - }) -}) diff --git a/src/main/hang-watchdog/main-thread-hang-telemetry.test.ts b/src/main/hang-watchdog/main-thread-hang-telemetry.test.ts index c49a80d22b0..ab31805a059 100644 --- a/src/main/hang-watchdog/main-thread-hang-telemetry.test.ts +++ b/src/main/hang-watchdog/main-thread-hang-telemetry.test.ts @@ -2,24 +2,6 @@ import { describe, expect, it } from 'vitest' import { eventSchemas } from '../../shared/telemetry-events' describe('main_thread_hang_detected telemetry schema', () => { - it('accepts an unresolved hang', () => { - expect( - eventSchemas.main_thread_hang_detected.safeParse({ - unresponsive_ms: 50_000, - self_recovered: false - }).success - ).toBe(true) - }) - - it('accepts a self-recovered stall', () => { - expect( - eventSchemas.main_thread_hang_detected.safeParse({ - unresponsive_ms: 61_000, - self_recovered: true - }).success - ).toBe(true) - }) - // Strict schema excludes paths, PIDs and window titles from telemetry. it('rejects unknown fields and non-integer durations', () => { expect( diff --git a/src/main/host/safe-storage-import-ratchet.test.ts b/src/main/host/safe-storage-import-ratchet.test.ts deleted file mode 100644 index 85bef05489b..00000000000 --- a/src/main/host/safe-storage-import-ratchet.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { readdirSync, readFileSync } from 'node:fs' -import { join, relative } from 'node:path' -import { describe, expect, it } from 'vitest' - -const MAIN_ROOT = join(__dirname, '..') -// Route keychain access through the run-wide guard so withheld keychains cannot block the main thread. -const ALLOWED = new Set(['host/safe-storage-availability.ts', 'host/electron-secret-store.ts']) - -function listSources(dir: string): string[] { - return readdirSync(dir, { withFileTypes: true }).flatMap((entry) => { - const path = join(dir, entry.name) - if (entry.isDirectory()) { - return listSources(path) - } - return entry.name.endsWith('.ts') && !entry.name.endsWith('.test.ts') ? [path] : [] - }) -} - -describe('electron.safeStorage importers', () => { - it('stay behind the keychain withhold', () => { - const importers = listSources(MAIN_ROOT) - .filter((path) => - /import\s*\{[^}]*\bsafeStorage\b[^}]*\}\s*from\s*'electron'/.test( - readFileSync(path, 'utf8') - ) - ) - .map((path) => relative(MAIN_ROOT, path).split('\\').join('/')) - expect(importers.filter((path) => !ALLOWED.has(path))).toEqual([]) - }) -}) diff --git a/src/main/ipc/deferred-emoji-shortcode-dataset.test.ts b/src/main/ipc/deferred-emoji-shortcode-dataset.test.ts deleted file mode 100644 index fe76c33eec9..00000000000 --- a/src/main/ipc/deferred-emoji-shortcode-dataset.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import emojiShortcodes from 'emojibase-data/en/shortcodes/emojibase.json' -import { requireEmojiShortcodeDataset } from './deferred-emoji-shortcode-dataset' - -// Keep main imports outside shared tsconfig projects; the lazy catalog test enforces that boundary. -describe('deferred emoji shortcode dataset', () => { - it('loads the main-side dataset synchronously into an identical catalog', async () => { - vi.resetModules() - const eager = await import('../../shared/emoji-shortcode-catalog.js') - eager.setEmojiShortcodeDatasetLoader(() => emojiShortcodes) - const eagerEntries = eager.getStandardEmojiShortcodeEntries() - const eagerTransform = eager.replaceKnownEmojiWithShortcodes('ship \u{1F389} \u{1F44D}') - - vi.resetModules() - const deferred = await import('../../shared/emoji-shortcode-catalog.js') - deferred.setEmojiShortcodeDatasetLoader(requireEmojiShortcodeDataset) - - // Immediate use must work without awaiting an async import. - expect(deferred.getStandardEmojiShortcodeEntries()).toEqual(eagerEntries) - expect(deferred.replaceKnownEmojiWithShortcodes('ship \u{1F389} \u{1F44D}')).toBe( - eagerTransform - ) - }) -}) diff --git a/src/main/ipc/freebuff-detection.test.ts b/src/main/ipc/freebuff-detection.test.ts deleted file mode 100644 index 2bc6d1cd7dc..00000000000 --- a/src/main/ipc/freebuff-detection.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - getTuiAgentDetectionProbeCommands, - KNOWN_TUI_AGENT_DETECTION_COMMANDS, - resolveDetectedTuiAgentIds -} from '../../shared/tui-agent-detection-commands' - -describe('Freebuff detection', () => { - it.each(['darwin', 'linux', 'win32', 'wsl'] as const)( - 'detects Freebuff independently of Codebuff on %s', - (runtime) => { - expect( - getTuiAgentDetectionProbeCommands(KNOWN_TUI_AGENT_DETECTION_COMMANDS, runtime) - ).toContain('freebuff') - expect( - resolveDetectedTuiAgentIds( - KNOWN_TUI_AGENT_DETECTION_COMMANDS, - new Set(['freebuff']), - runtime - ) - ).toEqual(['freebuff']) - expect( - resolveDetectedTuiAgentIds( - KNOWN_TUI_AGENT_DETECTION_COMMANDS, - new Set(['codebuff']), - runtime - ) - ).toEqual(['codebuff']) - expect( - resolveDetectedTuiAgentIds( - KNOWN_TUI_AGENT_DETECTION_COMMANDS, - new Set(['freebuff', 'codebuff']), - runtime - ) - ).toEqual(expect.arrayContaining(['freebuff', 'codebuff'])) - } - ) -}) diff --git a/src/main/ipc/runtime-environments/runtime-environment-control-socket-close-trace.test.ts b/src/main/ipc/runtime-environments/runtime-environment-control-socket-close-trace.test.ts deleted file mode 100644 index 5a600c07b6c..00000000000 --- a/src/main/ipc/runtime-environments/runtime-environment-control-socket-close-trace.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { afterEach, expect, it } from 'vitest' -import { setActiveSink } from '../../observability/tracer' -import { sharedControlEnvironmentPolicy } from './runtime-environment-shared-control-policy' - -afterEach(() => setActiveSink(null)) - -it('traces each control socket close for the support bundle', () => { - const records: unknown[] = [] - setActiveSink({ push: (record) => records.push(record), flush() {}, close() {} }) - - sharedControlEnvironmentPolicy('env-1').onSocketClosed?.({ - cause: 'keepalive_timeout', - errorCode: 'remote_runtime_unavailable', - closeCode: null, - state: 'ready', - lastRttMs: 320, - socketUptimeMs: 60_000, - readyUptimeMs: 59_000, - reconnectAttempt: 0, - pendingRequestCount: 1, - subscriptionCount: 4 - }) - - expect(records).toEqual([ - expect.objectContaining({ - type: 'effect-span', - name: 'remote-runtime.control-socket-close', - attributes: expect.objectContaining({ - environmentId: 'env-1', - cause: 'keepalive_timeout', - lastRttMs: 320, - socketUptimeMs: 60_000 - }) - }) - ]) -}) diff --git a/src/main/ipc/runtime-environments/runtime-environment-recovery-handler.test.ts b/src/main/ipc/runtime-environments/runtime-environment-recovery-handler.test.ts deleted file mode 100644 index ecd1497133f..00000000000 --- a/src/main/ipc/runtime-environments/runtime-environment-recovery-handler.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' - -const handlers = vi.hoisted(() => new Map unknown>()) -const retrySharedControl = vi.hoisted(() => vi.fn()) -const retrySsh = vi.hoisted(() => vi.fn()) - -vi.mock('electron', () => ({ - ipcMain: { - removeHandler: (channel: string) => handlers.delete(channel), - handle: (channel: string, handler: () => unknown) => handlers.set(channel, handler) - } -})) -vi.mock('./runtime-environment-request-connections', () => ({ - retryRemoteRuntimeSharedControlConnectionsNow: retrySharedControl -})) -vi.mock('../ssh/ssh-host-sleep-reconnect', () => ({ - retrySshConnectionsAfterNetworkReturn: retrySsh -})) - -import { registerRuntimeEnvironmentRecoveryHandler } from './runtime-environment-recovery-handler' - -describe('runtimeEnvironments:retryConnectionsNow', () => { - it('retries SSH transports as well as shared control when the window reports the network back', () => { - registerRuntimeEnvironmentRecoveryHandler() - handlers.get('runtimeEnvironments:retryConnectionsNow')?.() - expect(retrySharedControl).toHaveBeenCalledTimes(1) - expect(retrySsh).toHaveBeenCalledTimes(1) - }) -}) diff --git a/src/main/ipc/skill-install-progress-ipc.test.ts b/src/main/ipc/skill-install-progress-ipc.test.ts index f9ac04a5e11..3f2e942b79f 100644 --- a/src/main/ipc/skill-install-progress-ipc.test.ts +++ b/src/main/ipc/skill-install-progress-ipc.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it, vi } from 'vitest' import type { IpcMainInvokeEvent } from 'electron' -import { sendBundleInstallProgress, sendSkillInstallProgress } from './skill-install-progress-ipc' +import { sendSkillInstallProgress } from './skill-install-progress-ipc' function event(destroyed = false): IpcMainInvokeEvent { return { @@ -9,23 +9,6 @@ function event(destroyed = false): IpcMainInvokeEvent { } describe('skill install progress IPC', () => { - it('projects destination-owned bundle progress without paths or grants', () => { - const target = event() - sendBundleInstallProgress(target, { - operationId: 'operation_1', - skillId: 'alpha', - skillName: 'alpha', - skillIndex: 2, - skillCount: 30 - }) - - expect(target.sender.send).toHaveBeenCalledWith('skills:installProgress', { - operationId: 'operation_1', - phase: 'installing', - currentSkill: { id: 'alpha', name: 'alpha', index: 2, total: 30 } - }) - }) - it('does not publish after the invoking renderer is destroyed', () => { const target = event(true) sendSkillInstallProgress(target, { operationId: 'operation_1', phase: 'authorizing' }) diff --git a/src/main/ipc/worktree-watcher-removal-binding.test.ts b/src/main/ipc/worktree-watcher-removal-binding.test.ts deleted file mode 100644 index d96244dbf05..00000000000 --- a/src/main/ipc/worktree-watcher-removal-binding.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getWorktreeWatcherRemoval, setWorktreeWatcherRemoval } from './worktree-watcher-removal' - -/** The renderer-less default stays inert; installed ports route method calls. */ -describe('WorktreeWatcherRemoval port', () => { - const METHODS = ['closeLocal', 'restoreLocal', 'forgetLocal'] as const - - it('defaults to inert so a renderer-less host is honest, not broken', async () => { - setWorktreeWatcherRemoval(null) - const inert = getWorktreeWatcherRemoval() - for (const method of METHODS) { - await expect( - Promise.resolve(inert[method]('repo::/tmp/w', '/tmp/w' as never)) - ).resolves.not.toThrow() - } - }) - - it('routes every method to the installed binding', async () => { - const calls: string[] = [] - setWorktreeWatcherRemoval({ - closeLocal: async () => void calls.push('closeLocal'), - restoreLocal: async () => void calls.push('restoreLocal'), - forgetLocal: () => void calls.push('forgetLocal') - }) - for (const method of METHODS) { - await getWorktreeWatcherRemoval()[method]('conn', '/tmp/w' as never) - } - expect(calls).toEqual([...METHODS]) - setWorktreeWatcherRemoval(null) - }) -}) diff --git a/src/main/native-chat/agent-session-wire/json-string-shortening.test.ts b/src/main/native-chat/agent-session-wire/json-string-shortening.test.ts index d1c3d6bf695..578e889274f 100644 --- a/src/main/native-chat/agent-session-wire/json-string-shortening.test.ts +++ b/src/main/native-chat/agent-session-wire/json-string-shortening.test.ts @@ -1,11 +1,6 @@ import { expect, it } from 'vitest' import { jsonBytes, shortenJsonStringsToFit } from './json-string-shortening' -it('returns the value itself when it already fits', () => { - const value = { text: 'short' } - expect(shortenJsonStringsToFit(value, 1_000)).toBe(value) -}) - it('cuts long strings to fit and marks them, never splitting a surrogate pair', () => { const value = { text: '😀'.repeat(2_000), other: 'x'.repeat(4_000) } const fitted = shortenJsonStringsToFit(value, 2_000) diff --git a/src/main/opencode/opencode-status-plugin-startup-refresh.test.ts b/src/main/opencode/opencode-status-plugin-startup-refresh.test.ts deleted file mode 100644 index da588a3f689..00000000000 --- a/src/main/opencode/opencode-status-plugin-startup-refresh.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' - -const { refreshV1, refreshV2 } = vi.hoisted(() => ({ - refreshV1: vi.fn<() => void>(), - refreshV2: vi.fn<() => void>() -})) -vi.mock('./hook-service', () => ({ - openCodeHookService: { refreshInstalledPlugins: refreshV1 }, - openCode2HookService: { refreshInstalledPlugins: refreshV2 } -})) - -import { refreshInstalledOpenCodeStatusPlugins } from './opencode-status-plugin-startup-refresh' - -describe('refreshInstalledOpenCodeStatusPlugins', () => { - beforeEach(() => { - refreshV1.mockClear() - refreshV2.mockClear() - }) - - it('refreshes both variants by default', () => { - refreshInstalledOpenCodeStatusPlugins(null) - expect(refreshV1).toHaveBeenCalledTimes(1) - expect(refreshV2).toHaveBeenCalledTimes(1) - }) - - it('touches nothing while agent status hooks are off', () => { - refreshInstalledOpenCodeStatusPlugins({ agentStatusHooksEnabled: false }) - expect(refreshV1).not.toHaveBeenCalled() - expect(refreshV2).not.toHaveBeenCalled() - }) - - it('skips a disabled variant only', () => { - refreshInstalledOpenCodeStatusPlugins({ disabledTuiAgents: ['opencode2'] }) - expect(refreshV1).toHaveBeenCalledTimes(1) - expect(refreshV2).not.toHaveBeenCalled() - }) -}) diff --git a/src/main/provider-process/provider-process-launch.test.ts b/src/main/provider-process/provider-process-launch.test.ts index 0eb40592a50..50c4cb83f2e 100644 --- a/src/main/provider-process/provider-process-launch.test.ts +++ b/src/main/provider-process/provider-process-launch.test.ts @@ -15,13 +15,4 @@ describe('resolveProviderChildEnv', () => { expect(baseEnv).toEqual({ PATH: '/bin', AGENT_HOME: '/inherited', PARENT_AGENT: 'parent' }) expect(overlay.PARENT_AGENT).toBe('overlay') }) - - it('copies the inherited env when the launch carries no env', () => { - const baseEnv = { PATH: '/bin' } - - const childEnv = resolveProviderChildEnv({}, baseEnv) - - expect(childEnv).toEqual(baseEnv) - expect(childEnv).not.toBe(baseEnv) - }) }) diff --git a/src/main/pty/windows-path-registry-change.test.ts b/src/main/pty/windows-path-registry-change.test.ts index e6baee2cadf..1ce5f4e7da2 100644 --- a/src/main/pty/windows-path-registry-change.test.ts +++ b/src/main/pty/windows-path-registry-change.test.ts @@ -1,27 +1,7 @@ import { describe, expect, it, vi } from 'vitest' -import { - installWindowsPathRegistryChangeListener, - WINDOWS_SETTING_CHANGE_MESSAGE -} from './windows-path-registry-change' +import { installWindowsPathRegistryChangeListener } from './windows-path-registry-change' describe('installWindowsPathRegistryChangeListener', () => { - it('invalidates the persisted PATH cache on a Windows settings change', () => { - const hooks = new Map void>() - const invalidate = vi.fn() - installWindowsPathRegistryChangeListener( - { - hookWindowMessage: (message, callback) => { - hooks.set(message, callback) - } - }, - { invalidate, platform: 'win32' } - ) - - hooks.get(WINDOWS_SETTING_CHANGE_MESSAGE)?.(Buffer.alloc(0), Buffer.alloc(0)) - - expect(invalidate).toHaveBeenCalledOnce() - }) - it('does not hook native messages outside Windows', () => { const hookWindowMessage = vi.fn() diff --git a/src/main/ripgrep/bundled-ripgrep-stop.test.ts b/src/main/ripgrep/bundled-ripgrep-stop.test.ts deleted file mode 100644 index e2d6628956c..00000000000 --- a/src/main/ripgrep/bundled-ripgrep-stop.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import { spawnProcess } from '@orca/process-host' -import { stopBundledRipgrep } from './bundled-ripgrep-stop' - -const { signalTree, killChild } = vi.hoisted(() => ({ signalTree: vi.fn(), killChild: vi.fn() })) -vi.mock('@orca/process-host/process-tree-termination', () => ({ - signalProcessTree: signalTree -})) -vi.mock('../../shared/ripgrep-process-availability', () => ({ - killSpawnedRipgrepProcess: killChild -})) -afterEach(() => { - vi.restoreAllMocks() - vi.clearAllMocks() -}) - -describe('bundled search process termination', () => { - it('uses the existing bounded tree terminator for Windows WSL and coalesces duplicate stops', async () => { - const child = spawnProcess({ - program: process.execPath, - args: ['-e', 'setInterval(() => {}, 1000)'] - }) - const exited = new Promise((resolve) => child.once('close', resolve)) - try { - vi.spyOn(process, 'platform', 'get').mockReturnValue('win32') - signalTree.mockResolvedValue(true) - stopBundledRipgrep(child, true) - stopBundledRipgrep(child, true) - expect(signalTree).toHaveBeenCalledExactlyOnceWith(child) - expect(killChild).not.toHaveBeenCalled() - } finally { - child.kill() - await exited - } - }) -}) diff --git a/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.test.ts b/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.test.ts deleted file mode 100644 index fffda55e8ab..00000000000 --- a/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { ALL_RPC_METHODS } from '../rpc/methods' -import { MOBILE_RPC_METHOD_ALLOWLIST } from '../runtime-rpc/runtime-rpc-mobile-method-allowlist' -import { MOBILE_RPC_METHOD_ROUTES } from '../runtime-rpc/runtime-rpc-mobile-method-routing' -import { RELAYED_STREAM_CARRIERS } from './relayed-stream-carriers' - -describe('relayed stream carrier census', () => { - const relayableStreams: string[] = ALL_RPC_METHODS.filter( - (method) => - 'stream' in method && - MOBILE_RPC_METHOD_ALLOWLIST.has(method.name) && - MOBILE_RPC_METHOD_ROUTES.get(method.name) === 'execution-host' - ).map((method) => method.name) - - it('classifies how every relayable stream names itself', () => { - expect(relayableStreams.filter((name) => !RELAYED_STREAM_CARRIERS.has(name))).toEqual([]) - }) - - it('classifies nothing that is not a relayable stream', () => { - expect( - [...RELAYED_STREAM_CARRIERS.keys()].filter((name) => !relayableStreams.includes(name)) - ).toEqual([]) - }) -}) diff --git a/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.ts b/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.ts index b79a65a6114..21f3063c95e 100644 --- a/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.ts +++ b/src/main/runtime/mobile-desktop-relay/relayed-stream-carriers.ts @@ -1,5 +1,5 @@ /** terminal-stream-id renumbers result/header ids; none carries no id (one phone screencast at a time). - * Refuse phone-binary-frames because the relay cannot forward their input; census tests cover new streams. */ + * Refuse phone-binary-frames because the relay cannot forward their input. */ export type RelayedStreamCarrier = 'terminal-stream-id' | 'none' | 'phone-binary-frames' export const RELAYED_STREAM_CARRIERS: ReadonlyMap = new Map([ diff --git a/src/main/runtime/orca-runtime-tail-wait-memo.test.ts b/src/main/runtime/orca-runtime-tail-wait-memo.test.ts index 4ac28674dd8..a43de423155 100644 --- a/src/main/runtime/orca-runtime-tail-wait-memo.test.ts +++ b/src/main/runtime/orca-runtime-tail-wait-memo.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { computeTerminalTailWaitState } from './terminal-wait-tail-state' describe('terminal tail wait state', () => { @@ -19,19 +19,4 @@ describe('terminal tail wait state', () => { expect(blocked.fromTail).toBe(true) expect(blocked.signal?.reason).toBe('agent-update-prompt') }) - - it('does not rebuild or repeatedly scan an ordinary saturated tail', () => { - const lines = Array.from({ length: 2000 }, () => 'x'.repeat(126)) - const lastIndexOf = vi.spyOn(String.prototype, 'lastIndexOf') - - try { - const state = computeTerminalTailWaitState(lines, '', '') - - expect(state.signal).toBeNull() - expect(state.waitText).toBe('') - expect(lastIndexOf).not.toHaveBeenCalled() - } finally { - lastIndexOf.mockRestore() - } - }) }) diff --git a/src/main/runtime/rpc/methods/repo-badge-color.test.ts b/src/main/runtime/rpc/methods/repo-badge-color.test.ts deleted file mode 100644 index f641a90b933..00000000000 --- a/src/main/runtime/rpc/methods/repo-badge-color.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import '../unused-default-rpc-methods.test-fixture' -import { describe, expect, it, vi } from 'vitest' -import { RpcDispatcher } from '../dispatcher' -import type { RpcRequest } from '../core' -import type { OrcaRuntimeService } from '../../orca-runtime' -import { REPO_METHODS } from './repo' - -function makeRequest(method: string, params?: unknown): RpcRequest { - return { id: 'req-1', authToken: 'tok', method, params } -} - -describe('repo badge color RPC updates', () => { - it('normalizes repo badge colors before runtime updates', async () => { - const runtime = { - getRuntimeId: () => 'test-runtime', - updateRepo: vi.fn().mockResolvedValue({ - id: 'repo-1', - path: '/srv/repo', - badgeColor: '#abcdef' - }) - } as unknown as OrcaRuntimeService - const dispatcher = new RpcDispatcher({ runtime, methods: REPO_METHODS }) - - const response = await dispatcher.dispatch( - makeRequest('repo.update', { - repo: 'repo-1', - updates: { badgeColor: ' ABCDEF ' } - }) - ) - - expect(runtime.updateRepo).toHaveBeenCalledWith('repo-1', { - badgeColor: '#abcdef' - }) - expect(response).toMatchObject({ - ok: true, - result: { repo: { id: 'repo-1', badgeColor: '#abcdef' } } - }) - }) -}) diff --git a/src/main/runtime/runtime-rpc/runtime-rpc-mobile-method-routing.test.ts b/src/main/runtime/runtime-rpc/runtime-rpc-mobile-method-routing.test.ts index 1b758d9fa72..205cab94761 100644 --- a/src/main/runtime/runtime-rpc/runtime-rpc-mobile-method-routing.test.ts +++ b/src/main/runtime/runtime-rpc/runtime-rpc-mobile-method-routing.test.ts @@ -1,17 +1,7 @@ import { describe, expect, it } from 'vitest' -import { - EXECUTION_HOST_METHODS, - MOBILE_RPC_METHOD_ROUTES -} from './runtime-rpc-mobile-method-routing' -import { PAIRED_DESKTOP_METHODS } from './runtime-rpc-mobile-paired-desktop-methods' +import { MOBILE_RPC_METHOD_ROUTES } from './runtime-rpc-mobile-method-routing' describe('mobile RPC method routing census', () => { - it('tags every routed method exactly once', () => { - expect(PAIRED_DESKTOP_METHODS.length + EXECUTION_HOST_METHODS.length).toBe( - MOBILE_RPC_METHOD_ROUTES.size - ) - }) - it.each([ 'jira.status', 'jira.listIssues', diff --git a/src/main/runtime/structured-agent-runtime-registration-identity.test.ts b/src/main/runtime/structured-agent-runtime-registration-identity.test.ts deleted file mode 100644 index 1a52e0cc743..00000000000 --- a/src/main/runtime/structured-agent-runtime-registration-identity.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { expect, it } from 'vitest' -import { PI_RPC_RUNTIME_REGISTRATION } from '../pi/rpc-runtime-registration' -import { - STRUCTURED_AGENT_RUNTIME_METADATA, - structuredAgentRuntimeMetadata -} from './structured-agent-runtime-metadata' -import { - STRUCTURED_AGENT_RUNTIME_REGISTRATIONS, - structuredAgentRuntimeRegistration -} from './structured-agent-runtime-registrations' - -it.each( - STRUCTURED_AGENT_RUNTIME_METADATA.map( - (metadata, index) => [metadata.definition.agent, metadata, index] as const - ) -)( - 'keeps the metadata and synchronous factory on the same %s registration', - (agent, metadata, index) => { - const registration = STRUCTURED_AGENT_RUNTIME_REGISTRATIONS[index] - expect(registration).toBe(metadata) - expect(structuredAgentRuntimeRegistration(agent)).toBe(registration) - expect(structuredAgentRuntimeMetadata(agent)).toBe(registration) - expect(typeof registration.createAdapter).toBe('function') - expect(structuredAgentRuntimeRegistration(agent)?.createAdapter).toBe( - registration.createAdapter - ) - } -) - -it('keeps the standalone Pi registration in the shared roster', () => { - expect(structuredAgentRuntimeRegistration('pi')).toBe(PI_RPC_RUNTIME_REGISTRATION) -}) diff --git a/src/main/speech/speech-model-download-response.test.ts b/src/main/speech/speech-model-download-response.test.ts index 19e312cab66..bd3653bfd11 100644 --- a/src/main/speech/speech-model-download-response.test.ts +++ b/src/main/speech/speech-model-download-response.test.ts @@ -1,6 +1,5 @@ import { describe, expect, it } from 'vitest' import { parseContentRange, parseRetryAfterMs } from './speech-model-download-response' -import { isRetryableDownloadError } from '../network/transient-download-error' describe('speech model download response contracts', () => { it('accepts only internally consistent byte ranges', () => { @@ -15,12 +14,4 @@ describe('speech model download response contracts', () => { expect(parseRetryAfterMs(String(Number.MAX_SAFE_INTEGER))).toBeUndefined() expect(parseRetryAfterMs('invalid')).toBeUndefined() }) - - it('retries only allowlisted HTTP and network failures', () => { - expect( - isRetryableDownloadError(Object.assign(new Error('HTTP 503'), { httpStatusCode: 503 })) - ).toBe(true) - expect(isRetryableDownloadError(new Error('net::ERR_CONNECTION_RESET'))).toBe(true) - expect(isRetryableDownloadError(new Error('certificate rejected'))).toBe(false) - }) }) diff --git a/src/main/sqlite/node-sqlite-reader-api.test.ts b/src/main/sqlite/node-sqlite-reader-api.test.ts index 5818457684c..24e2f93ddb6 100644 --- a/src/main/sqlite/node-sqlite-reader-api.test.ts +++ b/src/main/sqlite/node-sqlite-reader-api.test.ts @@ -21,10 +21,4 @@ describe('node:sqlite reader admission', () => { expect(hasNodeSqliteReaderApi(sqlite)).toBe(admitted) expect(probe(sqlite)).toBe(admitted) }) - - it('admits the actual runtime module', () => { - const sqlite: unknown = process.getBuiltinModule('node:sqlite') - expect(hasNodeSqliteReaderApi(sqlite)).toBe(true) - expect(probe(sqlite)).toBe(true) - }) }) diff --git a/src/main/ssh/relay-install-artifacts.test.ts b/src/main/ssh/relay-install-artifacts.test.ts deleted file mode 100644 index 345eb8bd9a1..00000000000 --- a/src/main/ssh/relay-install-artifacts.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { ORCAD_WINDOWS_PROCESS_TREE_FILENAME } from '../../shared/orcad-artifacts' -import { relayArtifactFilenames } from './relay-install-artifacts' - -describe('relay install artifacts', () => { - it('keeps the optional process-table addon out of the required set', () => { - // A complete install never had to contain it: only a Windows build machine could emit it. - expect(relayArtifactFilenames(true)).not.toContain(ORCAD_WINDOWS_PROCESS_TREE_FILENAME) - expect(relayArtifactFilenames(false)).not.toContain(ORCAD_WINDOWS_PROCESS_TREE_FILENAME) - }) - - it('requires the Windows-only patches only on Windows', () => { - expect(relayArtifactFilenames(true)).toContain('relay.js') - expect(relayArtifactFilenames(true)).toContain('node-pty-1.1.0-console-list-agent-patch.cjs') - expect(relayArtifactFilenames(false)).not.toContain( - 'node-pty-1.1.0-console-list-agent-patch.cjs' - ) - }) - - it('lists the pty-master cloexec patch on every platform', () => { - for (const isWindows of [true, false]) { - expect(relayArtifactFilenames(isWindows)).toContain('node-pty-1.1.0-master-cloexec-patch.cjs') - } - }) -}) diff --git a/src/main/worker-thread-entry-path.test.ts b/src/main/worker-thread-entry-path.test.ts deleted file mode 100644 index 9faba9567eb..00000000000 --- a/src/main/worker-thread-entry-path.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { join } from 'node:path' -import { describe, expect, it } from 'vitest' -import { currentWorkerEntryLayout, resolveWorkerThreadEntryPath } from './worker-thread-entry-path' - -describe('worker-thread entry path', () => { - const outMain = join('/repo', 'out', 'main') - - it('resolves an unpackaged caller bundled into a shared chunk beside the main entry', () => { - const layout = currentWorkerEntryLayout(join(outMain, 'chunks')) - expect(resolveWorkerThreadEntryPath({ ...layout, isPackaged: false }, 'entry.js')).toBe( - join(outMain, 'entry.js') - ) - }) - - it('keeps an unpackaged caller already in the main entry folder', () => { - const layout = currentWorkerEntryLayout(outMain) - expect(resolveWorkerThreadEntryPath({ ...layout, isPackaged: false }, 'entry.js')).toBe( - join(outMain, 'entry.js') - ) - }) - - it('resolves packaged builds from resources, whatever the caller chunk', () => { - const layout = { isPackaged: true, resourcesPath: '/res', moduleDir: join(outMain, 'chunks') } - expect(resolveWorkerThreadEntryPath(layout, 'entry.js')).toBe( - join('/res', 'app.asar', 'out', 'main', 'entry.js') - ) - }) -}) diff --git a/src/main/workspace-space-repo-scan.test.ts b/src/main/workspace-space-repo-scan.test.ts deleted file mode 100644 index 5447ca93550..00000000000 --- a/src/main/workspace-space-repo-scan.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { WorkspaceSpaceWorktree } from '../shared/workspace-space-types' -import { summarizeWorkspaceSpaceRows } from './workspace-space-repo-scan' - -describe('summarizeWorkspaceSpaceRows', () => { - it('reads each summary field once per row', () => { - const reads = { status: 0, sizeBytes: 0, reclaimableBytes: 0 } - const makeRow = (status: WorkspaceSpaceWorktree['status']) => - new Proxy({ status, sizeBytes: 10, reclaimableBytes: 4 } as WorkspaceSpaceWorktree, { - get(target, property, receiver) { - if ( - property === 'status' || - property === 'sizeBytes' || - property === 'reclaimableBytes' - ) { - reads[property] += 1 - } - // oxlint-disable-next-line anti-slop/no-reflect-get -- Proxy get trap default forward. - return Reflect.get(target, property, receiver) - } - }) - - expect(summarizeWorkspaceSpaceRows([makeRow('ok'), makeRow('unavailable')])).toEqual({ - scannedWorktreeCount: 1, - unavailableWorktreeCount: 1, - totalSizeBytes: 20, - reclaimableBytes: 8 - }) - expect(reads).toEqual({ status: 2, sizeBytes: 2, reclaimableBytes: 2 }) - }) -}) diff --git a/src/main/zcode/interactive-capability.live.test.ts b/src/main/zcode/interactive-capability.live.test.ts deleted file mode 100644 index 5c605177593..00000000000 --- a/src/main/zcode/interactive-capability.live.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { existsSync } from 'node:fs' -import { describe, expect, it, beforeEach } from 'vitest' -import { - readZCodeInteractiveCapability, - _resetZCodeInteractiveCapabilityForTests -} from './interactive-capability' - -// Compare real bundled/no-TUI and CLI/TUI builds only where those local fixtures exist. -const WITHOUT_TUI = '/tmp/zcode-bin-notui/zcode' -const WITH_TUI = '/tmp/zcode-bin-tui/zcode' -const bothPresent = existsSync(WITHOUT_TUI) && existsSync(WITH_TUI) -const describeLive = bothPresent ? describe : describe.skip - -beforeEach(() => _resetZCodeInteractiveCapabilityForTests()) - -describeLive('readZCodeInteractiveCapability against real ZCode builds', () => { - it("reports missing-tui for the desktop app's bundled runtime", async () => { - await expect(readZCodeInteractiveCapability(WITHOUT_TUI)).resolves.toBe('missing-tui') - }, 30_000) - - it('reports interactive for a CLI built from source', async () => { - await expect(readZCodeInteractiveCapability(WITH_TUI)).resolves.toBe('interactive') - }, 30_000) - - it('fails open when the command does not exist', async () => { - await expect(readZCodeInteractiveCapability('/tmp/definitely-not-zcode')).resolves.toBe( - 'unknown' - ) - }, 30_000) -}) diff --git a/src/renderer/src/components/browser-pane/navigate/browser-download-progress.test.ts b/src/renderer/src/components/browser-pane/navigate/browser-download-progress.test.ts deleted file mode 100644 index c7fb944568f..00000000000 --- a/src/renderer/src/components/browser-pane/navigate/browser-download-progress.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - formatBrowserDownloadProgress, - type BrowserDownloadState -} from './browser-download-progress' - -function download(overrides: Partial = {}): BrowserDownloadState { - return { - downloadId: 'd1', - browserPageId: 'p1', - filename: 'file.bin', - mimeType: 'application/octet-stream', - origin: 'https://example.com', - totalBytes: 2048, - receivedBytes: 1024, - status: 'downloading', - savePath: null, - error: null, - progressState: 'progressing', - completedAt: null, - url: 'https://example.com/file.bin', - ...overrides - } as BrowserDownloadState -} - -describe('formatBrowserDownloadProgress', () => { - it('joins received and total when both are known', () => { - expect(formatBrowserDownloadProgress(download())).toBe('1.0 KB / 2.0 KB') - }) - - it('falls back to the single known side', () => { - expect(formatBrowserDownloadProgress(download({ totalBytes: null }))).toBe('1.0 KB') - expect(formatBrowserDownloadProgress(download({ receivedBytes: -1, totalBytes: 2048 }))).toBe( - '2.0 KB' - ) - }) -}) diff --git a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-keyboard.test.ts b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-keyboard.test.ts index 9c3176387f7..65f60046b12 100644 --- a/src/renderer/src/components/browser-pane/stream-remote/remote-browser-keyboard.test.ts +++ b/src/renderer/src/components/browser-pane/stream-remote/remote-browser-keyboard.test.ts @@ -19,10 +19,6 @@ function keyboardEvent( } describe('remote browser keyboard serialization', () => { - it('serializes modified letter shortcuts', () => { - expect(getRemoteBrowserKeyboardShortcut(keyboardEvent({ ctrlKey: true }))).toBe('Control+r') - }) - it('preserves Shift on modified letter shortcuts', () => { expect( getRemoteBrowserKeyboardShortcut(keyboardEvent({ key: 'R', ctrlKey: true, shiftKey: true })) diff --git a/src/renderer/src/components/comment-reply-target-state.test.ts b/src/renderer/src/components/comment-reply-target-state.test.ts deleted file mode 100644 index f19cc94a620..00000000000 --- a/src/renderer/src/components/comment-reply-target-state.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - getCommentReplyTargetCandidates, - resolveCommentReplyTarget -} from './comment-reply-target-state' - -describe('comment reply target state', () => { - it('preserves a visible reply target', () => { - expect(resolveCommentReplyTarget(2, [{ id: 1 }, { id: 2 }])).toBe(2) - }) - - it('clears a hidden reply target', () => { - expect(resolveCommentReplyTarget(3, [{ id: 1 }, { id: 2 }])).toBeNull() - }) - - it('keeps an empty reply target empty', () => { - expect(resolveCommentReplyTarget(null, [{ id: 1 }])).toBeNull() - }) - - it('uses filtered comments as reply targets for PRs', () => { - expect(getCommentReplyTargetCandidates('pr', [{ id: 1 }, { id: 2 }], [{ id: 2 }])).toEqual([ - { id: 2 } - ]) - }) - - it('uses all comments as reply targets for issues', () => { - expect(getCommentReplyTargetCandidates('issue', [{ id: 1 }, { id: 2 }], [{ id: 2 }])).toEqual([ - { id: 1 }, - { id: 2 } - ]) - }) -}) diff --git a/src/renderer/src/components/editor/diff-section-comment-submit.test.ts b/src/renderer/src/components/editor/diff-section-comment-submit.test.ts deleted file mode 100644 index 0332839c134..00000000000 --- a/src/renderer/src/components/editor/diff-section-comment-submit.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { beforeEach, describe, expect, it, vi } from 'vitest' -import { toast } from 'sonner' -import { submitDiffSectionComment } from './diff-section-comment-submit' -import type { DiffSection } from './diff-section-types' - -vi.mock('sonner', () => ({ toast: { error: vi.fn() } })) - -const section: DiffSection = { - key: 'section-1', - path: 'src/example.ts', - status: 'modified', - originalContent: 'before', - modifiedContent: 'after', - collapsed: false, - loading: false, - dirty: false, - diffResult: null, - largeDiffRenderLimit: null -} - -describe('submitDiffSectionComment', () => { - beforeEach(() => { - vi.mocked(toast.error).mockClear() - }) - - it('surfaces persistence failures while keeping the draft open', async () => { - const addDiffComment = vi.fn().mockResolvedValue(null) - - const result = await submitDiffSectionComment({ - addDiffComment, - body: 'Needs revision', - target: { lineNumber: 4 }, - section, - worktreeId: 'worktree-1' - }) - - expect(result).toBe(false) - expect(toast.error).toHaveBeenCalledWith('Failed to save comment') - }) -}) diff --git a/src/renderer/src/components/editor/editor-labels.test.ts b/src/renderer/src/components/editor/editor-labels.test.ts deleted file mode 100644 index a22e874384d..00000000000 --- a/src/renderer/src/components/editor/editor-labels.test.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getEditorDisplayLabel } from './editor-labels' -import type { OpenFile } from '@/store/slices/editor' - -function makeOpenFile(overrides: Partial = {}): OpenFile { - return { - id: '/repo/docs/README.md', - filePath: '/repo/docs/README.md', - relativePath: 'docs/README.md', - worktreeId: 'wt-1', - language: 'markdown', - isDirty: false, - mode: 'edit', - ...overrides - } -} - -describe('getEditorDisplayLabel', () => { - it('adds a preview suffix for markdown preview tabs', () => { - expect( - getEditorDisplayLabel( - makeOpenFile({ - id: 'markdown-preview::/repo/docs/README.md', - mode: 'markdown-preview' - }) - ) - ).toBe('README.md (preview)') - }) - - it('uses the requested label variant for markdown preview tabs', () => { - expect( - getEditorDisplayLabel( - makeOpenFile({ - id: 'markdown-preview::/repo/docs/README.md', - mode: 'markdown-preview' - }), - 'relativePath' - ) - ).toBe('docs/README.md (preview)') - }) -}) diff --git a/src/renderer/src/components/github-link-copy-state.test.ts b/src/renderer/src/components/github-link-copy-state.test.ts index 7b910871458..821b8bf344d 100644 --- a/src/renderer/src/components/github-link-copy-state.test.ts +++ b/src/renderer/src/components/github-link-copy-state.test.ts @@ -1,19 +1,11 @@ import { describe, expect, it } from 'vitest' import { clearGitHubLinkCopied, - createGitHubLinkCopyState, markGitHubLinkCopied, - resolveGitHubLinkCopyState, - type GitHubLinkCopyState + resolveGitHubLinkCopyState } from './github-link-copy-state' describe('GitHub link copy state', () => { - it('keeps copied state for the same work item', () => { - const state = markGitHubLinkCopied('item-1') - - expect(resolveGitHubLinkCopyState(state, 'item-1')).toBe(state) - }) - it('resets copied state when the rendered work item changes', () => { const state = markGitHubLinkCopied('item-1') @@ -28,10 +20,4 @@ describe('GitHub link copy state', () => { expect(clearGitHubLinkCopied(state, 'item-1')).toBe(state) }) - - it('preserves identity when clearing an already-clear state', () => { - const state: GitHubLinkCopyState = createGitHubLinkCopyState('item-1') - - expect(clearGitHubLinkCopied(state, 'item-1')).toBe(state) - }) }) diff --git a/src/renderer/src/components/github-project/ProjectViewStates.test.tsx b/src/renderer/src/components/github-project/ProjectViewStates.test.tsx deleted file mode 100644 index 7045ea2531b..00000000000 --- a/src/renderer/src/components/github-project/ProjectViewStates.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -// @vitest-environment happy-dom - -import { cleanup, render, screen } from '@testing-library/react' -import { afterEach, describe, expect, it } from 'vitest' -import { ProjectItemsEmptyState } from './ProjectViewStates' - -afterEach(cleanup) - -const FILTERED_COPY = "No items match this view's filter." -const UNFILTERED_COPY = 'This view has no items yet.' -const TRANSIENCE_HINT = 'Recently added items can take a while to appear.' - -describe('ProjectItemsEmptyState', () => { - it('blames the filter only when the view actually has one', () => { - render() - expect(screen.getByText(FILTERED_COPY)).toBeTruthy() - expect(screen.queryByText(UNFILTERED_COPY)).toBeNull() - }) - - it.each(['', ' ', '\n\t'])('reports an unfiltered view as empty for filter %j', (filter) => { - render() - expect(screen.getByText(UNFILTERED_COPY)).toBeTruthy() - expect(screen.getByText(TRANSIENCE_HINT)).toBeTruthy() - expect(screen.queryByText(FILTERED_COPY)).toBeNull() - }) -}) diff --git a/src/renderer/src/components/linear-api-key-dialog-state.test.ts b/src/renderer/src/components/linear-api-key-dialog-state.test.ts deleted file mode 100644 index 7339fdba5b6..00000000000 --- a/src/renderer/src/components/linear-api-key-dialog-state.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - CLOSED_LINEAR_API_KEY_DIALOG_STATE, - resolveLinearApiKeyDialogState, - type LinearApiKeyDialogState -} from './linear-api-key-dialog-state' - -describe('resolveLinearApiKeyDialogState', () => { - it('preserves draft and error state while the dialog is open', () => { - const state: LinearApiKeyDialogState = { - apiKeyDraft: 'lin_api_key', - connectState: 'error', - connectError: 'Nope' - } - - expect(resolveLinearApiKeyDialogState(state, true)).toBe(state) - }) - - it('preserves identity for an already-reset closed dialog', () => { - expect(resolveLinearApiKeyDialogState(CLOSED_LINEAR_API_KEY_DIALOG_STATE, false)).toBe( - CLOSED_LINEAR_API_KEY_DIALOG_STATE - ) - }) - - it('resets draft and connection state when the dialog is closed', () => { - const state: LinearApiKeyDialogState = { - apiKeyDraft: 'lin_api_key', - connectState: 'connecting', - connectError: 'Previous error' - } - - expect(resolveLinearApiKeyDialogState(state, false)).toEqual(CLOSED_LINEAR_API_KEY_DIALOG_STATE) - }) -}) diff --git a/src/renderer/src/components/native-chat/native-chat-split-shortcut.test.ts b/src/renderer/src/components/native-chat/native-chat-split-shortcut.test.ts deleted file mode 100644 index 0a5b2bd6688..00000000000 --- a/src/renderer/src/components/native-chat/native-chat-split-shortcut.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { matchNativeChatSplitShortcut } from './native-chat-split-shortcut' - -describe('matchNativeChatSplitShortcut', () => { - it('uses the existing platform split bindings', () => { - expect( - matchNativeChatSplitShortcut( - { key: 'd', metaKey: true, ctrlKey: false, altKey: false, shiftKey: false }, - 'darwin', - {} - ) - ).toBe('right') - expect( - matchNativeChatSplitShortcut( - { key: 'd', metaKey: false, ctrlKey: true, altKey: false, shiftKey: true }, - 'win32', - {} - ) - ).toBe('right') - expect( - matchNativeChatSplitShortcut( - { key: 'd', metaKey: false, ctrlKey: false, altKey: true, shiftKey: true }, - 'linux', - {} - ) - ).toBe('down') - }) - - it('respects customized bindings', () => { - expect( - matchNativeChatSplitShortcut( - { key: 'ArrowRight', metaKey: false, ctrlKey: true, altKey: true, shiftKey: false }, - 'linux', - { 'terminal.splitRight': ['Ctrl+Alt+Right'] } - ) - ).toBe('right') - }) -}) diff --git a/src/renderer/src/components/right-sidebar/SourceControl.push-failure-recovery.test.ts b/src/renderer/src/components/right-sidebar/SourceControl.push-failure-recovery.test.ts deleted file mode 100644 index 98295866cd2..00000000000 --- a/src/renderer/src/components/right-sidebar/SourceControl.push-failure-recovery.test.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - appendPushFailureCustomInstruction, - buildFixPushFailurePrompt -} from '../../../../shared/source-control-push-failure' - -describe('SourceControl push failure recovery prompt', () => { - it('adds one-time custom instructions before the response contract', () => { - const prompt = buildFixPushFailurePrompt({ - summary: 'Pre-push hook failed.', - error: 'lint failed', - branchName: 'main', - worktreePath: null, - entries: [], - customInstruction: 'Only change TypeScript files.' - }) - - expect(prompt).toContain('Additional user instruction for this fix:') - expect(prompt).toContain('Only change TypeScript files.') - expect(prompt.trim().endsWith('anything left for the user.')).toBe(true) - }) - - it('leaves the base prompt unchanged for empty custom instructions', () => { - const prompt = 'Fix the failed push.' - expect(appendPushFailureCustomInstruction(prompt, ' ')).toBe(prompt) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/ai-vault-search-hit-hosts.test.ts b/src/renderer/src/components/right-sidebar/ai-vault-search-hit-hosts.test.ts deleted file mode 100644 index f11e9a9c835..00000000000 --- a/src/renderer/src/components/right-sidebar/ai-vault-search-hit-hosts.test.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { aiVaultSearchHitHostLabels } from './ai-vault-search-hit-hosts' - -describe('aiVaultSearchHitHostLabels', () => { - it('returns null while every hit came from one host', () => { - expect( - aiVaultSearchHitHostLabels( - [{ executionHostId: 'runtime:devbox' }, { executionHostId: 'runtime:devbox' }], - [{ id: 'runtime:devbox', label: 'devbox' }] - ) - ).toBeNull() - }) - - it('names each host the way the host menu does, with the id label as fallback', () => { - const labels = aiVaultSearchHitHostLabels( - [ - { executionHostId: 'local' }, - { executionHostId: 'runtime:env-1' }, - { executionHostId: 'runtime:env-gone' } - ], - [ - { id: 'local', label: 'Local Mac' }, - { id: 'runtime:env-1', label: 'devbox' } - ] - ) - - expect(labels && Object.fromEntries(labels)).toEqual({ - local: 'Local Mac', - 'runtime:env-1': 'devbox', - 'runtime:env-gone': 'env-gone' - }) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/file-explorer-refresh-concurrency.test.ts b/src/renderer/src/components/right-sidebar/file-explorer-refresh-concurrency.test.ts deleted file mode 100644 index b1d319933b7..00000000000 --- a/src/renderer/src/components/right-sidebar/file-explorer-refresh-concurrency.test.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { fileExplorerRefreshConcurrency } from './file-explorer-refresh-concurrency' - -describe('fileExplorerRefreshConcurrency', () => { - it('allows the widest fan-out for local disk reads', () => { - expect(fileExplorerRefreshConcurrency({ kind: 'local' })).toBe(16) - }) - - it('caps SSH-owned worktrees at the remote tier', () => { - expect(fileExplorerRefreshConcurrency({ kind: 'ssh', connectionId: 'target-1' })).toBe(4) - }) - - it('treats an SSH-backed runtime as remote', () => { - expect( - fileExplorerRefreshConcurrency({ - kind: 'runtime', - environmentId: 'env-1', - executionHostId: 'ssh:target-1' - }) - ).toBe(4) - }) - - it('uses the runtime tier for a non-SSH runtime host', () => { - expect( - fileExplorerRefreshConcurrency({ - kind: 'runtime', - environmentId: 'env-1', - executionHostId: 'runtime:env-1' - }) - ).toBe(8) - }) - - it('falls back to the conservative remote tier when ownership is unresolved', () => { - expect(fileExplorerRefreshConcurrency({ kind: 'unresolved' })).toBe(4) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts b/src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts deleted file mode 100644 index 34fdecaadfb..00000000000 --- a/src/renderer/src/components/right-sidebar/right-sidebar-width.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - RIGHT_SIDEBAR_ABSOLUTE_FALLBACK_MAX_WIDTH, - RIGHT_SIDEBAR_MIN_WIDTH, - clampRightSidebarPanelWidth, - computeMaxRightSidebarPanelWidth -} from './right-sidebar-width' - -describe('right sidebar rendered width', () => { - it('leaves the reserved non-sidebar area when persisted width is too large', () => { - expect(clampRightSidebarPanelWidth(900, 900, 0)).toBe(580) - }) - - it('includes rendered extra width in the reservation math', () => { - expect(computeMaxRightSidebarPanelWidth(900, 40)).toBe(540) - expect(clampRightSidebarPanelWidth(900, 900, 40)).toBe(540) - }) - - it('preserves the minimum sidebar width on narrow windows', () => { - expect(clampRightSidebarPanelWidth(900, 400, 40)).toBe(RIGHT_SIDEBAR_MIN_WIDTH) - }) - - it('uses the fallback max outside DOM environments', () => { - expect(computeMaxRightSidebarPanelWidth(null, 40)).toBe( - RIGHT_SIDEBAR_ABSOLUTE_FALLBACK_MAX_WIDTH - ) - }) -}) diff --git a/src/renderer/src/components/right-sidebar/source-control-created-review-link.test.ts b/src/renderer/src/components/right-sidebar/source-control-created-review-link.test.ts deleted file mode 100644 index f427fcc3b7a..00000000000 --- a/src/renderer/src/components/right-sidebar/source-control-created-review-link.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { HostedReviewProvider } from '../../../../shared/hosted-review' -import { resolveCreatedHostedReviewLink } from './source-control-created-review-link' - -describe('resolveCreatedHostedReviewLink', () => { - it.each([ - ['github', { linkedPR: 42 }, { linkedGitHubPR: 42 }], - ['gitlab', { linkedGitLabMR: 42 }, { linkedGitLabMR: 42 }], - ['bitbucket', { linkedBitbucketPR: 42 }, { linkedBitbucketPR: 42 }], - ['azure-devops', { linkedAzureDevOpsPR: 42 }, { linkedAzureDevOpsPR: 42 }], - ['gitea', { linkedGiteaPR: 42 }, { linkedGiteaPR: 42 }] - ] as const)('links a created %s review by number', (provider, worktree, lookup) => { - expect(resolveCreatedHostedReviewLink(provider as HostedReviewProvider, 42)).toEqual({ - worktree, - lookup - }) - }) - - it('does not link an unsupported review provider', () => { - expect(resolveCreatedHostedReviewLink('unsupported', 42)).toEqual({ - worktree: {}, - lookup: {} - }) - }) -}) diff --git a/src/renderer/src/components/settings/FloatingWorkspacePane.test.tsx b/src/renderer/src/components/settings/FloatingWorkspacePane.test.tsx deleted file mode 100644 index 529c0425d9c..00000000000 --- a/src/renderer/src/components/settings/FloatingWorkspacePane.test.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getFloatingWorkspaceDirectoryInputValue } from './FloatingWorkspacePane' - -describe('getFloatingWorkspaceDirectoryInputValue', () => { - it('shows home shorthand for the default terminal directory', () => { - expect( - getFloatingWorkspaceDirectoryInputValue({ - configuredFloatingWorkspacePath: '~', - resolvedFloatingWorkspacePath: '/Users/example' - }) - ).toBe('~') - }) - - it('shows home shorthand for legacy blank terminal directory settings', () => { - expect( - getFloatingWorkspaceDirectoryInputValue({ - configuredFloatingWorkspacePath: '', - resolvedFloatingWorkspacePath: '/Users/example' - }) - ).toBe('~') - }) - - it('shows the main-resolved trusted custom directory', () => { - expect( - getFloatingWorkspaceDirectoryInputValue({ - configuredFloatingWorkspacePath: '/Users/example/notes', - resolvedFloatingWorkspacePath: '/Users/example/notes' - }) - ).toBe('/Users/example/notes') - }) -}) diff --git a/src/renderer/src/components/settings/PluginKeybindingConsentPreview.test.ts b/src/renderer/src/components/settings/PluginKeybindingConsentPreview.test.ts deleted file mode 100644 index 7fb393af63b..00000000000 --- a/src/renderer/src/components/settings/PluginKeybindingConsentPreview.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { describe, expect, it, afterEach, vi } from 'vitest' -import { shadowedKeybindingTitles } from './PluginKeybindingConsentPreview' - -describe('plugin keybinding consent preview', () => { - it('names built-in shortcuts shadowed by plugin chords and user overrides', () => { - expect(shadowedKeybindingTitles('Mod+P', 'darwin')).toContain('Go to File') - expect( - shadowedKeybindingTitles('Mod+Alt+T', 'linux', { 'view.tasks': ['Mod+Alt+T'] }) - ).toContain('Open Tasks') - }) -}) - -const { rejectAppStoreAccess } = vi.hoisted(() => ({ - rejectAppStoreAccess: vi.fn(() => { - throw new Error('Pure helper tests must not access the app store') - }) -})) - -vi.mock('@/store', () => ({ - useAppStore: Object.assign(rejectAppStoreAccess, { - getState: rejectAppStoreAccess, - getInitialState: rejectAppStoreAccess, - setState: rejectAppStoreAccess, - subscribe: rejectAppStoreAccess - }) -})) - -afterEach(() => { - expect(rejectAppStoreAccess).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/sidebar/project-filter-reveal.test.ts b/src/renderer/src/components/sidebar/project-filter-reveal.test.ts deleted file mode 100644 index b0836415a75..00000000000 --- a/src/renderer/src/components/sidebar/project-filter-reveal.test.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { describe, expect, it, vi } from 'vitest' -import { revealRepoInProjectFilter } from './project-filter-reveal' - -function makeState(filterRepoIds: readonly string[]) { - return { filterRepoIds, setFilterRepoIds: vi.fn() } -} - -describe('revealRepoInProjectFilter', () => { - it('keeps the existing selection and adds the revealed project', () => { - const state = makeState(['repo-a', 'repo-b']) - - revealRepoInProjectFilter(state, 'repo-c') - - expect(state.setFilterRepoIds).toHaveBeenCalledWith(['repo-a', 'repo-b', 'repo-c']) - }) - - it('does nothing when no project filter is active', () => { - const state = makeState([]) - - revealRepoInProjectFilter(state, 'repo-c') - - expect(state.setFilterRepoIds).not.toHaveBeenCalled() - }) - - it('does nothing when the project is already selected', () => { - const state = makeState(['repo-a', 'repo-c']) - - revealRepoInProjectFilter(state, 'repo-c') - - expect(state.setFilterRepoIds).not.toHaveBeenCalled() - }) -}) diff --git a/src/renderer/src/components/sidebar/worktree-card-dom-events.test.ts b/src/renderer/src/components/sidebar/worktree-card-dom-events.test.ts deleted file mode 100644 index 5f7e434ee5a..00000000000 --- a/src/renderer/src/components/sidebar/worktree-card-dom-events.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -// @vitest-environment happy-dom - -import { describe, expect, it } from 'vitest' -import { isEventTargetInsideCurrentTarget } from './worktree-card-dom-events' - -describe('worktree card DOM events', () => { - it('recognizes DOM events that originate inside the current target', () => { - const currentTarget = document.createElement('div') - const child = document.createElement('button') - currentTarget.appendChild(child) - - expect(isEventTargetInsideCurrentTarget(currentTarget, child)).toBe(true) - }) - - it('rejects portaled DOM events that bubble through the React tree', () => { - const currentTarget = document.createElement('div') - const portaledTarget = document.createElement('button') - - expect(isEventTargetInsideCurrentTarget(currentTarget, portaledTarget)).toBe(false) - }) - - it('supports text-node event targets inside the current target', () => { - const currentTarget = document.createElement('div') - const textTarget = document.createTextNode('Rename') - currentTarget.appendChild(textTarget) - - expect(isEventTargetInsideCurrentTarget(currentTarget, textTarget)).toBe(true) - }) -}) diff --git a/src/renderer/src/components/terminal-pane/terminal-http-link-activation.test.ts b/src/renderer/src/components/terminal-pane/terminal-http-link-activation.test.ts deleted file mode 100644 index ca11b713450..00000000000 --- a/src/renderer/src/components/terminal-pane/terminal-http-link-activation.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { afterEach, describe, expect, it, vi } from 'vitest' -import { isTerminalHttpLinkActivation } from './terminal-http-link-activation' - -afterEach(() => { - vi.unstubAllGlobals() -}) - -describe('isTerminalHttpLinkActivation', () => { - it('leaves Alt+Cmd gestures to the child TUI on macOS', () => { - vi.stubGlobal('navigator', { userAgent: 'Macintosh' }) - - expect( - isTerminalHttpLinkActivation({ metaKey: true, ctrlKey: false, altKey: false } as MouseEvent) - ).toBe(true) - expect( - isTerminalHttpLinkActivation({ metaKey: true, ctrlKey: false, altKey: true } as MouseEvent) - ).toBe(false) - }) - - it('leaves Alt+Ctrl gestures to the child TUI on other platforms', () => { - vi.stubGlobal('navigator', { userAgent: 'Windows' }) - - expect( - isTerminalHttpLinkActivation({ metaKey: false, ctrlKey: true, altKey: false } as MouseEvent) - ).toBe(true) - expect( - isTerminalHttpLinkActivation({ metaKey: false, ctrlKey: true, altKey: true } as MouseEvent) - ).toBe(false) - }) -}) diff --git a/src/renderer/src/components/terminal-pane/terminal-process-exit-restart.test.ts b/src/renderer/src/components/terminal-pane/terminal-process-exit-restart.test.ts index 78d4f469361..0edf52f4394 100644 --- a/src/renderer/src/components/terminal-pane/terminal-process-exit-restart.test.ts +++ b/src/renderer/src/components/terminal-pane/terminal-process-exit-restart.test.ts @@ -15,17 +15,6 @@ describe('terminal process exit restart', () => { ).toBe(startup) }) - it('restarts a shell when a capacity failure had no startup request', () => { - expect( - resolveTerminalProcessExitRestartStartup({ - paneId: 1, - exitCode: 1, - reason: 'git-bash-console-capacity', - startup: null - }) - ).toBeNull() - }) - it('restarts other process failures as a shell', () => { expect( resolveTerminalProcessExitRestartStartup({ diff --git a/src/renderer/src/components/terminal-pane/use-manual-terminal-worktree-parking.test.ts b/src/renderer/src/components/terminal-pane/use-manual-terminal-worktree-parking.test.ts deleted file mode 100644 index 1504ce16410..00000000000 --- a/src/renderer/src/components/terminal-pane/use-manual-terminal-worktree-parking.test.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { describe, expect, it, afterEach, vi } from 'vitest' -import { combineTerminalWorktreeParkIds } from './use-manual-terminal-worktree-parking' - -describe('combineTerminalWorktreeParkIds', () => { - it('adds manually parked worktrees without dropping automatic parks', () => { - expect(combineTerminalWorktreeParkIds(new Set(['automatic']), new Set(['manual']))).toEqual( - new Set(['automatic', 'manual']) - ) - }) - - it('keeps the automatic set reference when there are no manual parks', () => { - const automatic = new Set(['automatic']) - - expect(combineTerminalWorktreeParkIds(automatic, new Set())).toBe(automatic) - }) -}) - -const { rejectAppStoreAccess } = vi.hoisted(() => ({ - rejectAppStoreAccess: vi.fn(() => { - throw new Error('Pure helper tests must not access the app store') - }) -})) - -vi.mock('@/store', () => ({ - useAppStore: Object.assign(rejectAppStoreAccess, { - getState: rejectAppStoreAccess, - getInitialState: rejectAppStoreAccess, - setState: rejectAppStoreAccess, - subscribe: rejectAppStoreAccess - }) -})) - -afterEach(() => { - expect(rejectAppStoreAccess).not.toHaveBeenCalled() -}) diff --git a/src/renderer/src/components/ui/repo-multi-combobox.test.ts b/src/renderer/src/components/ui/repo-multi-combobox.test.ts deleted file mode 100644 index 3248e743afc..00000000000 --- a/src/renderer/src/components/ui/repo-multi-combobox.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { describe, expect, it } from 'vitest' -import type { Repo } from '../../../../shared/repo-types' -import { getRepoMultiComboboxDetail } from './repo-multi-combobox' - -function repo(overrides: Partial = {}): Repo { - return { - id: 'repo-1', - path: '/Users/jinwoo/orca', - displayName: 'orca', - badgeColor: '#999999', - addedAt: 1, - ...overrides - } -} - -describe('getRepoMultiComboboxDetail', () => { - it('shows host context before the path when available', () => { - expect(getRepoMultiComboboxDetail(repo(), 'Local Mac')).toBe('Local Mac · /Users/jinwoo/orca') - expect(getRepoMultiComboboxDetail(repo({ path: '/home/orca/orca' }), 'openclaw 2')).toBe( - 'openclaw 2 · /home/orca/orca' - ) - }) - - it('keeps the existing path-only detail when no host label is provided', () => { - expect(getRepoMultiComboboxDetail(repo(), null)).toBe('/Users/jinwoo/orca') - expect(getRepoMultiComboboxDetail(repo(), ' ')).toBe('/Users/jinwoo/orca') - }) -}) diff --git a/src/renderer/src/components/ui/scroll-area.test.tsx b/src/renderer/src/components/ui/scroll-area.test.tsx deleted file mode 100644 index 958347b767d..00000000000 --- a/src/renderer/src/components/ui/scroll-area.test.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// @vitest-environment happy-dom - -import { act } from 'react' -import { createRoot, type Root } from 'react-dom/client' -import { afterEach, describe, expect, it } from 'vitest' -import { ScrollArea } from './scroll-area' - -globalThis.IS_REACT_ACT_ENVIRONMENT = true - -const roots: Root[] = [] - -afterEach(() => { - roots.splice(0).forEach((root) => { - act(() => root.unmount()) - }) - document.body.replaceChildren() -}) - -describe('ScrollArea sizing footgun', () => { - // Radix Root’s inline position beats absolute classes; size ScrollArea with height instead. - it('keeps Radix inline position:relative even when given an absolute className', async () => { - const container = document.createElement('div') - document.body.appendChild(container) - const root = createRoot(container) - roots.push(root) - - await act(async () => { - root.render( - -
- - ) - }) - - const el = container.querySelector('[data-slot="scroll-area"]') - expect(el).not.toBeNull() - expect(el!.style.position).toBe('relative') - }) -}) diff --git a/src/renderer/src/components/ui/switch.test.tsx b/src/renderer/src/components/ui/switch.test.tsx index dacaf8b8699..6e5c102a558 100644 --- a/src/renderer/src/components/ui/switch.test.tsx +++ b/src/renderer/src/components/ui/switch.test.tsx @@ -1,17 +1,8 @@ import { renderToStaticMarkup } from 'react-dom/server' import { describe, expect, it } from 'vitest' -import { Switch, SwitchIndicator } from './switch' +import { SwitchIndicator } from './switch' describe('Switch', () => { - it('renders the checked state with symmetric track geometry', () => { - const html = renderToStaticMarkup() - - expect(html).toContain('role="switch"') - expect(html).toContain('aria-checked="true"') - expect(html).toContain('p-0.5') - expect(html).toContain('data-[state=checked]:translate-x-4') - }) - it('renders a visual-only indicator without switch semantics', () => { const html = renderToStaticMarkup() @@ -19,12 +10,4 @@ describe('Switch', () => { expect(html).toContain('data-state="unchecked"') expect(html).not.toContain('role="switch"') }) - - it('renders compact indicator geometry', () => { - const html = renderToStaticMarkup() - - expect(html).toContain('h-3.5 w-6') - expect(html).toContain('size-2.5') - expect(html).toContain('data-[state=checked]:translate-x-2.5') - }) }) diff --git a/src/renderer/src/hooks/useResetCountdownClock.test.ts b/src/renderer/src/hooks/useResetCountdownClock.test.ts index 411cc27b558..1336ad4f3a3 100644 --- a/src/renderer/src/hooks/useResetCountdownClock.test.ts +++ b/src/renderer/src/hooks/useResetCountdownClock.test.ts @@ -26,14 +26,4 @@ describe('useResetCountdownClock', () => { }) expect(result.current).toBe(START + 30_000 + 1) }) - - it('does not schedule a tick when there is no future reset', () => { - const { result } = renderHook(() => useResetCountdownClock([START - 1000])) - expect(result.current).toBe(START) - - act(() => { - vi.advanceTimersByTime(10 * MIN) - }) - expect(result.current).toBe(START) - }) }) diff --git a/src/renderer/src/hooks/useVirtualizedScrollAnchor.test.ts b/src/renderer/src/hooks/useVirtualizedScrollAnchor.test.ts deleted file mode 100644 index 6129364bde2..00000000000 --- a/src/renderer/src/hooks/useVirtualizedScrollAnchor.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { shouldCancelVirtualizedScrollOffsetRestore } from './virtualizedScrollOffsetRestore' - -describe('shouldCancelVirtualizedScrollOffsetRestore', () => { - it('keeps a pending restore when direct user scroll input is not tracked', () => { - expect( - shouldCancelVirtualizedScrollOffsetRestore({ - restoring: true - }) - ).toBe(false) - }) - - it('keeps a pending restore during programmatic scroll movement', () => { - expect( - shouldCancelVirtualizedScrollOffsetRestore({ - hasDirectScrollInput: () => false, - restoring: true - }) - ).toBe(false) - }) - - it('does not cancel when there is no pending restore', () => { - expect( - shouldCancelVirtualizedScrollOffsetRestore({ - hasDirectScrollInput: () => true, - restoring: false - }) - ).toBe(false) - }) - - it('cancels a pending restore while direct user scroll input is active', () => { - expect( - shouldCancelVirtualizedScrollOffsetRestore({ - hasDirectScrollInput: () => true, - restoring: true - }) - ).toBe(true) - }) -}) diff --git a/src/renderer/src/lib/agent-type-icon.test.tsx b/src/renderer/src/lib/agent-type-icon.test.tsx deleted file mode 100644 index 555bdad2216..00000000000 --- a/src/renderer/src/lib/agent-type-icon.test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { renderToStaticMarkup } from 'react-dom/server' -import { describe, expect, it } from 'vitest' -import { AgentTypeIcon } from './agent-type-icon' - -function render(agentType: string | null | undefined): string { - return renderToStaticMarkup() -} - -describe('AgentTypeIcon', () => { - it("renders a program's first letter", () => { - expect(render('brew')).toContain('>B') - expect(render('terraform')).toContain('>T') - }) - - it('skips leading punctuation the app id grammar allows', () => { - expect(render('_9tool')).toContain('>9') - expect(render('.+-')).toContain('>?') - }) - - it('keeps "?" for unidentified agents', () => { - expect(render('unknown')).toContain('>?') - expect(render(null)).toContain('>?') - expect(render(undefined)).toContain('>?') - }) - - it('still renders the Claude icon for known agents', () => { - expect(render('claude')).toContain('#D97757') - }) -}) diff --git a/src/renderer/src/lib/keyboard-layout/option-key-location-state.test.ts b/src/renderer/src/lib/keyboard-layout/option-key-location-state.test.ts index d4e8fc95411..a095ec124b0 100644 --- a/src/renderer/src/lib/keyboard-layout/option-key-location-state.test.ts +++ b/src/renderer/src/lib/keyboard-layout/option-key-location-state.test.ts @@ -24,10 +24,4 @@ describe('createOptionKeyLocationTracker', () => { tracker.keyUp({ key: 'Alt', location: 0 }) expect(tracker.get()).toBe(0) }) - - it('ignores non-Option keys', () => { - const tracker = createOptionKeyLocationTracker() - tracker.keyDown({ key: 'Shift', location: 1 }) - expect(tracker.get()).toBe(0) - }) }) diff --git a/src/renderer/src/lib/linked-work-item-provider.test.ts b/src/renderer/src/lib/linked-work-item-provider.test.ts deleted file mode 100644 index 5fb6822dd94..00000000000 --- a/src/renderer/src/lib/linked-work-item-provider.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { getLinkedWorkItemProvider } from './linked-work-item-provider' - -describe('getLinkedWorkItemProvider', () => { - it.each([ - [ - 'explicit provider metadata', - { - type: 'issue', - provider: 'jira', - number: 0, - title: 'ORCA-123 Fix Jira', - url: 'https://example.atlassian.net/browse/ORCA-123', - jiraIdentifier: 'ORCA-123' - }, - 'jira' - ], - [ - 'Jira issue URL with no numeric issue id', - { - type: 'issue', - number: 0, - title: 'ORCA-123 Fix Jira', - url: 'https://example.atlassian.net/browse/ORCA-123' - }, - 'jira' - ], - [ - 'legacy Linear linked issue', - { - type: 'issue', - number: 0, - title: 'Fix Linear', - url: 'https://linear.app/team/issue/ENG-123/fix-linear', - linearIdentifier: 'ENG-123' - }, - 'linear' - ] - ] as const)('detects %s', (_label, item, provider) => { - expect(getLinkedWorkItemProvider(item)).toBe(provider) - }) -}) diff --git a/src/renderer/src/lib/orca-hook-trust.test.ts b/src/renderer/src/lib/orca-hook-trust.test.ts deleted file mode 100644 index 6ee2116e005..00000000000 --- a/src/renderer/src/lib/orca-hook-trust.test.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { afterEach, describe, expect, it } from 'vitest' -import { hashOrcaHookScript } from './orca-hook-trust' - -const realCrypto = globalThis.crypto - -afterEach(() => { - Object.defineProperty(globalThis, 'crypto', { value: realCrypto, configurable: true }) -}) - -function stubCrypto(value: unknown): void { - Object.defineProperty(globalThis, 'crypto', { value, configurable: true }) -} - -describe('hashOrcaHookScript', () => { - it('produces a stable hex digest via crypto.subtle', async () => { - const hash = await hashOrcaHookScript('echo hi') - expect(hash).toMatch(/^[0-9a-f]+$/) - expect(await hashOrcaHookScript(' echo hi ')).toBe(hash) - }) - - // Plain-HTTP LAN clients lack crypto.subtle; fallback must still produce deterministic matching trust hashes. - it('falls back to a deterministic hash when crypto.subtle is unavailable', async () => { - stubCrypto(undefined) - const hash = await hashOrcaHookScript('echo hi') - expect(hash).toMatch(/^[0-9a-f]+$/) - expect(await hashOrcaHookScript('echo hi')).toBe(hash) - expect(await hashOrcaHookScript('echo bye')).not.toBe(hash) - }) -}) diff --git a/src/renderer/src/lib/pane-manager/pane-pointer-focus.test.ts b/src/renderer/src/lib/pane-manager/pane-pointer-focus.test.ts deleted file mode 100644 index 0eaa1a3570f..00000000000 --- a/src/renderer/src/lib/pane-manager/pane-pointer-focus.test.ts +++ /dev/null @@ -1,37 +0,0 @@ -import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -import { shouldFocusTerminalFromPanePointerDown } from './pane-pointer-focus' - -class FakeElement { - constructor(private readonly closestResult: FakeElement | null = null) {} - - closest(): FakeElement | null { - return this.closestResult - } -} - -describe('shouldFocusTerminalFromPanePointerDown', () => { - beforeEach(() => { - vi.stubGlobal('Element', FakeElement) - }) - - afterEach(() => { - vi.unstubAllGlobals() - }) - - it('focuses the terminal for non-element targets', () => { - expect(shouldFocusTerminalFromPanePointerDown({} as EventTarget)).toBe(true) - }) - - it('focuses the terminal for ordinary pane surface clicks', () => { - const target = new FakeElement() - - expect(shouldFocusTerminalFromPanePointerDown(target as unknown as Element)).toBe(true) - }) - - it('does not steal focus from pane-local controls', () => { - const control = new FakeElement() - const target = new FakeElement(control) - - expect(shouldFocusTerminalFromPanePointerDown(target as unknown as Element)).toBe(false) - }) -}) diff --git a/src/shared/session-tab-placement.test.ts b/src/shared/session-tab-placement.test.ts index 2658b3c3cc4..1f131bfa258 100644 --- a/src/shared/session-tab-placement.test.ts +++ b/src/shared/session-tab-placement.test.ts @@ -4,12 +4,6 @@ import { placeCreatedSessionTab } from './session-tab-placement' const created = { id: 'new' } describe('placeCreatedSessionTab', () => { - it('inserts directly after the anchor', () => { - expect( - placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }, { id: 'c' }], created, 'a').map((t) => t.id) - ).toEqual(['a', 'new', 'b', 'c']) - }) - it('inserts after all leaves of a split parent', () => { expect( placeCreatedSessionTab( @@ -54,27 +48,12 @@ describe('placeCreatedSessionTab', () => { ).toEqual(['split::left', 'trailing', 'split::right', 'new']) }) - it('appends when the anchor is the last tab', () => { - expect( - placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }], created, 'b').map((t) => t.id) - ).toEqual(['a', 'b', 'new']) - }) - it('appends when the anchor is absent', () => { expect( placeCreatedSessionTab([{ id: 'a' }, { id: 'b' }], created, 'missing').map((t) => t.id) ).toEqual(['a', 'b', 'new']) }) - it('appends when no anchor is given', () => { - for (const anchor of [undefined, null, '']) { - expect(placeCreatedSessionTab([{ id: 'a' }], created, anchor).map((t) => t.id)).toEqual([ - 'a', - 'new' - ]) - } - }) - it('re-places a tab that is already in the list instead of duplicating it', () => { expect( placeCreatedSessionTab([{ id: 'a' }, { id: 'new' }, { id: 'b' }], created, 'b').map( @@ -82,10 +61,4 @@ describe('placeCreatedSessionTab', () => { ) ).toEqual(['a', 'b', 'new']) }) - - it('does not mutate the input list', () => { - const tabs = [{ id: 'a' }, { id: 'b' }] - placeCreatedSessionTab(tabs, created, 'a') - expect(tabs.map((t) => t.id)).toEqual(['a', 'b']) - }) }) diff --git a/src/shared/sidebar-list/workspace-review-facts.test.ts b/src/shared/sidebar-list/workspace-review-facts.test.ts index da120b1b484..92f510d86aa 100644 --- a/src/shared/sidebar-list/workspace-review-facts.test.ts +++ b/src/shared/sidebar-list/workspace-review-facts.test.ts @@ -1,9 +1,5 @@ import { describe, expect, it } from 'vitest' -import { - buildWorkspaceReviewFacts, - prGroupOfReviewFact, - readWorkspaceReviewFact -} from './workspace-review-facts' +import { buildWorkspaceReviewFacts, readWorkspaceReviewFact } from './workspace-review-facts' const repo = { id: 'repo-1', path: '/r', connectionId: null, executionHostId: null } const row = { id: 'repo-1::/r/a', repoId: 'repo-1', branch: 'refs/heads/a', linkedPR: null } @@ -43,15 +39,6 @@ describe('readWorkspaceReviewFact', () => { }) }) -describe('prGroupOfReviewFact', () => { - it('keeps rows without a PR in progress and lanes the rest by state', () => { - expect(prGroupOfReviewFact(null)).toBe('in-progress') - expect(prGroupOfReviewFact({ provider: 'github', reviewState: 'draft' })).toBe('in-progress') - expect(prGroupOfReviewFact({ provider: 'github', reviewState: '' })).toBe('in-review') - expect(prGroupOfReviewFact({ provider: 'github', reviewState: 'merged' })).toBe('done') - }) -}) - it('lists only rows with a PR, under the key the workspaces domain lists them at', () => { const other = { ...row, id: 'repo-1::/r/b', branch: 'b' } expect(buildWorkspaceReviewFacts([row, other], [repo], { 'repo-1::a': pr('open') })).toEqual({ diff --git a/src/shared/skill-delete-contract.test.ts b/src/shared/skill-delete-contract.test.ts index 2dab06fd37f..ee27ed65a56 100644 --- a/src/shared/skill-delete-contract.test.ts +++ b/src/shared/skill-delete-contract.test.ts @@ -1,10 +1,5 @@ import { describe, expect, it } from 'vitest' -import { - MAX_SKILL_DELETE_BATCH, - SkillDeletePlanSchema, - SkillDeleteRequestSchema, - SkillDeleteResultSchema -} from './skill-delete-contract' +import { MAX_SKILL_DELETE_BATCH, SkillDeleteRequestSchema } from './skill-delete-contract' const SKILL = { id: 'skill-id', @@ -15,13 +10,6 @@ const SKILL = { } describe('SkillDeleteRequestSchema', () => { - it('accepts a request with no target, which is what the page sends', () => { - expect(SkillDeleteRequestSchema.parse({ operationId: 'op', skills: [SKILL] })).toEqual({ - operationId: 'op', - skills: [SKILL] - }) - }) - it('rejects an unknown top-level field rather than ignoring it', () => { // Old hosts must reject delete-affecting unknown fields instead of silently dropping them. expect(() => @@ -56,55 +44,3 @@ describe('SkillDeleteRequestSchema', () => { ).toThrow() }) }) - -describe('plan and result schemas', () => { - it('carries a typed block reason so the band can group without string matching', () => { - const plan = SkillDeletePlanSchema.parse({ - operationId: 'op', - skills: [ - { - id: 'a', - name: 'demo', - canonicalPath: '/root/demo/SKILL.md', - placements: [], - blocked: 'bundled' - } - ] - }) - expect(plan.skills[0].blocked).toBe('bundled') - }) - - it('rejects a block reason outside the shared vocabulary', () => { - expect(() => - SkillDeletePlanSchema.parse({ - operationId: 'op', - skills: [{ id: 'a', name: 'demo', canonicalPath: '/p', placements: [], blocked: 'because' }] - }) - ).toThrow() - }) - - it('has no `unsupported` status, because such a delete is never issued', () => { - expect(() => - SkillDeleteResultSchema.parse({ - operationId: 'op', - skills: [{ id: 'a', name: 'demo', status: 'unsupported', removedPaths: [] }] - }) - ).toThrow() - }) - - it('accepts a partial result carrying the staged paths', () => { - const result = SkillDeleteResultSchema.parse({ - operationId: 'op', - skills: [ - { - id: 'a', - name: 'demo', - status: 'partial', - removedPaths: [], - stagedPaths: ['/root/.demo.orca-skill-delete-1'] - } - ] - }) - expect(result.skills[0].stagedPaths).toHaveLength(1) - }) -}) diff --git a/src/shared/skill-path-containment.test.ts b/src/shared/skill-path-containment.test.ts index 07bdc756aa5..b5e2646b7f2 100644 --- a/src/shared/skill-path-containment.test.ts +++ b/src/shared/skill-path-containment.test.ts @@ -1,7 +1,5 @@ import { describe, expect, it } from 'vitest' import { - nativeSkillPathSemantics, - normalizedSkillPath, POSIX_SKILL_PATH_SEMANTICS, skillPathDepthBelow, skillPathInside, @@ -74,17 +72,3 @@ describe('skillPathDepthBelow', () => { expect(skillPathDepthBelow('/r', '/other/SKILL.md', POSIX_SKILL_PATH_SEMANTICS)).toBeNull() }) }) - -describe('nativeSkillPathSemantics', () => { - it('reads the platform it is given rather than the process it runs in', () => { - expect(nativeSkillPathSemantics('win32')).toEqual(WINDOWS_SKILL_PATH_SEMANTICS) - expect(nativeSkillPathSemantics('linux')).toEqual(POSIX_SKILL_PATH_SEMANTICS) - expect(nativeSkillPathSemantics('darwin')).toEqual(POSIX_SKILL_PATH_SEMANTICS) - }) -}) - -describe('normalizedSkillPath', () => { - it('resolves before comparing', () => { - expect(normalizedSkillPath('/a/b/../c', POSIX_SKILL_PATH_SEMANTICS)).toBe('/a/c') - }) -}) diff --git a/src/shared/source-control-ai-action-variables.spec.ts b/src/shared/source-control-ai-action-variables.spec.ts index 443b1658845..07ef41a85e3 100644 --- a/src/shared/source-control-ai-action-variables.spec.ts +++ b/src/shared/source-control-ai-action-variables.spec.ts @@ -2,49 +2,11 @@ import { describe, expect, it } from 'vitest' import type { CommitMessageDraftContext } from './commit-message-generation' import { formatLinkedIssueTemplateValue, - SOURCE_CONTROL_ACTION_VARIABLE_INFO, - SOURCE_CONTROL_ACTION_VARIABLES, withLinkedIssueDraftContext } from './source-control-ai-action-variables' -import { - renderSourceControlActionCommandTemplate, - SOURCE_CONTROL_LAUNCH_ACTION_IDS -} from './source-control-ai-actions' - -describe('source-control AI variable registry', () => { - it('documents every registered variable so chip hover cards cannot crash', () => { - // Keep runtime coverage if the registry’s compile-time constraint ever loosens. - const documented = new Set(Object.keys(SOURCE_CONTROL_ACTION_VARIABLE_INFO)) - const undocumented = [...new Set(Object.values(SOURCE_CONTROL_ACTION_VARIABLES).flat())].filter( - (variable) => !documented.has(variable) - ) - - expect(undocumented).toEqual([]) - }) - - it('offers linkedIssue on commit message and pull request only', () => { - expect(SOURCE_CONTROL_ACTION_VARIABLES.commitMessage).toContain('linkedIssue') - expect(SOURCE_CONTROL_ACTION_VARIABLES.pullRequest).toContain('linkedIssue') - expect(SOURCE_CONTROL_ACTION_VARIABLES.branchName).not.toContain('linkedIssue') - for (const actionId of SOURCE_CONTROL_LAUNCH_ACTION_IDS) { - expect(SOURCE_CONTROL_ACTION_VARIABLES[actionId]).not.toContain('linkedIssue') - } - }) - - it('names GitHub and the empty case in the linkedIssue description', () => { - const info = SOURCE_CONTROL_ACTION_VARIABLE_INFO.linkedIssue - expect(info.description).toContain('GitHub') - expect(info.description).toContain('Empty') - expect(info.example).toBe('123') - }) -}) +import { renderSourceControlActionCommandTemplate } from './source-control-ai-actions' describe('formatLinkedIssueTemplateValue', () => { - it('renders positive integers as decimal strings', () => { - expect(formatLinkedIssueTemplateValue(123)).toBe('123') - expect(formatLinkedIssueTemplateValue(1)).toBe('1') - }) - it('renders anything that is not a positive integer as an empty string', () => { // Corrupt issue numbers must not produce references like Fixes #-7 or Fixes #1e+21. for (const value of [ diff --git a/src/shared/synthetic-agent-title.test.ts b/src/shared/synthetic-agent-title.test.ts index 3bf30f9e4d9..bfa7d6dbf08 100644 --- a/src/shared/synthetic-agent-title.test.ts +++ b/src/shared/synthetic-agent-title.test.ts @@ -23,11 +23,6 @@ describe('synthetic agent titles', () => { expect(isSyntheticAgentPermissionTitle(title)).toBe(false) }) - it('provides terminal-state titles for Codex hook completion', () => { - expect(getSyntheticAgentTerminalTitle('codex', 'done')).toBe('Codex ready') - expect(getSyntheticAgentTerminalTitle('codex', 'waiting')).toBe('Codex - action required') - }) - it('does not synthesize Codex working titles over Codex native spinner titles', () => { expect(shouldDriveSyntheticAgentTitleFromHook('codex', 'working')).toBe(false) expect(shouldDriveSyntheticAgentTitleFromHook('codex', 'done')).toBe(true) @@ -40,23 +35,4 @@ describe('synthetic agent titles', () => { expect(shouldDriveSyntheticAgentTitleFromHook('opencode', 'done')).toBe(false) expect(shouldDriveSyntheticAgentTitleFromHook('opencode', 'waiting')).toBe(false) }) - - it('provides Devin titles for hook-driven status updates', () => { - expect(getSyntheticAgentTerminalTitle('devin', 'done')).toBe('Devin ready') - expect(getSyntheticAgentTerminalTitle('devin', 'waiting')).toBe('Devin - action required') - expect(shouldDriveSyntheticAgentTitleFromHook('devin', 'working')).toBe(true) - }) - - it('provides Pi-compatible OMP titles for hook-driven status updates', () => { - expect(getSyntheticAgentTerminalTitle('omp', 'done')).toBe('OMP ready') - expect(getSyntheticAgentTerminalTitle('omp', 'waiting')).toBe('OMP - action required') - // Why: the native π working title carries session name/cwd; synthesizing would clobber it. - expect(shouldDriveSyntheticAgentTitleFromHook('omp', 'working')).toBe(false) - }) - - it('provides Pi titles for hook-driven status updates', () => { - expect(getSyntheticAgentTerminalTitle('pi', 'done')).toBe('Pi ready') - expect(getSyntheticAgentTerminalTitle('pi', 'waiting')).toBe('Pi - action required') - expect(shouldDriveSyntheticAgentTitleFromHook('pi', 'working')).toBe(false) - }) }) diff --git a/src/shared/task-providers.test.ts b/src/shared/task-providers.test.ts index d1fb07a0c6e..337af16987b 100644 --- a/src/shared/task-providers.test.ts +++ b/src/shared/task-providers.test.ts @@ -2,23 +2,10 @@ import { describe, expect, it } from 'vitest' import { filterAvailableTaskProviders, normalizeTaskProviderSettings, - normalizeVisibleTaskProviders, - restoreAvailableDefaultTaskProvider, - resolveVisibleTaskProvider + restoreAvailableDefaultTaskProvider } from './task-providers' describe('task providers', () => { - it('normalizes provider lists while preserving supported order', () => { - expect(normalizeVisibleTaskProviders(['gitlab', 'unknown', 'gitlab', 'linear'])).toEqual([ - 'gitlab', - 'linear' - ]) - }) - - it('falls back to all providers when none are visible', () => { - expect(normalizeVisibleTaskProviders([])).toEqual(['github', 'gitlab', 'linear', 'jira']) - }) - it('restores a valid saved default when provider settings drifted', () => { expect( normalizeTaskProviderSettings({ @@ -43,10 +30,6 @@ describe('task providers', () => { }) }) - it('resolves hidden preferred providers to the first visible provider', () => { - expect(resolveVisibleTaskProvider('github', ['linear'])).toBe('linear') - }) - it('filters runtime-unavailable providers without changing preference normalization', () => { expect( filterAvailableTaskProviders(['github', 'gitlab', 'linear'], { diff --git a/src/shared/terminal-agent-status-processor.test.ts b/src/shared/terminal-agent-status-processor.test.ts index ff4fdd33e7e..75d2a4eaa51 100644 --- a/src/shared/terminal-agent-status-processor.test.ts +++ b/src/shared/terminal-agent-status-processor.test.ts @@ -2,13 +2,6 @@ import { describe, expect, it } from 'vitest' import { createTerminalAgentStatusProcessor } from './terminal-agent-status-processor' describe('createTerminalAgentStatusProcessor', () => { - it('returns OSC 9999 chunks untouched when no OSC 7501 record changed', () => { - const process = createTerminalAgentStatusProcessor() - const result = process('a\x1b]9999;{"state":"working","prompt":"p"}\x07b') - expect(result.cleanData).toBe('ab') - expect(result.programStatusPayloads).toBeUndefined() - }) - it('appends OSC 7501 projections, marks them, and leaves the sequence in the stream', () => { const process = createTerminalAgentStatusProcessor() const data = 'x\x1b]7501;state=working:app=codex\x1b\\y' diff --git a/src/shared/terminal-partial-escape-tail-ground-scan.test.ts b/src/shared/terminal-partial-escape-tail-ground-scan.test.ts index b30642d69d4..725c3046317 100644 --- a/src/shared/terminal-partial-escape-tail-ground-scan.test.ts +++ b/src/shared/terminal-partial-escape-tail-ground-scan.test.ts @@ -52,24 +52,4 @@ describe('partial escape scanning between sequences', () => { } expect(extractPartialEscapeTail(`\x1b]2;title\x1b[32m${text}\x1b[1;`)).toBe('\x1b[1;') }) - - it('keeps one-character echo free of per-code-unit scans and escape searches', () => { - const charCodeAt = vi.spyOn(String.prototype, 'charCodeAt') - const indexOf = vi.spyOn(String.prototype, 'indexOf') - let actual: string - let inspections: number - let searches: number - try { - actual = advancePartialEscapeTail('', 'x') - inspections = charCodeAt.mock.calls.length - searches = indexOf.mock.calls.length - } finally { - charCodeAt.mockRestore() - indexOf.mockRestore() - } - - expect(actual).toBe('') - expect(inspections).toBe(0) - expect(searches).toBe(0) - }) }) diff --git a/src/shared/terminal-title-classification-memo.test.ts b/src/shared/terminal-title-classification-memo.test.ts index 058e4223ca4..5f523ac6194 100644 --- a/src/shared/terminal-title-classification-memo.test.ts +++ b/src/shared/terminal-title-classification-memo.test.ts @@ -51,18 +51,6 @@ describe('terminal title classification memo', () => { expect(classifierCalls).not.toHaveBeenCalled() }) - it('classifies a title once no matter how many readers ask', () => { - const title = 'aider running' - getAgentLabel(title) - const firstReadCalls = classifierCalls.mock.calls.length - expect(firstReadCalls).toBeGreaterThan(0) - - for (let read = 0; read < 20; read += 1) { - getAgentLabel(title) - } - expect(classifierCalls.mock.calls.length).toBe(firstReadCalls) - }) - it('reclassifies as soon as the title changes', () => { expect(getAgentLabel('codex ready')).toBe('Codex') expect(getAgentLabel('grok ready')).toBe('Grok') diff --git a/src/shared/windows-command-line-budget.test.ts b/src/shared/windows-command-line-budget.test.ts index c224ad3e493..f3d5836e52d 100644 --- a/src/shared/windows-command-line-budget.test.ts +++ b/src/shared/windows-command-line-budget.test.ts @@ -1,4 +1,4 @@ -import { describe, expect, it, vi } from 'vitest' +import { describe, expect, it } from 'vitest' import { commandLineLength } from './windows-command-line-budget' /** The regex form this estimator replaced; kept as the differential oracle. */ @@ -7,18 +7,6 @@ function referenceCommandLineLength(args: readonly string[]): number { } describe('windows command line budget', () => { - it('counts quote-dense payloads without allocating a match array', () => { - const args = ['node.exe', '-e', '"\\abc'.repeat(6000)] - const expected = referenceCommandLineLength(args) - const match = vi.spyOn(String.prototype, 'match') - try { - expect(commandLineLength(args)).toBe(expected) - expect(match.mock.calls.length).toBe(0) - } finally { - match.mockRestore() - } - }) - it('preserves empty, Unicode, backslash and quote budget estimates', () => { for (const args of [[], [''], ['🦀', 'é', '\\', '"'], ['a\\\\"b', 'plain']]) { expect(commandLineLength(args)).toBe(referenceCommandLineLength(args)) @@ -42,13 +30,6 @@ describe('windows command line budget', () => { } }) - it('matches the regex oracle across every BMP code unit', () => { - for (let unit = 0; unit <= 0xffff; unit += 1) { - const args = [String.fromCharCode(unit)] - expect(commandLineLength(args)).toBe(referenceCommandLineLength(args)) - } - }) - // The sparse/dense escape-count handover must preserve totals and its continuation index. it('counts the same on either side of the dense-escape switch', () => { for (const args of [ diff --git a/src/shared/workspace-cleanup-browse-state-persistence.test.ts b/src/shared/workspace-cleanup-browse-state-persistence.test.ts index 3d48dd1e806..411a62d45d4 100644 --- a/src/shared/workspace-cleanup-browse-state-persistence.test.ts +++ b/src/shared/workspace-cleanup-browse-state-persistence.test.ts @@ -11,11 +11,6 @@ function throughDisk(value: T): unknown { } describe('workspace cleanup browse state persistence', () => { - it('round-trips the default state unchanged', () => { - const state = createDefaultWorkspaceCleanupBrowseState() - expect(normalizeWorkspaceCleanupBrowseState(throughDisk(state))).toEqual(state) - }) - it('round-trips an edited state', () => { const state = createDefaultWorkspaceCleanupBrowseState() state.filters.query = 'checkout' diff --git a/src/shared/workspace-doc-history.test.ts b/src/shared/workspace-doc-history.test.ts index b2e0561e766..4632d97e1c1 100644 --- a/src/shared/workspace-doc-history.test.ts +++ b/src/shared/workspace-doc-history.test.ts @@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest' import { MAX_WORKSPACE_DOC_HISTORY_ENTRIES, normalizeWorkspaceDocHistoryEntries, - normalizeWorkspaceDocHistoryTitle, type WorkspaceDocHistoryEntry } from './workspace-doc-history' @@ -48,10 +47,6 @@ describe('normalizeWorkspaceDocHistoryEntries', () => { expect(entries[0]?.title).toBe('a.html') }) - it('title fence falls back to the file for empty titles', () => { - expect(normalizeWorkspaceDocHistoryTitle('', DOC)).toBe('a.html') - expect(normalizeWorkspaceDocHistoryTitle('Report', DOC)).toBe('Report') - }) it('indexes document identity while deduplicating a large legacy history', () => { let reads = 0 const entries = Array.from({ length: 10_000 }, (_, i) => diff --git a/src/shared/workspace-layout/workspace-layout-simulator-tab.test.ts b/src/shared/workspace-layout/workspace-layout-simulator-tab.test.ts index 3b846401f29..7534df65bf7 100644 --- a/src/shared/workspace-layout/workspace-layout-simulator-tab.test.ts +++ b/src/shared/workspace-layout/workspace-layout-simulator-tab.test.ts @@ -1,7 +1,7 @@ import { describe, expect, it } from 'vitest' import { applyLayoutCommand } from './workspace-layout-commands' import type { CommandOf } from './workspace-layout-command-types' -import { build, emptyModel, testContext, WS } from './workspace-layout-command.test-fixture' +import { build, testContext, WS } from './workspace-layout-command.test-fixture' const drawn = ( fields: Partial> = {} @@ -78,9 +78,4 @@ describe('a simulator tab a window drew', () => { ).model expect(closed.workspaces[WS]?.groups.map((group) => group.id)).toEqual([besideGroupId]) }) - - it('makes the workspace when main holds none', () => { - const { model } = build(testContext(), [drawn()], emptyModel()) - expect(model.workspaces[WS]?.groups).toHaveLength(1) - }) }) diff --git a/src/shared/workspace-linked-item-source-context.test.ts b/src/shared/workspace-linked-item-source-context.test.ts index aaff22d8155..3c77286fcf6 100644 --- a/src/shared/workspace-linked-item-source-context.test.ts +++ b/src/shared/workspace-linked-item-source-context.test.ts @@ -56,26 +56,6 @@ describe('workspace linked-item source context', () => { ).toBe(false) }) - it('keeps provider matching sufficient for non-Jira items', () => { - expect( - isWorkspaceLinkedItemSourceContextMatch( - { - provider: 'linear', - type: 'issue', - number: 0, - title: 'Linear item', - url: 'https://linear.app/acme/issue/ENG-1/item' - }, - { - kind: 'task-source', - provider: 'linear', - projectId: 'project-1', - hostId: 'local' - } - ) - ).toBe(true) - }) - it('infers GitHub/GitLab provider when TaskPage seeds omit provider', () => { expect( isWorkspaceLinkedItemSourceContextMatch( diff --git a/src/shared/workspace-view/workspace-view-options.test.ts b/src/shared/workspace-view/workspace-view-options.test.ts deleted file mode 100644 index bddd0901b8a..00000000000 --- a/src/shared/workspace-view/workspace-view-options.test.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { describe, expect, it } from 'vitest' -import { - getWorkspaceCardPropertiesValue, - getShownWorkspaceViewSections, - type WorkspaceViewOptionContext, - type WorkspaceViewOptionKey -} from './workspace-view-options' - -const LOCAL_ONLY: WorkspaceViewOptionContext = { - groupBy: 'none', - hideSleepingWorkspaces: false, - hideWorkspacesFromOtherDevices: false, - newCardStyle: false, - hasRemoteHosts: false, - projectCount: 1, - mayHaveServerHosts: false -} - -function shownKeys(overrides: Partial = {}): WorkspaceViewOptionKey[] { - return getShownWorkspaceViewSections({ ...LOCAL_ONLY, ...overrides }).flatMap(({ options }) => - options.map((option) => option.key) - ) -} - -describe('which Workspace options show', () => { - it('shows the base controls for a single local project', () => { - expect(shownKeys()).toEqual([ - 'groupBy', - 'sortBy', - 'cardLayout', - 'cardProperties', - 'hideSleepingWorkspaces', - 'hideDefaultBranchWorkspace', - 'hideAutomationGeneratedWorkspaces', - 'hideCliCreatedWorkspaces', - 'hideDetachedHeadWorkspaces' - ]) - }) - - it('shows the Show section for remote hosts and for more than one project', () => { - expect(shownKeys({ hasRemoteHosts: true }).slice(0, 2)).toEqual(['hosts', 'groupBy']) - expect(shownKeys({ projectCount: 2 }).slice(0, 2)).toEqual(['projects', 'groupBy']) - }) - - it('shows Project order only while grouping by project', () => { - expect(shownKeys({ groupBy: 'repo' })).toContain('projectOrderBy') - expect(shownKeys({ groupBy: 'pr-status' })).not.toContain('projectOrderBy') - }) - - it('shows the default-branch exemption only while sleeping workspaces are hidden', () => { - expect(shownKeys()).not.toContain('alwaysShowDefaultBranchWorkspace') - const keys = shownKeys({ hideSleepingWorkspaces: true }) - expect(keys.indexOf('alwaysShowDefaultBranchWorkspace')).toBe( - keys.indexOf('hideSleepingWorkspaces') + 1 - ) - }) - - it('shows the other-client filter when servers may exist, or while it is on', () => { - expect(shownKeys()).not.toContain('hideWorkspacesFromOtherDevices') - expect(shownKeys({ mayHaveServerHosts: true })).toContain('hideWorkspacesFromOtherDevices') - expect(shownKeys({ hideWorkspacesFromOtherDevices: true })).toContain( - 'hideWorkspacesFromOtherDevices' - ) - }) - - it('swaps Card layout and Show properties for Card display in the experimental card style', () => { - const keys = shownKeys({ newCardStyle: true }) - expect(keys).toContain('cardDisplay') - expect(keys).not.toContain('cardLayout') - expect(keys).not.toContain('cardProperties') - }) -}) - -describe('the Show properties value', () => { - it('reads Hover under the compact layout, else how many properties show, else nothing', () => { - expect(getWorkspaceCardPropertiesValue(['pr', 'host'], true)).toBe('hover') - expect(getWorkspaceCardPropertiesValue(['pr', 'host'], false)).toBe(2) - // Ids outside the Show properties list (Card display only) are not counted. - expect(getWorkspaceCardPropertiesValue(['cli', 'branch'], false)).toBeNull() - }) -}) diff --git a/src/shared/worktree-name-suggestion.test.ts b/src/shared/worktree-name-suggestion.test.ts index 73c15e1e583..d1377b31dc4 100644 --- a/src/shared/worktree-name-suggestion.test.ts +++ b/src/shared/worktree-name-suggestion.test.ts @@ -1,10 +1,6 @@ import { describe, expect, it } from 'vitest' import { MARINE_CREATURES } from './marine-creatures' -import { - normalizeSuggestedName, - selectSuggestedCreatureName, - suggestionPathBasename -} from './worktree-name-suggestion' +import { selectSuggestedCreatureName, suggestionPathBasename } from './worktree-name-suggestion' const pickFirst = () => 0 const lower = (index: number) => MARINE_CREATURES[index].toLowerCase() @@ -19,22 +15,10 @@ describe('suggestionPathBasename', () => { }) describe('selectSuggestedCreatureName', () => { - it('returns a name absent from the used set', () => { - // Check exclusion rather than a pool index that could pass without validating collisions. - const used = [lower(0), lower(1), lower(2)] - const suggested = selectSuggestedCreatureName(used) - expect(used).not.toContain(suggested) - }) - it('skips used names when picking the first available', () => { expect(selectSuggestedCreatureName([lower(0)], pickFirst)).toBe(lower(1)) }) - it('normalizes the used set so case and padding cannot smuggle a name back in', () => { - const suggested = selectSuggestedCreatureName([` ${MARINE_CREATURES[0].toUpperCase()} `]) - expect(suggested).not.toBe(lower(0)) - }) - it('degrades to a suffixed tier once every base name is spent', () => { const allUsed = MARINE_CREATURES.map((name) => name.toLowerCase()) expect(selectSuggestedCreatureName(allUsed, pickFirst)).toBe(`${lower(0)}-2`) @@ -65,16 +49,4 @@ describe('selectSuggestedCreatureName', () => { it('ignores a nonsense watermark rather than skipping the pool', () => { expect(selectSuggestedCreatureName([], pickFirst, -4)).toBe(lower(0)) }) - - it('returns a lowercase name to match branch convention', () => { - const suggested = selectSuggestedCreatureName([], pickFirst) - expect(suggested).toBe(suggested.toLowerCase()) - expect(MARINE_CREATURES).toContain(suggested.charAt(0).toUpperCase() + suggested.slice(1)) - }) -}) - -describe('normalizeSuggestedName', () => { - it('trims and lowercases', () => { - expect(normalizeSuggestedName(' Nautilus ')).toBe('nautilus') - }) }) diff --git a/src/shared/worktree/base-ref.test.ts b/src/shared/worktree/base-ref.test.ts index de87a1b0880..a808ab3cb0c 100644 --- a/src/shared/worktree/base-ref.test.ts +++ b/src/shared/worktree/base-ref.test.ts @@ -12,19 +12,6 @@ describe('resolveWorktreeAddBaseRef', () => { expect(refExists).not.toHaveBeenCalled() }) - it('leaves provider review refs unchanged', async () => { - const refExists = vi.fn() - - await expect(resolveWorktreeAddBaseRef('refs/pull/123/head', refExists)).resolves.toBe( - 'refs/pull/123/head' - ) - await expect( - resolveWorktreeAddBaseRef('refs/merge-requests/456/head', refExists) - ).resolves.toBe('refs/merge-requests/456/head') - - expect(refExists).not.toHaveBeenCalled() - }) - it('qualifies a bare local branch name', async () => { const refExists = vi.fn(async (ref: string) => ref === 'refs/heads/main') @@ -75,12 +62,6 @@ describe('worktreeBaseRefFamily', () => { expect(worktreeBaseRefFamily('refs/remotes/origin/release/24.1')).toBe('release/24.1') }) - it('separates different branches', () => { - expect(worktreeBaseRefFamily('refs/heads/main')).not.toBe( - worktreeBaseRefFamily('refs/heads/release') - ) - }) - it('has no family for anything that is not a branch ref', () => { expect(worktreeBaseRefFamily('abc1234')).toBeNull() expect(worktreeBaseRefFamily('main')).toBeNull()