mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 18:07:45 +00:00
test: remove 49 low-value test declarations (#37856)
This commit is contained in:
@@ -1005,7 +1005,7 @@
|
||||
2 test-no-wall-clock:src/main/windows/windows-pty-job.win32.test.ts
|
||||
1 test-no-wall-clock:src/main/workspaces/removal/worktree-removal-close-records.test.ts
|
||||
3 test-no-wall-clock:src/main/wsl/orcad/wsl-orcad-real-distro-lane.test.ts
|
||||
4 test-no-wall-clock:src/main/wsl/execution/wsl-runner.wsl.test.ts
|
||||
2 test-no-wall-clock:src/main/wsl/execution/wsl-runner.wsl.test.ts
|
||||
1 test-no-wall-clock:src/renderer/src/app-shell/visible-review-reporting.test.ts
|
||||
7 test-no-wall-clock:src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.behavior.test.tsx
|
||||
8 test-no-wall-clock:src/renderer/src/components/worktree-jump/WorktreeJumpPalette.recent-tabs.test.tsx
|
||||
@@ -1261,7 +1261,7 @@
|
||||
1 test-timeout-needs-reason:src/main/windows/windows-msys-job.win32.test.ts
|
||||
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/execution/wsl-runner.wsl.test.ts
|
||||
4 test-timeout-needs-reason:src/main/wsl/execution/wsl-runner.wsl.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
|
||||
|
||||
@@ -437,7 +437,6 @@
|
||||
"config/scripts/win-crash-survival-e2e.test.mjs": 565,
|
||||
"config/scripts/win32-test-lane-registration.test.mjs": 3507,
|
||||
"config/scripts/windows-bin-spawn-predicate.test.mjs": 125,
|
||||
"config/scripts/windows-cmd-shim-spawn-boundary.test.mjs": 2077,
|
||||
"config/scripts/windows-native-batch-reference-policy.test.ts": 363,
|
||||
"config/scripts/windows-native-preparation-benchmark.test.mjs": 284,
|
||||
"config/scripts/windows-native-toolchain-routing.test.mjs": 88,
|
||||
@@ -6780,7 +6779,6 @@
|
||||
"src/main/stats/agent-session-stats-feed.test.ts": 79,
|
||||
"src/main/stats/agent-session-transition-recorder.test.ts": 722,
|
||||
"src/main/stats/collector-async-save.test.ts": 497,
|
||||
"src/main/window/desktop-integration/system-fonts.test.ts": 77,
|
||||
"src/main/power/system-power-lifecycle.test.ts": 42,
|
||||
"src/main/power/system-resume-broadcast.test.ts": 67,
|
||||
"src/main/telemetry/burst-cap.test.ts": 177,
|
||||
@@ -8814,7 +8812,6 @@
|
||||
"src/renderer/src/components/settings/appearance/chat/AppearanceChatSection.test.tsx": 1633,
|
||||
"src/renderer/src/components/settings/appearance/AppearancePane.test.tsx": 2066,
|
||||
"src/renderer/src/components/settings/artifacts/ArtifactsSettingsPane.test.tsx": 862,
|
||||
"src/renderer/src/components/settings/automations/AutomationsSettingsPane.test.tsx": 602,
|
||||
"src/renderer/src/components/settings/browser/routing/BrowserClientHostedRemoteSetting.test.tsx": 841,
|
||||
"src/renderer/src/components/settings/browser/BrowserPane.search-catalog.test.tsx": 774,
|
||||
"src/renderer/src/components/settings/browser/profiles/BrowserProfileRow.google-cookie-clear.test.tsx": 27636,
|
||||
@@ -9054,7 +9051,6 @@
|
||||
"src/renderer/src/components/sidebar/WorktreeReferenceStack.test.tsx": 530,
|
||||
"src/renderer/src/components/sidebar/WorktreeTitleInlineRename.editor-lifecycle.test.tsx": 407,
|
||||
"src/renderer/src/components/sidebar/WorktreeVisibilityDialog.test.tsx": 2602,
|
||||
"src/renderer/src/components/sidebar/WorktreeWslHostStartMenuItem.test.tsx": 491,
|
||||
"src/renderer/src/components/sidebar/add-remote-host-ssh-actions.test.ts": 232,
|
||||
"src/renderer/src/components/sidebar/add-repo-browse-authority.test.ts": 57,
|
||||
"src/renderer/src/components/sidebar/add-repo-existing-workspaces-telemetry.test.ts": 52,
|
||||
|
||||
@@ -14,15 +14,6 @@ function runnerFor(job, os, fast, event = 'workflow_dispatch') {
|
||||
}).coerceString()
|
||||
}
|
||||
|
||||
it('defaults reusable and manual qualification to Blacksmith', () => {
|
||||
for (const trigger of ['workflow_call', 'workflow_dispatch']) {
|
||||
expect(workflow.on[trigger].inputs.fast_runners).toMatchObject({
|
||||
type: 'boolean',
|
||||
default: true
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
it.each([
|
||||
['ubuntu-22.04', 'blacksmith-8vcpu-ubuntu-2204'],
|
||||
['ubuntu-24.04-arm', 'blacksmith-8vcpu-ubuntu-2404-arm'],
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { beforeAll, describe, expect, it } from 'vitest'
|
||||
import { parse } from 'yaml'
|
||||
import {
|
||||
classifyOrcadTerminalSmokeChanges,
|
||||
collectOrcadTerminalSmokeInputs
|
||||
@@ -87,29 +85,3 @@ describe('the actual terminal smoke dependency graph', () => {
|
||||
).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
it('only skips the unchanged smoke after a successful diff and dependency analysis', () => {
|
||||
const workflow = parse(
|
||||
readFileSync(new URL('../../.github/workflows/pr.yml', import.meta.url), 'utf8')
|
||||
)
|
||||
const steps = workflow.jobs.preflight.steps
|
||||
const scope = steps.find((candidate) => candidate.id === 'orcad-smoke-scope')
|
||||
expect(scope.env).toEqual({ BASE_SHA: '${{ github.event.pull_request.base.sha }}' })
|
||||
// HEAD^1 bypasses merge-base lookup, permitting shallow checkout; payload head SHA is unused (see localization gate).
|
||||
expect(scope.run).toContain('node config/scripts/git-pull-request-diff-base.mjs "$BASE_SHA"')
|
||||
expect(scope.run).toContain('git diff --name-only --no-renames -z "$DIFF_BASE" HEAD')
|
||||
expect(scope.run).not.toContain('--diff-filter')
|
||||
expect(scope.run).toMatch(
|
||||
/&& \[ "\$scope" = false \]; then[\s\S]*run=false[\s\S]*else\s+echo 'run=true'/
|
||||
)
|
||||
// orcad refuses to build without the page, so the page builds exactly when the smoke runs.
|
||||
const gated = "steps.orcad-smoke-scope.outputs.run == 'true'"
|
||||
const page = steps.find(
|
||||
(candidate) => candidate.uses === './.github/actions/build-mobile-web-bundle'
|
||||
)
|
||||
const smoke = steps.find((candidate) => candidate.name === 'Boot orcad and round-trip a terminal')
|
||||
expect(page.if).toBe(gated)
|
||||
expect(smoke.if).toBe(gated)
|
||||
expect(smoke.run).toBe('pnpm run smoke:orcad-terminal')
|
||||
expect(steps.indexOf(page)).toBeLessThan(steps.indexOf(smoke))
|
||||
})
|
||||
|
||||
@@ -76,19 +76,6 @@ describe('release RC history', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps RC numbers monotonic after a stale tag is deleted', () => {
|
||||
withGitRepo((repo) => {
|
||||
commit(repo, 'initial')
|
||||
commit(repo, 'release: v1.4.36-rc.5')
|
||||
git(repo, ['tag', 'v1.4.36-rc.5'])
|
||||
commit(repo, 'release: v1.4.36-rc.6')
|
||||
git(repo, ['tag', 'v1.4.36-rc.6'])
|
||||
git(repo, ['tag', '--delete', 'v1.4.36-rc.6'])
|
||||
|
||||
expect(highestRcForBase('1.4.36', { cwd: repo })).toBe(6)
|
||||
})
|
||||
})
|
||||
|
||||
it('considers origin/main when releasing from an older ref', () => {
|
||||
withGitRepo((repo) => {
|
||||
commit(repo, 'initial')
|
||||
|
||||
@@ -37,39 +37,6 @@ describe('typecheck project coverage', () => {
|
||||
expect(tests.filter((file) => !project.files.has(resolve(root, file)))).toEqual([])
|
||||
})
|
||||
|
||||
it('assigns cross-process integrations and their producer fixture to the mixed project', () => {
|
||||
const files = [
|
||||
'src/renderer/src/components/task-page/linear/task-page-linear-detail-query.test.tsx',
|
||||
'src/renderer/src/components/terminal-pane/pty-agent-pane-launch.test.ts',
|
||||
'src/renderer/src/components/right-sidebar/SourceControlAgentActionDialog.picker.test.tsx',
|
||||
'src/renderer/src/components/github-item-dialog/load-item-details/work-item-details-target-contract.test.tsx',
|
||||
'src/renderer/src/runtime/observed-provider-accounts.test.tsx',
|
||||
'src/renderer/src/components/status-bar/ClaudeSwitcherMenu.observation.test.tsx',
|
||||
'src/renderer/src/components/status-bar/ClaudeSwitcherMenu.owner-lifetime.test.tsx',
|
||||
'src/renderer/src/runtime/provider-account-observation.test-fixture.ts'
|
||||
]
|
||||
for (const file of files) {
|
||||
expect(
|
||||
projects
|
||||
.filter((project) => project.files.has(resolve(root, file)))
|
||||
.map((project) => project.config),
|
||||
file
|
||||
).toEqual(['config/tsconfig.test.pane-launch.json'])
|
||||
}
|
||||
for (const config of ['config/tsconfig.web.json', 'config/tsconfig.tc.web.json']) {
|
||||
const parsed = ts.readConfigFile(resolve(root, config), ts.sys.readFile)
|
||||
expect(parsed.error).toBeUndefined()
|
||||
expect(parsed.config.exclude).toEqual(
|
||||
expect.arrayContaining(files.map((file) => `../${file}`))
|
||||
)
|
||||
}
|
||||
const combined = projects.find(
|
||||
(project) => project.config === 'config/tsconfig.test.pane-launch.json'
|
||||
)
|
||||
expect(combined.files.has(resolve(root, 'src/types/build-constants.d.ts'))).toBe(true)
|
||||
expect(combined.files.has(resolve(root, 'src/renderer/src/env.d.ts'))).toBe(true)
|
||||
})
|
||||
|
||||
it('checks every shared test exactly once, in the scheduled Node project', () => {
|
||||
const tests = typedFiles('src/shared').filter(isTest)
|
||||
expect(tests.length).toBeGreaterThan(0)
|
||||
|
||||
@@ -1,108 +0,0 @@
|
||||
import { readdirSync, readFileSync } from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { hasNodeModulesBinSpawn } from './windows-bin-spawn-predicate.mjs'
|
||||
import { hasWindowsNativeBatchReferenceViolation } from './windows-native-batch-reference-policy'
|
||||
|
||||
/**
|
||||
* Resolve package bins under process.execPath (see oxc-cli-invocation.mjs).
|
||||
* The legacy list only shrinks; reviewed native compiler references use process-host.
|
||||
* The literal check catches quoted .cmd/.bat paths, excluding drive letters and
|
||||
* templates; comment-only lines are dropped, but trailing comments fail closed.
|
||||
* The AST check catches spawn/spawnSync/execFile/execFileSync first arguments
|
||||
* containing node_modules/.bin: literals, templates, concatenation, join/resolve,
|
||||
* local variable initializers and ternaries. It does not follow imports, function
|
||||
* returns, assignments, destructuring, aliased spawn names or computed members.
|
||||
* Names are matched without scope/import resolution; shadowed names and non-path
|
||||
* join/resolve calls can fail closed. Package paths fold dot segments.
|
||||
* Neither check proves a Windows branch or an actual unsafe spawn.
|
||||
*/
|
||||
const WINDOWS_SHIM_LITERAL = /['"][\w./\\-]*\.(?:cmd|bat)['"]/gi
|
||||
|
||||
const SCANNED_ROOTS = ['config/scripts', 'tests/tools']
|
||||
|
||||
/** Scripts that still name a batch shim, held as data so it reads as the list it is. */
|
||||
const WINDOWS_SHIM_SPAWN_ALLOWLIST = [
|
||||
// Owns the pnpm invocation decision for every other script.
|
||||
'config/scripts/pnpm-cli-invocation.mjs',
|
||||
'config/scripts/pnpm-cli-invocation.test.mjs',
|
||||
// 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/live-remote-freeze-rpc.mjs',
|
||||
'config/scripts/pty-transcript-secret-scan.test.mjs',
|
||||
'config/scripts/remote-agent-session-authority-repro.mjs',
|
||||
// Platform-local build paths; the win32 branch is dead code on both.
|
||||
'config/scripts/build-mac-local.mjs',
|
||||
'config/scripts/build-linux-local.mjs',
|
||||
'config/scripts/build-linux-local.test.mjs',
|
||||
// Benchmarks, repros and e2e drivers — developer-invoked or Linux-only in CI.
|
||||
'config/scripts/run-ephemeral-vm-runtime-store-rollback-repro.mjs',
|
||||
'config/scripts/run-multi-client-navigation-e2e.mjs',
|
||||
'config/scripts/run-ssh-staged-upload-reliability.mjs',
|
||||
'config/scripts/run-terminal-ibus-hangul-e2e.mjs',
|
||||
'config/scripts/run-terminal-scale-perf-e2e.mjs',
|
||||
'tests/tools/benchmarks/startup-time-bench.mjs',
|
||||
'tests/tools/benchmarks/worktree-deletion-dev-bench.mjs',
|
||||
'tests/tools/repro-terminal-send-submit.mjs'
|
||||
]
|
||||
|
||||
/** Drop comment-only lines so prose about the old idiom is not an offender. */
|
||||
function codeText(contents) {
|
||||
return contents
|
||||
.split('\n')
|
||||
.filter((line) => !/^\s*(?:\/\/|\/\*|\*)/.test(line))
|
||||
.join('\n')
|
||||
}
|
||||
|
||||
// Why recursive: a future config/scripts/<subdir>/ would otherwise escape silently.
|
||||
function collectScripts(directory, repoRoot, found = []) {
|
||||
for (const entry of readdirSync(directory, { withFileTypes: true })) {
|
||||
const full = path.join(directory, entry.name)
|
||||
if (entry.isDirectory()) {
|
||||
if (entry.name !== 'node_modules') {
|
||||
collectScripts(full, repoRoot, found)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if (/\.[cm]?js$/.test(entry.name)) {
|
||||
found.push(path.relative(repoRoot, full).split(path.sep).join('/'))
|
||||
}
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
describe('windows batch shim spawn boundary', () => {
|
||||
const repoRoot = path.resolve(import.meta.dirname, '..', '..')
|
||||
const scripts = SCANNED_ROOTS.flatMap((root) =>
|
||||
collectScripts(path.join(repoRoot, root), repoRoot)
|
||||
)
|
||||
const offenders = scripts.filter((relativePath) => {
|
||||
const contents = readFileSync(path.join(repoRoot, relativePath), 'utf8')
|
||||
const literals = [...codeText(contents).matchAll(WINDOWS_SHIM_LITERAL)].map((match) =>
|
||||
match[0].slice(1, -1)
|
||||
)
|
||||
return (
|
||||
hasWindowsNativeBatchReferenceViolation(relativePath, contents, literals) ||
|
||||
hasNodeModulesBinSpawn(contents)
|
||||
)
|
||||
})
|
||||
|
||||
it('scans a plausible number of scripts', () => {
|
||||
// A broken root or extension filter would make the guard silently vacuous.
|
||||
expect(scripts.length).toBeGreaterThan(100)
|
||||
})
|
||||
|
||||
it('has no unlisted script naming a Windows batch shim or spawning a package bin shim', () => {
|
||||
const unlisted = offenders.filter((name) => !WINDOWS_SHIM_SPAWN_ALLOWLIST.includes(name))
|
||||
expect(
|
||||
unlisted,
|
||||
'Resolve package shims to their real executable. Fixed native compiler batch runners must pass the scoped process-host policy.'
|
||||
).toEqual([])
|
||||
})
|
||||
|
||||
it('has no stale allowlist entry', () => {
|
||||
const stale = WINDOWS_SHIM_SPAWN_ALLOWLIST.filter((name) => !offenders.includes(name))
|
||||
expect(stale, 'Script no longer matches either shim predicate — delete the line.').toEqual([])
|
||||
})
|
||||
})
|
||||
@@ -1,10 +1,6 @@
|
||||
import { readFileSync } from 'node:fs'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { parse } from 'yaml'
|
||||
import { hasWslSourceChange, selectPrE2eSpecs } from './pr-e2e-source-routing.mjs'
|
||||
|
||||
const read = (path) => readFileSync(new URL(`../../${path}`, import.meta.url), 'utf8')
|
||||
|
||||
describe('real WSL terminal lane', () => {
|
||||
it.each([
|
||||
'config/scripts/verify-wsl-e2e-participation.mjs',
|
||||
@@ -40,44 +36,4 @@ describe('real WSL terminal lane', () => {
|
||||
])('excludes unrelated or unit-only change %s', (path) => {
|
||||
expect(hasWslSourceChange([path])).toBe(false)
|
||||
})
|
||||
|
||||
it('runs the reusable lane at the immutable PR head', () => {
|
||||
const pr = parse(read('.github/workflows/pr.yml'))
|
||||
expect(pr.jobs.windows_wsl.if).toBe("needs.code_paths.outputs.wsl_source_changed == 'true'")
|
||||
expect(pr.jobs.windows_wsl.with.ref).toBe('${{ github.event.pull_request.head.sha }}')
|
||||
const detector = pr.jobs['code_paths'].steps.find(
|
||||
(step) => step.name === 'Filter changed E2E specs'
|
||||
)
|
||||
expect(detector.run).toContain(
|
||||
'WSL_CHANGED="$(git diff --name-only --no-renames --diff-filter=ACDMR'
|
||||
)
|
||||
expect(detector.run).toContain(
|
||||
'"$WSL_CHANGED" | node config/scripts/pr-e2e-source-routing.mjs --wsl-source'
|
||||
)
|
||||
const workflow = parse(read('.github/workflows/windows-wsl-e2e.yml'))
|
||||
const steps = workflow.jobs['wsl-terminal'].steps
|
||||
expect(steps[0].with.ref).toBe('${{ inputs.ref || github.sha }}')
|
||||
expect(steps.some((step) => step.uses === './.github/actions/setup-wsl-test-runtime')).toBe(
|
||||
true
|
||||
)
|
||||
const exercise = steps.find((step) => step.name === 'Exercise real WSL launch and paste')
|
||||
expect(exercise.run.split(/\s+/).filter((arg) => arg.startsWith('--repeat-each='))).toEqual([
|
||||
'--repeat-each=3'
|
||||
])
|
||||
expect(exercise.run).toContain('--grep "WSL"')
|
||||
const receipt = steps.find((step) => step.name === 'Require all nine WSL executions')
|
||||
expect(receipt.if).toBe('always()')
|
||||
expect(receipt.run).toBe(
|
||||
'node config/scripts/verify-wsl-e2e-participation.mjs test-results/wsl-results.json'
|
||||
)
|
||||
// E9: the guard terminates only the distro this job imported, and must prove it ran.
|
||||
const guard = steps.find(
|
||||
(step) => step.name === 'Guard that background work never starts the stopped WSL distro'
|
||||
)
|
||||
expect(guard.env.ORCA_E2E_WSL_TERMINATE_DISTRO).toBe('Ubuntu')
|
||||
expect(guard.run).toContain('tests/e2e/wsl-bridge-no-background-boot.spec.ts')
|
||||
expect(guard.run).toContain('--repeat-each=3')
|
||||
const guardReceipt = steps.find((step) => step.name === 'Require all three E9 guard executions')
|
||||
expect(guardReceipt.if).toBe('always()')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -58,15 +58,6 @@ describe('formatAutomationShow reports the host the authority projects', () => {
|
||||
expect(output).toContain('target: ssh:box-1')
|
||||
})
|
||||
|
||||
it('names the local host for a self-owned automation', () => {
|
||||
const output = formatAutomationShow({
|
||||
automation: automation({ executionTargetType: 'local', executionTargetId: 'local' }),
|
||||
owner: { selector: { kind: 'self' } }
|
||||
})
|
||||
|
||||
expect(output).toContain('host: self')
|
||||
})
|
||||
|
||||
it('omits the host line when the authority reports no owner', () => {
|
||||
const output = formatAutomationShow({ automation: automation() })
|
||||
|
||||
@@ -76,16 +67,6 @@ describe('formatAutomationShow reports the host the authority projects', () => {
|
||||
})
|
||||
|
||||
describe('formatAutomationShow reports the saved setup choice', () => {
|
||||
it.each([
|
||||
['run', 'setup: run'],
|
||||
['skip', 'setup: skip'],
|
||||
[undefined, 'setup: not set']
|
||||
] as const)('shows saved %s as %s for new-per-run automations', (setupDecision, line) => {
|
||||
const output = formatAutomationShow({ automation: automation({ setupDecision }) })
|
||||
|
||||
expect(output.split('\n')).toContain(line)
|
||||
})
|
||||
|
||||
it('omits setup for existing-workspace automations', () => {
|
||||
const output = formatAutomationShow({
|
||||
automation: automation({ workspaceMode: 'existing', workspaceId: 'wt-1' })
|
||||
|
||||
@@ -82,37 +82,4 @@ describe('orchestration check identity', () => {
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('preserves the pinned legacy --inject check signature', async () => {
|
||||
process.env.ORCA_TERMINAL_HANDLE = 'term_legacy_worker'
|
||||
|
||||
await invokeCheck(
|
||||
new Map<string, string | boolean>([
|
||||
['unread', true],
|
||||
['inject', true]
|
||||
])
|
||||
)
|
||||
|
||||
expect(callMock).toHaveBeenCalledWith(
|
||||
'orchestration.check',
|
||||
expect.objectContaining({
|
||||
terminal: 'term_legacy_worker',
|
||||
unread: true,
|
||||
inject: true
|
||||
})
|
||||
)
|
||||
})
|
||||
|
||||
it('surfaces a stale --terminal refusal instead of an empty inbox', async () => {
|
||||
callMock.mockRejectedValue(
|
||||
Object.assign(new Error('Terminal term_gone has no live pane bound to a Run'), {
|
||||
code: 'stable_pane_required'
|
||||
})
|
||||
)
|
||||
|
||||
await expect(
|
||||
invokeCheck(new Map<string, string | boolean>([['terminal', 'term_gone']]))
|
||||
).rejects.toMatchObject({ code: 'stable_pane_required' })
|
||||
expect(printResultMock).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -60,22 +60,6 @@ describe('orca plugin create templates', () => {
|
||||
}
|
||||
)
|
||||
|
||||
it('components writes a build-less TSX panel and its gitignored typings', async () => {
|
||||
const dir = join(await tempRoot(), 'todo-panel')
|
||||
const created = await createPluginFromTemplate({ dir, template: 'components' })
|
||||
expect(created.files).toEqual(
|
||||
expect.arrayContaining(['orca-plugin.json', 'src/panel.tsx', 'tsconfig.json', '.gitignore'])
|
||||
)
|
||||
expect(created.files.some((file) => file.startsWith('dist/') || file.includes('build'))).toBe(
|
||||
false
|
||||
)
|
||||
expect(created.typeFiles).toContain('.orca/types/orca/index.d.ts')
|
||||
expect(JSON.parse(await readFile(join(dir, 'tsconfig.json'), 'utf8')).extends).toBe(
|
||||
'./.orca/types/tsconfig.json'
|
||||
)
|
||||
expect(await readFile(join(dir, '.gitignore'), 'utf8')).toContain('.orca/')
|
||||
})
|
||||
|
||||
it('refuses a non-empty folder and never overwrites', async () => {
|
||||
const dir = await tempRoot()
|
||||
await writeFile(join(dir, 'keep.txt'), 'mine')
|
||||
|
||||
@@ -72,21 +72,6 @@ describe('orchestration recovery command identity', () => {
|
||||
])
|
||||
})
|
||||
|
||||
it.each([
|
||||
[
|
||||
'gate-create',
|
||||
'orchestration.gateCreate',
|
||||
['orchestration', 'gate-create', '--task', 'task_1', '--question', 'ship?']
|
||||
],
|
||||
[
|
||||
'worker-retain',
|
||||
'orchestration.workerRetain',
|
||||
['orchestration', 'worker-retain', '--dispatch', 'dispatch_1', '--json']
|
||||
]
|
||||
] as const)('preserves exact raw argv for %s recovery', (_name, method, args) => {
|
||||
expect(buildOrchestrationRecoveryCommand(method, {}, 'orca', args)).toEqual(['orca', ...args])
|
||||
})
|
||||
|
||||
it.each([
|
||||
['split', ['orchestration', 'send', '--pairing-code', 'secret', '--subject', 'status']],
|
||||
['equals', ['orchestration', 'send', '--pairing-code=secret', '--subject', 'status']],
|
||||
|
||||
@@ -18,11 +18,7 @@ vi.mock('../wsl/execution/wsl-executable-path', () => ({
|
||||
resolveWslExecutablePath: () => 'C:\\Windows\\System32\\wsl.exe'
|
||||
}))
|
||||
|
||||
import {
|
||||
buildGuestLaunchScript,
|
||||
resolveWslHookRelayBundle,
|
||||
spawnWslRelayProcess
|
||||
} from './wsl-hook-relay-launch'
|
||||
import { spawnWslRelayProcess } from './wsl-hook-relay-launch'
|
||||
import { orcadPosixNodeRuntimeGlobs } from '../managed-server/install/orcad-node-runtime-globs'
|
||||
|
||||
describe('spawnWslRelayProcess', () => {
|
||||
@@ -57,14 +53,6 @@ describe('spawnWslRelayProcess', () => {
|
||||
})
|
||||
|
||||
describe('buildGuestLaunchScript', () => {
|
||||
it('falls back to orcad pinned runtimes only after every system node candidate', () => {
|
||||
const forLine = buildGuestLaunchScript('1.2.3')
|
||||
.split('\n')
|
||||
.find((line) => line.startsWith('for c in '))
|
||||
const [orcadRuntime, orcadMachineRuntimes] = orcadPosixNodeRuntimeGlobs()
|
||||
expect(forLine).toContain(`"$HOME/.local/bin/node" ${orcadRuntime} ${orcadMachineRuntimes}; do`)
|
||||
})
|
||||
|
||||
it.skipIf(process.platform === 'win32')(
|
||||
'expands the orcad runtime globs to the store and machine-home runtimes',
|
||||
() => {
|
||||
@@ -94,19 +82,3 @@ describe('buildGuestLaunchScript', () => {
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
describe('resolveWslHookRelayBundle', () => {
|
||||
it('stamps the launcher revision so a launcher change gets a fresh guest dir', () => {
|
||||
const relayRoot = mkdtempSync(join(tmpdir(), 'wsl-relay-bundle-'))
|
||||
vi.stubEnv('ORCA_RELAY_PATH', relayRoot)
|
||||
try {
|
||||
mkdirSync(join(relayRoot, 'wsl'))
|
||||
writeFileSync(join(relayRoot, 'wsl', 'wsl-agent-hook-relay.js'), '')
|
||||
writeFileSync(join(relayRoot, 'wsl', '.version'), '0.1.0+abc\n')
|
||||
expect(resolveWslHookRelayBundle()?.version).toMatch(/^0\.1\.0\+abc\.[0-9a-f]{8}$/)
|
||||
} finally {
|
||||
vi.unstubAllEnvs()
|
||||
rmSync(relayRoot, { recursive: true, force: true })
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { mkdtemp, rm, stat, writeFile } from 'node:fs/promises'
|
||||
import { mkdtemp, rm, stat } from 'node:fs/promises'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, expect, it } from 'vitest'
|
||||
@@ -8,12 +8,8 @@ import {
|
||||
resetSessionParseCachePersistenceForTests
|
||||
} from './session-parse-cache-persistence'
|
||||
import { createSessionParseStats, parseAgentSessionFileCached } from './session-scanner-parse-cache'
|
||||
import {
|
||||
resetSessionParseCacheForTests,
|
||||
getSessionParseCacheEntry
|
||||
} from './session-parse-cache-store'
|
||||
import { resetSessionParseCacheForTests } from './session-parse-cache-store'
|
||||
|
||||
import { createAntigravityWorkspaceResolver } from '../scanners/antigravity/session-scanner-antigravity-history'
|
||||
import { writeAntigravityTranscript } from '../session-scanner-test-fixtures'
|
||||
import type { SessionFileCandidate } from '../session-scanner-types'
|
||||
|
||||
@@ -51,40 +47,6 @@ async function candidate(): Promise<SessionFileCandidate> {
|
||||
}
|
||||
}
|
||||
|
||||
it('reparses an unchanged pre-fix cached Antigravity transcript after an update', async () => {
|
||||
const input = await candidate()
|
||||
await parseAgentSessionFileCached(input, 'linux')
|
||||
const {
|
||||
resume: _resume,
|
||||
foldSession: _fold,
|
||||
...entry
|
||||
} = getSessionParseCacheEntry(input.file.path)!
|
||||
const staleSession = entry.session && { ...entry.session, antigravityOpeningPrompt: undefined }
|
||||
const entries = [[input.file.path, { ...entry, session: staleSession }]]
|
||||
const cacheFile = join(root ?? '', 'cache.json')
|
||||
await writeFile(cacheFile, JSON.stringify({ schemaVersion: 3, appVersion: 'pre-fix', entries }))
|
||||
resetSessionParseCacheForTests()
|
||||
initSessionParseCachePersistence({ filePath: cacheFile, appVersion: 'fixed' })
|
||||
const stats = createSessionParseStats()
|
||||
const session = await parseAgentSessionFileCached(input, 'linux', stats)
|
||||
expect(stats.fullParses).toBe(1)
|
||||
expect(stats.reused).toBe(0)
|
||||
if (!session) {
|
||||
throw new Error('Missing reparsed session')
|
||||
}
|
||||
expect(session.previewMessagesTruncated).toBe(true)
|
||||
const resolver = createAntigravityWorkspaceResolver(async (path) =>
|
||||
path === 'history.jsonl'
|
||||
? JSON.stringify({
|
||||
display: 'Original request',
|
||||
timestamp: Date.parse('2026-07-15T11:39:10Z'),
|
||||
workspace: '/repo/original'
|
||||
})
|
||||
: null
|
||||
)
|
||||
expect((await resolver.enrich(session, 'history.jsonl')).cwd).toBe('/repo/original')
|
||||
})
|
||||
|
||||
it('retains the opening identity in current caches without retaining full prompt text', async () => {
|
||||
const input = await candidate()
|
||||
const cacheFile = join(root ?? '', 'cache.json')
|
||||
|
||||
@@ -91,13 +91,6 @@ describe('Claude descendant forced-sweep fence', () => {
|
||||
expect(killedPids(calls)).toEqual([...EARLIER_BORN, ...WALK_SECOND_BORN])
|
||||
})
|
||||
|
||||
it('still escalates descendants born before the walk that first saw them', async () => {
|
||||
const onlyEarlier = [{ pids: EARLIER_BORN, startedAt: EARLIER_SECOND }]
|
||||
const calls = await sweep([walk(WALK_MS + 42, onlyEarlier)], onlyEarlier)
|
||||
|
||||
expect(killedPids(calls)).toEqual(EARLIER_BORN)
|
||||
})
|
||||
|
||||
it('withholds the sweep from a row no walk re-derived, on its start second alone', async () => {
|
||||
const retained = { pids: [900], startedAt: WALK_SECOND }
|
||||
const firstWalk = walk(WALK_MS + 42, [...LIVE_TREE, retained])
|
||||
|
||||
@@ -102,10 +102,6 @@ describe('startup device attributes responder', () => {
|
||||
expect(registered).toHaveLength(0)
|
||||
expect(replies).toEqual([])
|
||||
})
|
||||
|
||||
it('reports the same primary attributes the renderer would, so consuming the query is transparent', () => {
|
||||
expect(STARTUP_DA1_RESPONSE).toBe('\x1b[?1;2c')
|
||||
})
|
||||
})
|
||||
|
||||
describe('startup device attributes query filter', () => {
|
||||
|
||||
@@ -68,45 +68,6 @@ describe('TerminalHost startup command delivery logging', () => {
|
||||
})
|
||||
})
|
||||
|
||||
const delivery = (): Record<string, unknown> =>
|
||||
events.find((e) => e.event === 'startup-command-delivery')?.details ?? {}
|
||||
|
||||
it('records a written startup command', async () => {
|
||||
await host.createOrAttach({
|
||||
sessionId: 'delivery-written',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
command: 'codex',
|
||||
shellReadySupported: false,
|
||||
streamClient: { onData: vi.fn(), onExit: vi.fn() }
|
||||
})
|
||||
expect(delivery()).toMatchObject({ written: true, hasCommand: true, commandLength: 5 })
|
||||
})
|
||||
|
||||
it('records a session created with no startup command at all', async () => {
|
||||
await host.createOrAttach({
|
||||
sessionId: 'delivery-none',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
shellReadySupported: false,
|
||||
streamClient: { onData: vi.fn(), onExit: vi.fn() }
|
||||
})
|
||||
expect(delivery()).toMatchObject({ written: false, hasCommand: false, commandLength: 0 })
|
||||
expect(sub.write).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('never logs the command text, which can carry credentials', async () => {
|
||||
await host.createOrAttach({
|
||||
sessionId: 'delivery-secret',
|
||||
cols: 80,
|
||||
rows: 24,
|
||||
command: 'deploy --token=hunter2',
|
||||
shellReadySupported: false,
|
||||
streamClient: { onData: vi.fn(), onExit: vi.fn() }
|
||||
})
|
||||
expect(JSON.stringify(delivery())).not.toContain('hunter2')
|
||||
})
|
||||
|
||||
it('still delivers the command when the diagnostic sink throws', async () => {
|
||||
host = new TerminalHost({
|
||||
spawnSubprocess: () => sub,
|
||||
|
||||
@@ -84,16 +84,6 @@ describe('Git command tree termination', () => {
|
||||
await pending
|
||||
expect(child.kill).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('preserves handle termination on POSIX', async () => {
|
||||
Object.defineProperty(process, 'platform', { value: 'linux', configurable: true })
|
||||
const child = childWithPid(1234)
|
||||
|
||||
await killSpawnedCommandTree(child)
|
||||
|
||||
expect(child.kill).toHaveBeenCalledOnce()
|
||||
expect(spawnMock).not.toHaveBeenCalled()
|
||||
})
|
||||
it.skipIf(originalPlatform !== 'win32').each([0, 128])(
|
||||
'does not taskkill an actual native Windows child after exit %i',
|
||||
async (exitCode) => {
|
||||
|
||||
@@ -27,11 +27,8 @@ vi.mock('../../../workspaces/catalog/worktree-lineage-pruning', () => ({
|
||||
pruneLineageForMissingRepoWorktrees: vi.fn()
|
||||
}))
|
||||
|
||||
const {
|
||||
__resetDetectedWorktreeScanCacheForTests,
|
||||
applyFreshDetectedWorktreeScanSideEffects,
|
||||
listDetectedGitWorktrees
|
||||
} = await import('./detected-worktree-scan-cache')
|
||||
const { __resetDetectedWorktreeScanCacheForTests, listDetectedGitWorktrees } =
|
||||
await import('./detected-worktree-scan-cache')
|
||||
const { WslDistroStoppedError } = await import('../../../wsl/filesystem/wsl-unc-access-gate')
|
||||
|
||||
const repo: Repo = {
|
||||
@@ -41,46 +38,9 @@ const repo: Repo = {
|
||||
badgeColor: '#000',
|
||||
addedAt: 0
|
||||
}
|
||||
const worktree = { path: '/repos/one-feature', head: 'abc', branch: 'feature', isBare: false }
|
||||
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: a first local scan reads only this store method; routing, listing and registration are mocked.
|
||||
const store = { captureNativeLocalWorktreeMetadataScanExpectation: vi.fn() } as unknown as Store
|
||||
|
||||
async function scanAndRegister(): Promise<void> {
|
||||
const scan = await listDetectedGitWorktrees(store, repo)
|
||||
await applyFreshDetectedWorktreeScanSideEffects(store, repo, scan.gitWorktrees, undefined, {
|
||||
sideEffectToken: scan.sideEffectToken,
|
||||
hygieneDue: false
|
||||
})
|
||||
}
|
||||
|
||||
describe('detected worktree scan root registration', () => {
|
||||
beforeEach(() => {
|
||||
vi.resetAllMocks()
|
||||
mocks.list.mockResolvedValue([{ ...worktree, isMainWorktree: false }])
|
||||
__resetDetectedWorktreeScanCacheForTests()
|
||||
})
|
||||
|
||||
it('records the distro whose Git listed the scan', async () => {
|
||||
mocks.gitOptions.mockReturnValue({ wslDistro: 'Ubuntu-24.04' })
|
||||
await scanAndRegister()
|
||||
|
||||
expect(mocks.registerRoots).toHaveBeenCalledWith(
|
||||
store,
|
||||
repo,
|
||||
[repo.path, worktree.path],
|
||||
expect.objectContaining({ wslDistro: 'Ubuntu-24.04' })
|
||||
)
|
||||
})
|
||||
|
||||
it('records host Git for a scan listed without a distro', async () => {
|
||||
mocks.gitOptions.mockReturnValue({})
|
||||
await scanAndRegister()
|
||||
|
||||
expect(mocks.registerRoots).toHaveBeenCalledTimes(1)
|
||||
expect(mocks.registerRoots.mock.calls[0]?.[3]?.wslDistro).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
// A stopped distro fails the scan as unavailable, so rows are kept, instead of booting it (E9).
|
||||
describe('detected worktree scan for a stopped WSL distro', () => {
|
||||
const originalPlatform = Object.getOwnPropertyDescriptor(process, 'platform')
|
||||
|
||||
@@ -104,14 +104,6 @@ describe('panel storage and settings', () => {
|
||||
expect(panels.dataChanged).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('tells panels and the worker after a write lands', async () => {
|
||||
const panels = bridge()
|
||||
await expect(
|
||||
call('storage.set', { key: 'todos', value: [1] }, { panels })
|
||||
).resolves.toMatchObject({ ok: true })
|
||||
expect(panels.dataChanged).toHaveBeenCalledWith('acme.todos', 'storage', 'todos')
|
||||
})
|
||||
|
||||
it('keeps the capability gate for panels', async () => {
|
||||
await expect(call('storage.get', { key: 'todos' }, { grants: [] })).resolves.toMatchObject({
|
||||
code: 'capability_denied'
|
||||
|
||||
@@ -4,10 +4,7 @@ import type { ValidDiscoveredPlugin } from '../plugin-discovery'
|
||||
import type { PluginWorkerHandle } from './plugin-host-process'
|
||||
import { PluginWorkerManager } from './plugin-worker-manager'
|
||||
import { buildPluginWorkerSpawnSpec } from './plugin-worker-spawn-spec'
|
||||
import {
|
||||
createPluginResidentWorkerWarmer,
|
||||
pluginNeedsResidentWorker
|
||||
} from './plugin-resident-worker'
|
||||
import { createPluginResidentWorkerWarmer } from './plugin-resident-worker'
|
||||
|
||||
function plugin(
|
||||
pluginKey: string,
|
||||
@@ -53,15 +50,6 @@ function worker(): PluginWorkerHandle {
|
||||
const meter = { statusBarItems: [{ id: 'usage' }] }
|
||||
|
||||
describe('resident plugin workers', () => {
|
||||
it('needs a resident worker for hooks or status bar items, only with a worker entry', () => {
|
||||
expect(pluginNeedsResidentWorker(plugin('a', meter).manifest)).toBe(true)
|
||||
expect(
|
||||
pluginNeedsResidentWorker(plugin('a', { hooks: [{ event: 'terminal.send' }] }).manifest)
|
||||
).toBe(true)
|
||||
expect(pluginNeedsResidentWorker(plugin('a', {}).manifest)).toBe(false)
|
||||
expect(pluginNeedsResidentWorker(plugin('a', meter, { main: false }).manifest)).toBe(false)
|
||||
})
|
||||
|
||||
it('starts a status bar plugin once per approved revision while it is enabled', () => {
|
||||
let plugins = [plugin('acme.meter', meter), plugin('acme.plain', {})]
|
||||
const enabled = new Set(['acme.meter', 'acme.plain'])
|
||||
|
||||
@@ -104,14 +104,6 @@ describe('dropIncoherentCondaActivationEnv', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('leaves an environment with no conda state alone', () => {
|
||||
const env: Record<string, string> = { PATH: '/usr/bin', HOME: '/home/dev' }
|
||||
|
||||
dropIncoherentCondaActivationEnv(env, 'linux')
|
||||
|
||||
expect(env).toEqual({ PATH: '/usr/bin', HOME: '/home/dev' })
|
||||
})
|
||||
|
||||
it('ignores a non-numeric sentinel rather than guessing', () => {
|
||||
const env: Record<string, string> = { CONDA_SHLVL: 'weird', CONDA_DEFAULT_ENV: 'base' }
|
||||
|
||||
|
||||
@@ -17,10 +17,7 @@ vi.mock('../github/client', async (importOriginal) => ({
|
||||
getPRForBranch: getPRForBranchMock
|
||||
}))
|
||||
|
||||
import {
|
||||
canCheckoutExistingLocalBranch,
|
||||
getLocalGitHubPrForBranch
|
||||
} from './runtime-worktree-create-git'
|
||||
import { canCheckoutExistingLocalBranch } from './runtime-worktree-create-git'
|
||||
|
||||
beforeEach(() => {
|
||||
getPRForBranchMock.mockReset()
|
||||
@@ -99,19 +96,3 @@ describe('explicit local branch reuse on the execution host', () => {
|
||||
expect(worktrees).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
describe('getLocalGitHubPrForBranch', () => {
|
||||
it('routes the PR lookup through the WSL distro', async () => {
|
||||
await getLocalGitHubPrForBranch('/repo', 'app', { wslDistro: 'Ubuntu' })
|
||||
|
||||
expect(getPRForBranchMock).toHaveBeenCalledWith('/repo', 'app', null, null, null, {
|
||||
localGitExecOptions: { wslDistro: 'Ubuntu' }
|
||||
})
|
||||
})
|
||||
|
||||
it('uses the plain lookup without project git options', async () => {
|
||||
await getLocalGitHubPrForBranch('/repo', 'app', {})
|
||||
|
||||
expect(getPRForBranchMock).toHaveBeenCalledWith('/repo', 'app')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,7 +5,6 @@ import { tmpdir } from 'node:os'
|
||||
import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { CLAUDE_STRUCTURED_BASE_OPTIONS } from '../claude/structured/launch/claude-structured-launch-resolution'
|
||||
import { fakeClaude } from '../claude/structured/claude-structured-session-test-support'
|
||||
import {
|
||||
CLAUDE_THINKING_DISPLAY_FLAG,
|
||||
createClaudeCliFlagSupport
|
||||
@@ -79,29 +78,6 @@ describe('a Claude CLI that refuses the thinking-display flag', () => {
|
||||
expect(probe).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('hands the session whether its close was the one Orca began', async () => {
|
||||
const claude = fakeClaude()
|
||||
const support = createClaudeCliFlagSupport({
|
||||
probe: async () => '2.1.280',
|
||||
keyOf: async () => null,
|
||||
budgetMs: 1_000,
|
||||
now: () => performance.now()
|
||||
})
|
||||
const { openConnection } = openClaudeConnectionOf({
|
||||
claudeCliFlags: support,
|
||||
openClaudeConnection: claude.openConnection
|
||||
})
|
||||
const onExit = vi.fn()
|
||||
await openConnection!(
|
||||
{ pathToClaudeCodeExecutable: FAKE_CLI, options: {}, cwd: '/w' },
|
||||
{ onExit }
|
||||
)
|
||||
const exited = new Error('closed')
|
||||
claude.connections[0]!.handlers.onExit?.(exited, { expected: true })
|
||||
// Without it, a Stop's own exit would read as the child exiting on its own.
|
||||
expect(onExit).toHaveBeenCalledWith(exited, { expected: true })
|
||||
})
|
||||
|
||||
it('records nothing when the start failed for another reason', async () => {
|
||||
const { support, launch } = await startRefusing('claude: not signed in\n')
|
||||
await expect(support.check(CLAUDE_THINKING_DISPLAY_FLAG, launch)).resolves.toBe('supported')
|
||||
|
||||
@@ -3,12 +3,8 @@ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
const runWslProcessMock = vi.hoisted(() => vi.fn())
|
||||
vi.mock('../wsl/execution/wsl-runner', () => ({ runWslProcess: runWslProcessMock }))
|
||||
|
||||
import { SKILL_INSTALL_PROVIDERS } from '../../shared/skill-install-providers'
|
||||
import { getTuiAgentDetectCommands, TUI_AGENT_CONFIG } from '../../shared/tui-agent-config'
|
||||
import { detectSkillProvidersInWsl } from './skill-wsl-provider-detection'
|
||||
|
||||
type RunWslProcessSpec = { distro: string; loginPath: string; script: string }
|
||||
|
||||
describe('detectSkillProvidersInWsl', () => {
|
||||
beforeEach(() => {
|
||||
runWslProcessMock.mockReset()
|
||||
@@ -18,24 +14,6 @@ describe('detectSkillProvidersInWsl', () => {
|
||||
vi.restoreAllMocks()
|
||||
})
|
||||
|
||||
it('asks for the login PATH so a nvm/mise-only install is still found (regression)', async () => {
|
||||
// Without login-shell PATH, nvm-installed agents look absent under bare sh -c.
|
||||
runWslProcessMock.mockResolvedValue({
|
||||
environmentResolved: true,
|
||||
code: 0,
|
||||
stdout: 'codex\n',
|
||||
stderr: '',
|
||||
timedOut: false
|
||||
})
|
||||
|
||||
const found = await detectSkillProvidersInWsl('Ubuntu')
|
||||
|
||||
const [spec] = runWslProcessMock.mock.calls.at(-1) as [RunWslProcessSpec]
|
||||
expect(spec.loginPath).toBe('preferred')
|
||||
expect(spec.distro).toBe('Ubuntu')
|
||||
expect(found).toEqual(['codex'])
|
||||
})
|
||||
|
||||
it('parses both providers when present', async () => {
|
||||
runWslProcessMock.mockResolvedValue({
|
||||
environmentResolved: true,
|
||||
@@ -50,26 +28,6 @@ describe('detectSkillProvidersInWsl', () => {
|
||||
expect(found.toSorted()).toEqual(['claude', 'codex'])
|
||||
})
|
||||
|
||||
it('probes every install provider by the commands Orca detects it with', async () => {
|
||||
runWslProcessMock.mockResolvedValue({
|
||||
environmentResolved: true,
|
||||
code: 0,
|
||||
stdout: 'cursor-agent\n',
|
||||
stderr: '',
|
||||
timedOut: false
|
||||
})
|
||||
|
||||
const found = await detectSkillProvidersInWsl('Ubuntu')
|
||||
|
||||
const [spec] = runWslProcessMock.mock.calls.at(-1) as [RunWslProcessSpec]
|
||||
for (const provider of SKILL_INSTALL_PROVIDERS) {
|
||||
for (const command of getTuiAgentDetectCommands(TUI_AGENT_CONFIG[provider.id])) {
|
||||
expect(spec.script, provider.id).toContain(`'${command}'`)
|
||||
}
|
||||
}
|
||||
expect(found).toEqual(['cursor'])
|
||||
})
|
||||
|
||||
it('ignores stray output that is not a recognized provider name', async () => {
|
||||
runWslProcessMock.mockResolvedValue({
|
||||
environmentResolved: true,
|
||||
|
||||
@@ -1,124 +0,0 @@
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
|
||||
import type { ProcessResult, ProcessSpec } from '@orca/process-host/process-spec'
|
||||
|
||||
const { runProcessMock } = vi.hoisted(() => ({
|
||||
runProcessMock: vi.fn<(spec: ProcessSpec) => Promise<ProcessResult>>()
|
||||
}))
|
||||
|
||||
// Verify discovery's process options; spawning and console hiding belong to runProcess.
|
||||
vi.mock('@orca/process-host', () => ({
|
||||
runProcess: runProcessMock
|
||||
}))
|
||||
|
||||
const ok = (stdout: string): ProcessResult => ({
|
||||
code: 0,
|
||||
signal: null,
|
||||
stdout,
|
||||
stderr: '',
|
||||
timedOut: false
|
||||
})
|
||||
|
||||
const timedOut: ProcessResult = {
|
||||
code: null,
|
||||
signal: 'SIGTERM',
|
||||
stdout: '',
|
||||
stderr: '',
|
||||
timedOut: true
|
||||
}
|
||||
|
||||
async function withPlatform<T>(platform: NodeJS.Platform, fn: () => Promise<T>): Promise<T> {
|
||||
const originalPlatform = process.platform
|
||||
Object.defineProperty(process, 'platform', { configurable: true, value: platform })
|
||||
try {
|
||||
return await fn()
|
||||
} finally {
|
||||
Object.defineProperty(process, 'platform', { configurable: true, value: originalPlatform })
|
||||
}
|
||||
}
|
||||
|
||||
describe('listSystemFontFamilies', () => {
|
||||
afterEach(() => {
|
||||
vi.resetModules()
|
||||
runProcessMock.mockReset()
|
||||
})
|
||||
|
||||
it('sets UTF-8 stdout encoding as the first statement of the Windows font script', async () => {
|
||||
await withPlatform('win32', async () => {
|
||||
runProcessMock.mockResolvedValue(ok('Consolas\n'))
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await listSystemFontFamilies()
|
||||
|
||||
const args = runProcessMock.mock.calls[0]?.[0].args ?? []
|
||||
const script = args[args.indexOf('-Command') + 1] ?? ''
|
||||
// Output before this statement would still use the OEM encoding.
|
||||
expect(script.trim().split(/\r?\n/)[0]).toBe(
|
||||
'[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)'
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
it('spawns the Windows font script without an -ExecutionPolicy switch', async () => {
|
||||
await withPlatform('win32', async () => {
|
||||
runProcessMock.mockResolvedValue(ok('Consolas\n'))
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await listSystemFontFamilies()
|
||||
|
||||
const args = runProcessMock.mock.calls[0]?.[0].args ?? []
|
||||
expect(args).toContain('-Command')
|
||||
expect(args).not.toContain('-ExecutionPolicy')
|
||||
expect(args).not.toContain('Bypass')
|
||||
})
|
||||
})
|
||||
|
||||
it('runs PowerShell by absolute path on Windows', async () => {
|
||||
await withPlatform('win32', async () => {
|
||||
runProcessMock.mockResolvedValue(ok('Consolas\n'))
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await listSystemFontFamilies()
|
||||
|
||||
const program = runProcessMock.mock.calls[0]?.[0].program ?? ''
|
||||
expect(program).toMatch(/^[A-Za-z]:[\\/]/)
|
||||
expect(program.toLowerCase()).toContain('system32')
|
||||
expect(program.toLowerCase()).toContain('powershell.exe')
|
||||
})
|
||||
})
|
||||
|
||||
it('returns no fonts when the platform font command never exits', async () => {
|
||||
runProcessMock.mockResolvedValue(timedOut)
|
||||
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await expect(listSystemFontFamilies()).resolves.toEqual([])
|
||||
})
|
||||
|
||||
it('returns no fonts when the platform font command reports failure', async () => {
|
||||
runProcessMock.mockResolvedValue({
|
||||
code: 1,
|
||||
signal: null,
|
||||
stdout: '',
|
||||
stderr: 'nope',
|
||||
timedOut: false
|
||||
})
|
||||
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await expect(listSystemFontFamilies()).resolves.toEqual([])
|
||||
})
|
||||
|
||||
const platformTimeouts: [NodeJS.Platform, number][] = [
|
||||
['darwin', 45_000],
|
||||
['linux', 15_000],
|
||||
['win32', 15_000]
|
||||
]
|
||||
it.each(platformTimeouts)(
|
||||
'asks for the %s font command timeout of %dms',
|
||||
async (platform, timeoutMs) => {
|
||||
await withPlatform(platform, async () => {
|
||||
runProcessMock.mockResolvedValue(ok('Consolas\n'))
|
||||
const { listSystemFontFamilies } = await import('./system-fonts')
|
||||
await listSystemFontFamilies()
|
||||
|
||||
expect(runProcessMock.mock.calls[0]?.[0].timeoutMs).toBe(timeoutMs)
|
||||
})
|
||||
}
|
||||
)
|
||||
})
|
||||
@@ -49,29 +49,6 @@ describeOnWsl('runWslProcess against a real distro', () => {
|
||||
expect(elapsed).toBeLessThan(20_000)
|
||||
}, 60_000)
|
||||
|
||||
it('second probe-lane call does not pay the login shell again', async () => {
|
||||
const started = Date.now()
|
||||
await runWslProcess({
|
||||
loginPath: 'preferred',
|
||||
distro: DISTRO,
|
||||
program: '/bin/true',
|
||||
timeoutMs: 15_000
|
||||
})
|
||||
expect(Date.now() - started).toBeLessThan(5_000)
|
||||
}, 30_000)
|
||||
|
||||
it('interactive lane strips the distro banner from parsed stdout', async () => {
|
||||
// Fence stock Ubuntu rc hints out of stdout before parsing (#11327/#11823).
|
||||
const result = await runWslProcess({
|
||||
loginPath: 'preferred',
|
||||
distro: DISTRO,
|
||||
program: '/bin/echo',
|
||||
args: ['ORCA_PAYLOAD'],
|
||||
timeoutMs: 60_000
|
||||
})
|
||||
expect(result.stdout.trim()).toBe('ORCA_PAYLOAD')
|
||||
}, 90_000)
|
||||
|
||||
it('a script with quotes and $ arrives byte-identical', async () => {
|
||||
// Preserve $2 and embedded quotes; -- expansion/base64-eval wrappers broke both (#12964/#14292).
|
||||
const script = [
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import '@testing-library/jest-dom/vitest'
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
|
||||
import { getDefaultSettings } from '../../../../../shared/constants'
|
||||
|
||||
const mocks = vi.hoisted(() => ({
|
||||
openAutomationsPage: vi.fn()
|
||||
}))
|
||||
|
||||
vi.mock('@/i18n/i18n', () => ({
|
||||
translate: (_key: string, fallback: string) => fallback
|
||||
}))
|
||||
|
||||
vi.mock('@/store/index', () => ({
|
||||
useAppStore: (selector: (state: Record<string, unknown>) => unknown) =>
|
||||
selector({ openAutomationsPage: mocks.openAutomationsPage })
|
||||
}))
|
||||
|
||||
import { AutomationsSettingsPane } from './AutomationsSettingsPane'
|
||||
|
||||
describe('AutomationsSettingsPane', () => {
|
||||
beforeEach(() => {
|
||||
mocks.openAutomationsPage.mockReset()
|
||||
})
|
||||
|
||||
afterEach(cleanup)
|
||||
|
||||
it('controls sidebar visibility and opens Automations', async () => {
|
||||
const user = userEvent.setup()
|
||||
const updateSettings = vi.fn()
|
||||
render(
|
||||
<AutomationsSettingsPane
|
||||
settings={{ ...getDefaultSettings('/tmp'), showAutomationsButton: false }}
|
||||
updateSettings={updateSettings}
|
||||
/>
|
||||
)
|
||||
|
||||
const toggle = screen.getByRole('switch', { name: 'Show Automations Button' })
|
||||
expect(toggle).toHaveAttribute('aria-checked', 'false')
|
||||
await user.click(toggle)
|
||||
expect(updateSettings).toHaveBeenCalledWith({ showAutomationsButton: true })
|
||||
|
||||
const openButton = screen.getByRole('button', { name: /Open Automations/ })
|
||||
expect(openButton).toBeEnabled()
|
||||
await user.click(openButton)
|
||||
expect(mocks.openAutomationsPage).toHaveBeenCalledOnce()
|
||||
})
|
||||
})
|
||||
@@ -1,54 +0,0 @@
|
||||
// @vitest-environment happy-dom
|
||||
|
||||
import { cleanup, fireEvent, render } from '@testing-library/react'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import { DropdownMenu, DropdownMenuContent } from '@/components/ui/dropdown-menu'
|
||||
import type { StoppedWslHost } from '../wsl-host-stopped/use-stopped-wsl-host'
|
||||
import { WorktreeWslHostStartMenuItem } from './WorktreeWslHostStartMenuItem'
|
||||
|
||||
const mocks = vi.hoisted(() => {
|
||||
const stopped: { current: StoppedWslHost | null } = { current: null }
|
||||
return {
|
||||
stopped,
|
||||
start: vi.fn<(environmentId: string) => Promise<boolean>>()
|
||||
}
|
||||
})
|
||||
|
||||
vi.mock('../wsl-host-stopped/use-stopped-wsl-host', () => ({
|
||||
useStoppedWslHost: () => mocks.stopped.current
|
||||
}))
|
||||
vi.mock('@/lib/wsl-host-user-start', () => ({
|
||||
startWslHostAndReloadProjects: mocks.start
|
||||
}))
|
||||
|
||||
function renderMenu() {
|
||||
return render(
|
||||
<DropdownMenu open modal={false}>
|
||||
<DropdownMenuContent>
|
||||
<WorktreeWslHostStartMenuItem worktreeId="wt-wsl" />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
}
|
||||
|
||||
afterEach(() => {
|
||||
cleanup()
|
||||
mocks.stopped.current = null
|
||||
mocks.start.mockReset()
|
||||
})
|
||||
|
||||
describe('WorktreeWslHostStartMenuItem', () => {
|
||||
it('offers Start for a workspace on a stopped distro, and boots only on select (E9)', () => {
|
||||
mocks.stopped.current = { environmentId: 'wsl:ubuntu', distro: 'Ubuntu' }
|
||||
mocks.start.mockResolvedValue(true)
|
||||
const view = renderMenu()
|
||||
expect(mocks.start).not.toHaveBeenCalled()
|
||||
fireEvent.click(view.getByRole('menuitem', { name: 'Start Ubuntu' }))
|
||||
expect(mocks.start).toHaveBeenCalledWith('wsl:ubuntu')
|
||||
})
|
||||
|
||||
it('adds nothing for a workspace whose host is not stopped', () => {
|
||||
const view = renderMenu()
|
||||
expect(view.queryByRole('menuitem')).toBeNull()
|
||||
})
|
||||
})
|
||||
-14
@@ -24,20 +24,6 @@ describe('ackPaintedColdRestore', () => {
|
||||
vi.unstubAllGlobals()
|
||||
})
|
||||
|
||||
it('acks by terminal only with the switch off', async () => {
|
||||
await ackWithSwitch(false, 'pty-1')
|
||||
expect(ackColdRestore).toHaveBeenCalledWith('pty-1')
|
||||
})
|
||||
|
||||
it('names the painted pane in the layout-owner build', async () => {
|
||||
await ackWithSwitch(true, 'pty-1')
|
||||
expect(ackColdRestore).toHaveBeenCalledWith('pty-1', {
|
||||
worktreeId: 'repo::/wt',
|
||||
tabId: 'tab-1',
|
||||
leafId: 'leaf-1'
|
||||
})
|
||||
})
|
||||
|
||||
it('never acks a paired server’s terminal, whose host owns its restore', async () => {
|
||||
const { toRemoteRuntimePtyId } =
|
||||
await import('../../../../../shared/remote-runtime/remote-runtime-pty-id')
|
||||
|
||||
@@ -29,16 +29,6 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('live terminal surface owners', () => {
|
||||
it('records the exact pane the host binds a live PTY to', () => {
|
||||
const owners = indexLiveTerminalSurfaceOwners([summary({})], WORKTREE_ID)
|
||||
|
||||
expect(owners.get(`${WORKTREE_ID}@@live-agent`)).toEqual({
|
||||
paneKey: `tab-live:${LEAF_ID}`,
|
||||
ptyId: `${WORKTREE_ID}@@live-agent`,
|
||||
tabId: 'tab-live'
|
||||
})
|
||||
})
|
||||
|
||||
it.each([false, true])(
|
||||
'rejects conflicting owned and orphan rows (orphan first: %s)',
|
||||
(orphanFirst) => {
|
||||
|
||||
@@ -8,11 +8,6 @@ const BEGIN = '\x1b[200~'
|
||||
const END = '\x1b[201~'
|
||||
|
||||
describe('buildNativeChatPasteBytes', () => {
|
||||
it('single-line text has no trailing submit (Enter is written separately)', () => {
|
||||
expect(buildNativeChatPasteBytes('hello world')).toBe('hello world')
|
||||
expect(buildNativeChatPasteBytes('hello world')).not.toContain('\r')
|
||||
})
|
||||
|
||||
it('multi-line text is bracketed-paste wrapped with NO trailing submit', () => {
|
||||
const text = 'line one\r\nline two\nline three'
|
||||
expect(buildNativeChatPasteBytes(text)).toBe(`${BEGIN}line one\rline two\rline three${END}`)
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { z } from 'zod'
|
||||
import { acknowledgesByDefault } from './testing-host'
|
||||
import { mountWorker } from './orca-testing'
|
||||
|
||||
type HookOrca = {
|
||||
@@ -39,11 +37,6 @@ describe('orca/testing hooks', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('answers fire-and-forget host methods with success by default', () => {
|
||||
expect(acknowledgesByDefault({ result: z.object({ ok: z.literal(true) }) })).toBe(true)
|
||||
expect(acknowledgesByDefault({ result: z.object({ delivered: z.boolean() }) })).toBe(false)
|
||||
})
|
||||
|
||||
it('fires editor.save.before and returns the text the worker wrote', async () => {
|
||||
const formatter = {
|
||||
default(orca: {
|
||||
|
||||
Reference in New Issue
Block a user