test: strengthen CLI expectations and consolidate repeated scenarios (#32976)

* test: strengthen CLI refusals and consolidate serve validation

* test: consolidate terminal creation and strengthen restore output

* test: pin dashboard telemetry clock away from midnight

---------

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-10-23 17:11:16 -07:00
committed by GitHub
co-authored by OrcaWin
parent c84817e8f9
commit 225f940453
8 changed files with 365 additions and 504 deletions
@@ -142,12 +142,12 @@ it('retains fork reports without requiring a Slack secret and redacts delivery e
sendNotification({
fetch: vi.fn().mockRejectedValue(new Error('fetch failed: https://example.test/slack'))
})
).rejects.toThrow('Slack dependency review notification could not be sent')
).rejects.toThrow(/^Slack dependency review notification could not be sent$/)
await expect(
sendNotification({
fetch: vi.fn().mockResolvedValue({ ok: false, status: 503 })
})
).rejects.toThrow('Slack dependency review notification returned HTTP 503')
).rejects.toThrow(/^Slack dependency review notification returned HTTP 503$/)
})
it('extracts release data while excluding executable package and Cargo configuration', async () => {
+77 -17
View File
@@ -1,4 +1,4 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const mocks = vi.hoisted(() => ({
callMock: vi.fn(),
@@ -31,10 +31,6 @@ import { buildWorktree, okFixture } from './test-fixtures'
import { RuntimeClientError } from './runtime/types'
import { JIRA_AGENT_ACCESS_RUNTIME_CAPABILITY } from '../shared/jira/jira-agent-capability'
import { WORKTREE_LINKED_ITEMS_DELTA_RUNTIME_CAPABILITY } from '../shared/workspace-attachment-capabilities'
import {
getWorkspaceReferenceIdentity,
parseWorkspaceReferenceUrl
} from '../shared/workspace-reference-identity'
const site = {
id: 'site-1',
@@ -56,9 +52,17 @@ const issue = {
updatedAt: '2026-10-13',
createdAt: '2026-10-12'
}
const attachment = { ...parseWorkspaceReferenceUrl(issue.url), title: issue.title }
const jiraReference = {
provider: 'jira' as const,
type: 'issue' as const,
number: 0,
identifier: 'ENG-123',
jiraIdentifier: 'ENG-123',
url: issue.url
}
const attachment = { ...jiraReference, title: issue.title }
const reviewUrl = 'https://gitlab.com/acme/api/-/merge_requests/12'
const review = parseWorkspaceReferenceUrl(reviewUrl)
const review = { provider: 'gitlab' as const, type: 'mr' as const, number: 12, url: reviewUrl }
const workspace = { ...buildWorktree('/tmp/api', 'api'), kind: 'worktree', name: 'api' }
const addArgs = ['reference', 'add', 'eng-123', '--worktree', 'name:api']
const createArgs = [
@@ -106,8 +110,16 @@ function expectNoWrite(): void {
}
describe('Jira reference keys', () => {
const priorExitCode = process.exitCode
beforeEach(() => {
process.exitCode = undefined
})
afterEach(() => {
process.exitCode = priorExitCode
})
useWorktreeAwarenessEnvironment(mocks)
beforeEach(() => {
mocks.runtimeClientConstructorMock.mockClear()
vi.spyOn(console, 'log').mockImplementation(() => {})
vi.spyOn(console, 'error').mockImplementation(() => {})
pairRuntimeEnvironment(mocks.listEnvironmentsMock, 'remote')
@@ -123,6 +135,7 @@ describe('Jira reference keys', () => {
expect(mocks.callMock).toHaveBeenCalledWith(
'worktree.set',
expect.objectContaining({
worktree: 'id:repo::/tmp/api',
linkedItemsBase: [],
linkedItems: [attachment],
linkedItemsSelectionChanged: false
@@ -132,13 +145,18 @@ describe('Jira reference keys', () => {
it('uses the selected execution host for Jira lookup and workspace mutation', async () => {
await main([...addArgs, '--environment', 'remote'], '/tmp/api')
expect(mocks.runtimeClientConstructorMock).toHaveBeenCalledWith(undefined, 'remote')
expect(mocks.runtimeClientConstructorMock).toHaveBeenCalledExactlyOnceWith(undefined, 'remote')
expect(mocks.callMock).toHaveBeenCalledWith('jira.lookupIssueSummary', {
key: 'ENG-123',
siteId: site.id
})
expect(mocks.callMock).toHaveBeenCalledWith('reference.list', { worktree: 'name:api' })
expect(mocks.callMock).toHaveBeenCalledWith('worktree.set', expect.anything())
expect(mocks.callMock).toHaveBeenCalledWith('worktree.set', {
worktree: 'id:repo::/tmp/api',
linkedItemsBase: [],
linkedItems: [attachment],
linkedItemsSelectionChanged: false
})
})
it('refuses ambiguous sites rather than using activeSiteId', async () => {
@@ -157,7 +175,12 @@ describe('Jira reference keys', () => {
it.each(['all', 'missing'])('rejects invalid explicit site %s before lookup', async (id) => {
await main([...addArgs, '--reference-site', id], '/tmp/api')
expect(console.error).toHaveBeenCalled()
expect(console.error).toHaveBeenCalledExactlyOnceWith(
id === 'all'
? 'Choose one Jira site ID; --reference-site all is unsupported.'
: 'No matching connected Jira site. Check orca jira connection and Orca Jira settings.'
)
expect(process.exitCode).toBe(1)
expect(mocks.callMock).not.toHaveBeenCalledWith('jira.lookupIssueSummary', expect.anything())
expectNoWrite()
})
@@ -182,7 +205,7 @@ describe('Jira reference keys', () => {
expect(mocks.callMock).toHaveBeenCalledWith(
'worktree.set',
expect.objectContaining({
linkedItems: [{ ...parseWorkspaceReferenceUrl(serverIssue.url), title: issue.title }]
linkedItems: [{ ...attachment, url: serverIssue.url }]
})
)
})
@@ -198,7 +221,14 @@ describe('Jira reference keys', () => {
])('rejects an absent or mismatched summary %#', async (summary) => {
responses({ 'jira.lookupIssueSummary': summary })
await main(addArgs, '/tmp/api')
expect(console.error).toHaveBeenCalled()
expect(mocks.callMock).toHaveBeenCalledWith('jira.lookupIssueSummary', {
key: 'ENG-123',
siteId: site.id
})
expect(console.error).toHaveBeenCalledExactlyOnceWith(
'Jira did not return issue ENG-123 with a title on the selected site.'
)
expect(process.exitCode).toBe(1)
expectNoWrite()
})
@@ -241,7 +271,13 @@ describe('Jira reference keys', () => {
responses({
'reference.list': {
worktree: workspace,
references: [{ ...stored, key: getWorkspaceReferenceIdentity(stored), selected: false }]
references: [
{
...stored,
key: '["jira","issue","example.atlassian.net","/browse/ENG-123"]',
selected: false
}
]
}
})
await main([...addArgs, '--json'], '/tmp/api')
@@ -273,6 +309,7 @@ describe('Jira reference keys', () => {
it('resolves create references before workspace creation', async () => {
await main(createArgs, '/tmp/api')
const methods = mocks.callMock.mock.calls.map(([method]) => method)
expect(methods).toContain('jira.lookupIssueSummary')
expect(methods.indexOf('jira.lookupIssueSummary')).toBeLessThan(
methods.indexOf('worktree.create')
)
@@ -285,6 +322,18 @@ describe('Jira reference keys', () => {
it('creates nothing when the Jira reference cannot resolve', async () => {
responses({ 'jira.lookupIssueSummary': null })
await main(createArgs, '/tmp/api')
expect(mocks.callMock).toHaveBeenCalledWith('jira.lookupIssueSummary', {
key: 'ENG-123',
siteId: site.id
})
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0])).toMatchObject({
ok: false,
error: {
code: 'jira_issue_unavailable',
message: 'Jira did not return issue ENG-123 with a title on the selected site.'
}
})
expect(process.exitCode).toBe(1)
expectNoWrite()
})
@@ -312,7 +361,18 @@ describe('Jira reference keys', () => {
key: 'ENG-124',
siteId: site.id
})
expect(console.error).toHaveBeenCalled()
expect(
mocks.callMock.mock.calls
.filter(([method]) => method === 'jira.lookupIssueSummary')
.map(([, params]) => params)
).toEqual([
{ key: 'ENG-123', siteId: site.id },
{ key: 'ENG-124', siteId: site.id }
])
expect(console.error).toHaveBeenCalledExactlyOnceWith(
'Jira did not return issue ENG-124 with a title on the selected site.'
)
expect(process.exitCode).toBe(1)
expectNoWrite()
})
@@ -328,11 +388,11 @@ describe('Jira reference keys', () => {
it('keeps full Jira URLs usable without a saved Jira connection', async () => {
responses({ 'status.get': { capabilities: [WORKTREE_LINKED_ITEMS_DELTA_RUNTIME_CAPABILITY] } })
await main(['reference', 'add', issue.url, '--worktree', 'name:api'], '/tmp/api')
expect(mocks.callMock).not.toHaveBeenCalledWith('jira.status')
expect(mocks.callMock.mock.calls.map(([method]) => method)).not.toContain('jira.status')
expect(mocks.callMock).toHaveBeenCalledWith(
'worktree.set',
expect.objectContaining({
linkedItems: [parseWorkspaceReferenceUrl(issue.url)]
linkedItems: [jiraReference]
})
)
})
@@ -341,7 +401,7 @@ describe('Jira reference keys', () => {
responses({ 'status.get': { capabilities: [WORKTREE_LINKED_ITEMS_DELTA_RUNTIME_CAPABILITY] } })
await main(addArgs, '/tmp/api')
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('Update Orca'))
expect(mocks.callMock).not.toHaveBeenCalledWith('jira.status')
expect(mocks.callMock.mock.calls.map(([method]) => method)).not.toContain('jira.status')
expectNoWrite()
})
})
+66 -35
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const {
callMock,
@@ -42,17 +42,24 @@ vi.mock('child_process', async () => {
import { main } from './index'
import { buildWorktree, okFixture } from './test-fixtures'
import {
getWorkspaceReferenceIdentity,
parseWorkspaceReferenceUrl
} from '../shared/workspace-reference-identity'
import { getWorkspaceReferenceIdentity } from '../shared/workspace-reference-identity'
import type { WorkspaceAttachment } from '../shared/worktree/types'
import { WORKTREE_LINKED_ITEMS_DELTA_RUNTIME_CAPABILITY } from '../shared/workspace-attachment-capabilities'
import { useWorktreeAwarenessEnvironment } from './index-test-harness'
const PR = 'https://github.com/acme/api/pull/5123'
const TASK = 'https://linear.app/acme/issue/STA-1234'
const parsedPR = parseWorkspaceReferenceUrl(PR)
const parsedTask = parseWorkspaceReferenceUrl(TASK)
const PR_KEY = '["github","pr","github.com","/acme/api/pull/5123"]'
const parsedPR: WorkspaceAttachment = { provider: 'github', type: 'pr', number: 5123, url: PR }
const parsedTask: WorkspaceAttachment = {
provider: 'linear',
type: 'issue',
number: 0,
identifier: 'STA-1234',
linearIdentifier: 'STA-1234',
linearOrganizationUrlKey: 'acme',
url: TASK
}
function listResult(references = [parsedPR], kind: 'worktree' | 'folder' = 'worktree') {
return {
@@ -94,6 +101,13 @@ function mockCalls(
}
describe('reference CLI', () => {
const priorExitCode = process.exitCode
beforeEach(() => {
process.exitCode = undefined
})
afterEach(() => {
process.exitCode = priorExitCode
})
useWorktreeAwarenessEnvironment({
callMock,
serveOrcaAppMock,
@@ -112,7 +126,14 @@ describe('reference CLI', () => {
linkedItems: [parsedPR, parsedTask],
linkedItemsSelectionChanged: false
})
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0]).result.changes).toHaveLength(2)
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0]).result.changes).toEqual([
{ key: PR_KEY, operation: 'add', changed: true },
{
key: '["linear","issue","linear.app","/acme/issue/STA-1234"]',
operation: 'add',
changed: true
}
])
})
it('validates every URL before any request', async () => {
@@ -125,17 +146,20 @@ describe('reference CLI', () => {
it('requires the delta capability even if the host supports linked items', async () => {
mockCalls(listResult(), listResult(), ['worktree.linked-items.v1'])
await main(['reference', 'add', TASK, '--worktree', 'name:api'], '/tmp/api')
expect(callMock).toHaveBeenCalledTimes(1)
expect(callMock).toHaveBeenCalledExactlyOnceWith('status.get')
expect(console.error).toHaveBeenCalledWith(expect.stringContaining('cannot merge'))
})
it('duplicate adds preserve current metadata and produce a no-op', async () => {
mockCalls()
mockCalls(listResult([{ ...parsedPR, title: 'Saved title' }]))
await main(['reference', 'add', PR, PR, '--worktree', 'name:api', '--json'], '/tmp/api')
expect(callMock.mock.calls.some(([method]) => method === 'worktree.set')).toBe(false)
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0]).result.references[0].title).toBe(
'Saved title'
)
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0]).result.changes).toEqual([
{
key: getWorkspaceReferenceIdentity(parsedPR),
key: PR_KEY,
operation: 'add',
changed: false,
reason: 'already_linked'
@@ -145,17 +169,7 @@ describe('reference CLI', () => {
it('removes only requested keys from folders via existing folder storage', async () => {
mockCalls(listResult([parsedPR, parsedTask], 'folder'), listResult([parsedTask], 'folder'))
await main(
[
'reference',
'remove',
'--key',
getWorkspaceReferenceIdentity(parsedPR),
'--worktree',
'folder:folder1'
],
'/tmp/api'
)
await main(['reference', 'remove', '--key', PR_KEY, '--worktree', 'folder:folder1'], '/tmp/api')
expect(callMock).toHaveBeenCalledWith('folderWorkspace.update', {
folderWorkspaceId: 'folder1',
updates: {
@@ -167,7 +181,7 @@ describe('reference CLI', () => {
})
it('removes a URL without touching the same review number in another repository', async () => {
const other = parseWorkspaceReferenceUrl('https://github.com/acme/other/pull/5123')
const other = { ...parsedPR, url: 'https://github.com/acme/other/pull/5123' }
mockCalls(listResult([parsedPR, other]), listResult([other]))
await main(['reference', 'remove', PR, '--worktree', 'name:api'], '/tmp/api')
expect(callMock).toHaveBeenCalledWith(
@@ -308,13 +322,21 @@ describe('reference CLI', () => {
})
it.each([
['5123'],
['STA-1234', '--worktree', 'name:api', '--repo', 'id:repo'],
['STA-1234', '--limit', '0']
])('rejects invalid find arguments %j before querying', async (...args) => {
{ args: ['5123'], message: 'Expected a full reference URL (https://…).' },
{
args: ['STA-1234', '--worktree', 'name:api', '--repo', 'id:repo'],
message: 'Pass --worktree or --repo, not both.'
},
{ args: ['STA-1234', '--limit', '0'], message: 'Invalid positive integer for --limit' }
])('rejects invalid find arguments $args before querying', async ({ args, message }) => {
mockCalls()
await main(['reference', 'find', ...args], '/tmp/api')
await main(['reference', 'find', ...args, '--json'], '/tmp/api')
expect(callMock).not.toHaveBeenCalled()
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0])).toMatchObject({
ok: false,
error: { code: 'invalid_argument', message }
})
expect(process.exitCode).toBe(1)
})
it('seeds repeated references in the create request before setup or agent startup', async () => {
@@ -357,11 +379,17 @@ describe('reference CLI', () => {
'--reference',
PR,
`--${flag}`,
'4'
'4',
'--json'
],
'/tmp/api'
)
expect(callMock).not.toHaveBeenCalled()
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0])).toMatchObject({
ok: false,
error: { code: 'invalid_argument', message: `Cannot combine --reference with --${flag}.` }
})
expect(process.exitCode).toBe(1)
}
)
@@ -380,13 +408,16 @@ describe('reference CLI', () => {
}
return base?.(method, ...rest)
})
const priorExitCode = process.exitCode
await main(argv, '/tmp/api')
const printed = vi.mocked(console.error).mock.calls.flat().join('\n')
expect(printed).toContain('Update Orca on the execution host')
expect(printed).not.toContain('Unknown method')
await main([...argv, '--json'], '/tmp/api')
expect(JSON.parse(vi.mocked(console.log).mock.calls[0][0])).toMatchObject({
ok: false,
error: {
code: 'incompatible_runtime',
message:
'This Orca host does not support reference commands yet. Update Orca on the execution host.'
}
})
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('validates create flags locally before probing reference capability', async () => {
+55 -81
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const {
callMock,
@@ -44,6 +44,13 @@ import { main } from './index'
import { useWorktreeAwarenessEnvironment } from './index-test-harness'
describe('orca cli worktree awareness', () => {
const priorExitCode = process.exitCode
beforeEach(() => {
process.exitCode = undefined
})
afterEach(() => {
process.exitCode = priorExitCode
})
useWorktreeAwarenessEnvironment({
callMock,
serveOrcaAppMock,
@@ -54,7 +61,7 @@ describe('orca cli worktree awareness', () => {
})
it('starts a foreground headless server through `serve`', async () => {
serveOrcaAppMock.mockResolvedValue(0)
serveOrcaAppMock.mockResolvedValue(17)
process.env.ORCA_ENVIRONMENT = 'stale-env'
await main(
@@ -62,7 +69,7 @@ describe('orca cli worktree awareness', () => {
'/tmp/repo'
)
expect(serveOrcaAppMock).toHaveBeenCalledWith({
expect(serveOrcaAppMock).toHaveBeenCalledExactlyOnceWith({
json: true,
port: '6768',
pairingAddress: '100.64.1.20',
@@ -72,6 +79,8 @@ describe('orca cli worktree awareness', () => {
recipeJson: false,
projectRoot: null
})
expect(process.exitCode).toBe(17)
expect(callMock).not.toHaveBeenCalled()
})
it.skipIf(process.platform === 'win32')(
@@ -88,11 +97,16 @@ describe('orca cli worktree awareness', () => {
expect(serveOrcaAppMock.mock.lastCall?.[0]).not.toHaveProperty('supervise')
serveOrcaAppMock.mockClear()
const error = vi.spyOn(console, 'error').mockImplementation(() => {})
await main(
['serve', '--supervise', '--recipe-json', '--project-root', '/workspace/repo'],
'/tmp/repo'
)
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect(error).toHaveBeenCalledExactlyOnceWith(
'--recipe-json starts a detached server and returns; it cannot be combined with --supervise.'
)
expect(process.exitCode).toBe(1)
}
)
@@ -114,7 +128,7 @@ describe('orca cli worktree awareness', () => {
'/tmp/repo'
)
expect(serveOrcaAppMock).toHaveBeenCalledWith({
expect(serveOrcaAppMock).toHaveBeenCalledExactlyOnceWith({
json: true,
port: null,
pairingAddress: '100.64.1.20',
@@ -141,7 +155,7 @@ describe('orca cli worktree awareness', () => {
'/tmp/repo'
)
expect(serveOrcaAppMock).toHaveBeenCalledWith({
expect(serveOrcaAppMock).toHaveBeenCalledExactlyOnceWith({
json: false,
port: null,
pairingAddress: 'wss://sandbox.example.com',
@@ -153,86 +167,46 @@ describe('orca cli worktree awareness', () => {
})
})
it('rejects recipe JSON output without a project root', async () => {
it.each([
{
name: 'recipe JSON output without a project root',
args: ['serve', '--recipe-json'],
message: 'Recipe JSON output requires --project-root.'
},
{
name: 'recipe JSON output with mobile pairing',
args: ['serve', '--recipe-json', '--project-root', '/workspace/repo', '--mobile-pairing'],
message: 'Recipe JSON output requires runtime pairing; remove --mobile-pairing.'
},
{
name: 'contradictory pairing flags',
args: ['serve', '--mobile-pairing', '--no-pairing'],
message: 'Use either --mobile-pairing or --no-pairing, not both.'
},
{
name: 'an invalid port',
args: ['serve', '--port', 'not-a-port'],
message: 'Invalid --port value: not-a-port'
},
{
name: 'a valueless port',
args: ['serve', '--port'],
message: 'Missing value for --port.'
}
])('rejects $name before launching the app', async ({ args, message }) => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
vi.spyOn(console, 'error').mockImplementation(() => {})
await main(['serve', '--recipe-json'], '/tmp/repo')
await main([...args, '--json'], '/tmp/repo')
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Recipe JSON output requires --project-root.'
)
expect(logSpy).toHaveBeenCalledTimes(1)
expect(JSON.parse(logSpy.mock.calls[0][0])).toEqual({
id: 'local',
ok: false,
error: { code: 'invalid_argument', message },
_meta: { runtimeId: null }
})
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('rejects recipe JSON output with mobile pairing', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(
['serve', '--recipe-json', '--project-root', '/workspace/repo', '--mobile-pairing'],
'/tmp/repo'
)
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Recipe JSON output requires runtime pairing; remove --mobile-pairing.'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('rejects contradictory serve pairing flags', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(['serve', '--mobile-pairing', '--no-pairing', '--json'], '/tmp/repo')
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Use either --mobile-pairing or --no-pairing, not both.'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('rejects invalid serve ports before launching the app', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(['serve', '--port', 'not-a-port', '--json'], '/tmp/repo')
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Invalid --port value: not-a-port'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('rejects value-less serve ports before launching the app', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(['serve', '--port', '--json'], '/tmp/repo')
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Missing value for --port.'
)
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
})
+26 -8
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { beforeEach, describe, expect, it, vi } from 'vitest'
const {
callMock,
@@ -53,6 +53,10 @@ describe('orca serve restore resume', () => {
spawnMock
})
beforeEach(() => {
runtimeClientConstructorMock.mockClear()
})
it('asks the local Orca to resume and never starts a server', async () => {
process.env.ORCA_ENVIRONMENT = 'paired-env'
callMock.mockResolvedValue({
@@ -72,10 +76,13 @@ describe('orca serve restore resume', () => {
await main(['serve', 'restore', 'resume'], '/tmp/repo')
expect(serveOrcaAppMock).not.toHaveBeenCalled()
expect(callMock).toHaveBeenCalledWith('runtime.automaticWork.resume')
expect(runtimeClientConstructorMock).toHaveBeenLastCalledWith(null, null)
expect(logSpy.mock.calls[0]?.[0]).toContain('Automatic restores resumed')
expect(logSpy.mock.calls[0]?.[0]).toContain('stopped unexpectedly')
expect(callMock.mock.calls).toEqual([['runtime.automaticWork.resume']])
expect(runtimeClientConstructorMock.mock.calls).toEqual([[null, null]])
expect(logSpy.mock.calls).toEqual([
[
'Automatic restores resumed. They were paused at 1970-01-01T00:00:00.000Z because the terminal host stopped unexpectedly.'
]
])
})
it('says so when nothing was paused, and when the host has no gate', async () => {
@@ -95,8 +102,14 @@ describe('orca serve restore resume', () => {
})
await main(['serve', 'restore', 'resume'], '/tmp/repo')
expect(logSpy.mock.calls[0]?.[0]).toContain('were not paused')
expect(logSpy.mock.calls[1]?.[0]).toContain('no automatic-restore gate')
expect(callMock.mock.calls).toEqual([
['runtime.automaticWork.resume'],
['runtime.automaticWork.resume']
])
expect(logSpy.mock.calls).toEqual([
['Automatic restores were not paused; nothing to resume.'],
['This host has no automatic-restore gate to resume (its terminal host predates it).']
])
})
it('explains a terminal host that predates the command', async () => {
@@ -108,6 +121,11 @@ describe('orca serve restore resume', () => {
_meta: { runtimeId: 'runtime-1' }
})
await main(['serve', 'restore', 'resume'], '/tmp/repo')
expect(logSpy.mock.calls[0]?.[0]).toContain('predates this command')
expect(callMock.mock.calls).toEqual([['runtime.automaticWork.resume']])
expect(logSpy.mock.calls).toEqual([
[
'The terminal host running now predates this command, so it cannot clear its pause. Run this again after the terminal host restarts. Until then, opening a sleeping terminal still resumes it.'
]
])
})
})
+120 -355
View File
@@ -1,4 +1,4 @@
import { describe, expect, it, vi } from 'vitest'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
const {
callMock,
@@ -54,14 +54,114 @@ describe('orca cli worktree awareness', () => {
spawnMock
})
it('passes explicit focus through terminal.create', async () => {
const originalExitCode = process.exitCode
beforeEach(() => {
process.exitCode = undefined
runtimeClientConstructorMock.mockClear()
})
afterEach(() => {
process.exitCode = originalExitCode
})
it.each([
[
'passes explicit focus through terminal.create',
{
title: 'RUNNER',
command: undefined,
flags: ['--focus'],
expected: { focus: true, presentation: 'focused' }
}
],
[
'keeps interactive Codex startup commands backgrounded unless focus is explicit',
{
title: 'Codex',
command: 'codex',
flags: [],
expected: { focus: false, rendererBacked: true, activate: false }
}
],
[
'keeps explicit focus semantics when forcing Codex through the renderer path',
{
title: 'Codex',
command: 'codex',
flags: ['--focus'],
expected: { focus: true, presentation: 'focused', rendererBacked: true, activate: true }
}
],
[
'does not force the visible terminal path for explicit Codex exec commands',
{
title: 'Codex exec',
command: 'codex exec summarize',
flags: [],
expected: { focus: false }
}
],
[
'does not force the visible terminal path for Codex exec commands after global options',
{
title: 'Codex exec',
command: 'codex -m gpt-5 --sandbox workspace-write exec summarize',
flags: [],
expected: { focus: false }
}
],
[
'does not force the visible terminal path for Codex review commands after long options',
{
title: 'Codex review',
command: 'codex --model=gpt-5 --sandbox=workspace-write review',
flags: [],
expected: { focus: false }
}
],
[
'does not force the visible terminal path for Codex help commands',
{
title: 'Codex help',
command: 'codex --help',
flags: [],
expected: { focus: false }
}
],
[
'keeps Codex prompts after global options backgrounded unless focus is explicit',
{
title: 'Codex prompt',
command: 'codex -m gpt-5 "fix the flaky test"',
flags: [],
expected: { focus: false, rendererBacked: true, activate: false }
}
],
[
'keeps interactive Claude startup commands backgrounded unless focus is explicit',
{
title: 'Claude',
command: 'claude',
flags: [],
expected: { focus: false, rendererBacked: true, activate: false }
}
],
[
'keeps Claude print commands on the background terminal path',
{
title: 'Claude print',
command: 'claude -p "summarize"',
flags: [],
expected: { focus: false }
}
]
] as const)('%s', async (_name, { title, command, flags, expected }) => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'RUNNER'
title
}
})
)
@@ -74,20 +174,18 @@ describe('orca cli worktree awareness', () => {
'--worktree',
'path:/tmp/repo/feature',
'--title',
'RUNNER',
'--focus',
title,
...(command === undefined ? [] : ['--command', command]),
...flags,
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: undefined,
title: 'RUNNER',
focus: true,
presentation: 'focused'
})
expect(callMock.mock.calls).toEqual([
['terminal.create', { worktree: 'path:/tmp/repo/feature', command, title, ...expected }]
])
expect(process.exitCode).toBeUndefined()
})
it('prints terminal.read fallback screen lines in json mode', async () => {
@@ -126,340 +224,6 @@ describe('orca cli worktree awareness', () => {
])
})
it('keeps interactive Codex startup commands backgrounded unless focus is explicit', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex',
'--command',
'codex',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex',
title: 'Codex',
focus: false,
rendererBacked: true,
activate: false
})
})
it('keeps explicit focus semantics when forcing Codex through the renderer path', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex',
'--command',
'codex',
'--focus',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex',
title: 'Codex',
focus: true,
presentation: 'focused',
rendererBacked: true,
activate: true
})
})
it('does not force the visible terminal path for explicit Codex exec commands', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex exec'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex exec',
'--command',
'codex exec summarize',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex exec summarize',
title: 'Codex exec',
focus: false
})
})
it('does not force the visible terminal path for Codex exec commands after global options', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex exec'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex exec',
'--command',
'codex -m gpt-5 --sandbox workspace-write exec summarize',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex -m gpt-5 --sandbox workspace-write exec summarize',
title: 'Codex exec',
focus: false
})
})
it('does not force the visible terminal path for Codex review commands after long options', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex review'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex review',
'--command',
'codex --model=gpt-5 --sandbox=workspace-write review',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex --model=gpt-5 --sandbox=workspace-write review',
title: 'Codex review',
focus: false
})
})
it('does not force the visible terminal path for Codex help commands', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex help'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex help',
'--command',
'codex --help',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex --help',
title: 'Codex help',
focus: false
})
})
it('keeps Codex prompts after global options backgrounded unless focus is explicit', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Codex prompt'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Codex prompt',
'--command',
'codex -m gpt-5 "fix the flaky test"',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'codex -m gpt-5 "fix the flaky test"',
title: 'Codex prompt',
focus: false,
rendererBacked: true,
activate: false
})
})
it('keeps interactive Claude startup commands backgrounded unless focus is explicit', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Claude'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Claude',
'--command',
'claude',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'claude',
title: 'Claude',
focus: false,
rendererBacked: true,
activate: false
})
})
it('keeps Claude print commands on the background terminal path', async () => {
queueFixtures(
callMock,
okFixture('req_terminal_create', {
terminal: {
handle: 'term_1',
worktreeId: 'repo-1::/tmp/repo/feature',
title: 'Claude print'
}
})
)
vi.spyOn(console, 'log').mockImplementation(() => {})
await main(
[
'terminal',
'create',
'--worktree',
'path:/tmp/repo/feature',
'--title',
'Claude print',
'--command',
'claude -p "summarize"',
'--json'
],
'/tmp/repo'
)
expect(callMock).toHaveBeenCalledWith('terminal.create', {
worktree: 'path:/tmp/repo/feature',
command: 'claude -p "summarize"',
title: 'Claude print',
focus: false
})
})
it('uses the resolved enclosing worktree for terminal consumers', async () => {
queueFixtures(
callMock,
@@ -532,7 +296,6 @@ describe('orca cli worktree awareness', () => {
it('rejects implicit remote terminal create instead of resolving from client cwd', async () => {
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const errSpy = vi.spyOn(console, 'error').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(
['terminal', 'create', '--pairing-code', 'remote-runtime', '--json'],
@@ -540,12 +303,17 @@ describe('orca cli worktree awareness', () => {
)
expect(callMock).not.toHaveBeenCalled()
expect([...logSpy.mock.calls, ...errSpy.mock.calls].flat().join('\n')).toContain(
'Remote terminal create requires --worktree'
)
expect(logSpy).toHaveBeenCalledTimes(1)
expect(JSON.parse(String(logSpy.mock.calls[0]?.[0]))).toMatchObject({
ok: false,
error: {
code: 'invalid_argument',
message:
'Remote terminal create requires --worktree because the client cwd cannot identify a server worktree.'
}
})
expect(errSpy).not.toHaveBeenCalled()
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('sends explicit remote terminal create worktree selectors unchanged', async () => {
@@ -602,7 +370,6 @@ describe('orca cli worktree awareness', () => {
}
})
const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {})
const priorExitCode = process.exitCode
await main(['terminal', 'wait', '--terminal', 'term_worker', '--for', 'tui-idle'], '/tmp/repo')
@@ -619,8 +386,6 @@ describe('orca cli worktree awareness', () => {
)
expect(logSpy.mock.calls.flat().join('\n')).toContain('blockedReason: codex-cwd-prompt')
expect(process.exitCode).toBe(1)
process.exitCode = priorExitCode
})
it('does not force remote Codex terminal creates through a local renderer path', async () => {
+18 -5
View File
@@ -84,6 +84,10 @@ describe('orca terminal list host scope', () => {
await main(['terminal', 'list', '--json'], '/tmp/repo')
expect(callMock.mock.calls).toEqual([
['terminal.list', { worktree: undefined, limit: undefined, includeVisualLayouts: false }]
])
const printed = JSON.parse(String(logSpy.mock.calls[0]?.[0]))
expect(printed.result.terminals[0].executionHostId).toBe('ssh:box-1')
expect(printed.result.hostScope).toEqual({
@@ -108,10 +112,14 @@ describe('orca terminal list host scope', () => {
await main(['terminal', 'list'], '/tmp/repo')
expect(callMock.mock.calls).toEqual([
['terminal.list', { worktree: undefined, limit: undefined, includeVisualLayouts: true }]
])
const printed = String(logSpy.mock.calls[0]?.[0])
expect(printed).toContain('host=ssh:box-1')
expect(printed).toContain('scope: ssh:box-1')
expect(printed).toContain('not covered: local')
expect(printed).toBe(
'term_remote worker connected host=ssh:box-1 /remote/wt\npreview: <empty>\n\nscope: ssh:box-1 — not covered: local (reached through this runtime; no flag selects it)'
)
})
it('does not claim a local scope when the host never reported one', async () => {
@@ -123,8 +131,13 @@ describe('orca terminal list host scope', () => {
await main(['terminal', 'list'], '/tmp/repo')
expect(callMock.mock.calls).toEqual([
['terminal.list', { worktree: undefined, limit: undefined, includeVisualLayouts: true }]
])
const printed = String(logSpy.mock.calls[0]?.[0])
expect(printed).toContain('scope: unverifiable')
expect(printed).not.toContain('scope: local')
expect(printed).toBe(
'No terminals listed.\nscope: unverifiable — this host does not report which hosts it lists'
)
})
})
@@ -35,7 +35,7 @@ describe('dashboard visible-use telemetry', () => {
let visibility: DocumentVisibilityState
beforeEach(() => {
vi.useFakeTimers()
vi.useFakeTimers({ now: new Date('2026-10-22T12:00:00Z') })
track.mockReset().mockResolvedValue(true)
getConsentState.mockReset().mockResolvedValue({ effective: 'enabled' })
useAppStore.setState({