mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: remove seven low-value cases and repair behavioral assertions (#33453)
* test: remove low-value cases and repair behavioral assertions * test: prune repaired wall-clock finding from flaky-test baseline --------- Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
@@ -1051,7 +1051,6 @@
|
||||
3 test-no-wall-clock:src/renderer/src/components/activity/activity-auto-mark-read-loop.react185.test.tsx
|
||||
2 test-no-wall-clock:src/renderer/src/components/artifacts/artifact-list-windowing.test.tsx
|
||||
2 test-no-wall-clock:src/renderer/src/components/artifacts/ArtifactCollection.test.tsx
|
||||
1 test-no-wall-clock:src/renderer/src/components/automations/automation-list-search-rows.test.ts
|
||||
7 test-no-wall-clock:src/renderer/src/components/automations/AutomationListLocalRows.test.tsx
|
||||
1 test-no-wall-clock:src/renderer/src/components/automations/use-automation-list-search.test.tsx
|
||||
1 test-no-wall-clock:src/renderer/src/components/browser-pane/assemble-chrome/browser-workspace-pane.adoption-chrome.test.tsx
|
||||
|
||||
@@ -82,7 +82,7 @@ const FULL: RuntimeManagedWorktreeCreateArgs = {
|
||||
}
|
||||
|
||||
describe('createWorktreeWithStartupAgent', () => {
|
||||
it('starts a terminal agent with the prompt folded by the create, whatever the chat default', async () => {
|
||||
it('forwards the startup agent and prompt to the create with the chat default on', async () => {
|
||||
const { runtime, created, create } = harness()
|
||||
const prompt = 'x'.repeat(3000)
|
||||
const args = {
|
||||
@@ -100,7 +100,7 @@ describe('createWorktreeWithStartupAgent', () => {
|
||||
expect(runtime.getStructuredAgentSessionCreateSupport).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('hands a post-start agent its prompt through the create, which sends it once the agent is up', async () => {
|
||||
it('forwards a post-start agent and prompt to the create', async () => {
|
||||
const { runtime, create } = harness()
|
||||
const args = { ...FULL, startupAgent: 'aider' as const, startupPrompt: 'fix the bug' }
|
||||
|
||||
@@ -109,7 +109,7 @@ describe('createWorktreeWithStartupAgent', () => {
|
||||
expect(runtime.createManagedWorktree).toHaveBeenCalledWith(args)
|
||||
})
|
||||
|
||||
it('treats a blank prompt as none, which the create launches bare either way', async () => {
|
||||
it('omits a blank startup prompt from the create request', async () => {
|
||||
for (const startupPrompt of ['', ' \n']) {
|
||||
const { runtime, create } = harness()
|
||||
|
||||
@@ -119,7 +119,7 @@ describe('createWorktreeWithStartupAgent', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('starts a linked draft through `startupDraft`, unsent, with the agent the draft resolves', async () => {
|
||||
it('forwards a linked draft through `startupDraft` with its resolved agent', async () => {
|
||||
const { runtime, create } = harness({ draftAgent: 'codex' })
|
||||
const { createdWithAgent: _requested, ...request } = FULL
|
||||
const draft = 'https://github.com/o/r/issues/1'
|
||||
|
||||
@@ -84,7 +84,7 @@ describe('markCursorWorkspaceTrusted', () => {
|
||||
const trustFile = join(projectsDir, slugDirs[0], '.workspace-trusted')
|
||||
expect(existsSync(trustFile)).toBe(true)
|
||||
const payload = JSON.parse(readFileSync(trustFile, 'utf-8'))
|
||||
expect(payload.workspacePath).toBeTruthy()
|
||||
expect(payload.workspacePath).toBe(realpathSync.native(workspace))
|
||||
expect(typeof payload.trustedAt).toBe('string')
|
||||
} finally {
|
||||
rmSync(workspace, { recursive: true, force: true })
|
||||
@@ -152,7 +152,7 @@ describe('markCopilotFolderTrusted', () => {
|
||||
const parsed = JSON.parse(readFileSync(configPath, 'utf-8'))
|
||||
expect(Array.isArray(parsed.trustedFolders)).toBe(true)
|
||||
expect(parsed.trustedFolders.length).toBe(1)
|
||||
expect(typeof parsed.trustedFolders[0]).toBe('string')
|
||||
expect(parsed.trustedFolders[0]).toBe(realpathSync.native(workspace))
|
||||
} finally {
|
||||
rmSync(workspace, { recursive: true, force: true })
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ function counts(db: SyncDatabase): Record<string, number> {
|
||||
}
|
||||
}
|
||||
|
||||
it('writes a whole read in one transaction', () => {
|
||||
it('publishes all rows from a completed whole read', () => {
|
||||
replayTranscriptRead({ messages: userMessages('needle text', 300) })
|
||||
|
||||
const after = counts(index.db)
|
||||
|
||||
@@ -154,7 +154,7 @@ it('moves the generation when a purge reclaims rows nothing can reach', async ()
|
||||
}
|
||||
})
|
||||
|
||||
it("leaves the generation alone when a replace swaps a session's own rows", async () => {
|
||||
it('leaves the generation alone when messages attached to live sessions are deleted', async () => {
|
||||
// Deleting messages attached to live sessions must not fire the orphan-reclamation trigger.
|
||||
const root = await tempRoot()
|
||||
const path = join(root, 'index.sqlite')
|
||||
@@ -213,7 +213,7 @@ it('keeps the generation across a reopen, because the bump rides its own commit'
|
||||
}
|
||||
})
|
||||
|
||||
it('fences a reader against a writer it does not share a process with', async () => {
|
||||
it('fences a reader against another database handle moving the index', async () => {
|
||||
// A process-local generation would miss another process’s writes and admit stale cursors.
|
||||
const root = await tempRoot()
|
||||
const path = join(root, 'index.sqlite')
|
||||
|
||||
@@ -132,7 +132,7 @@ it('cuts at punctuation when the window holds no whitespace at all', async () =>
|
||||
}
|
||||
})
|
||||
|
||||
it('keeps a 9,000-character identifier whole rather than cutting at its underscores', () => {
|
||||
it('hard-cuts a 9,000-character identifier without treating underscores as boundaries', () => {
|
||||
// Underscores are token characters, so this oversized identifier requires a hard cut.
|
||||
const text = 'ab_'.repeat(3000)
|
||||
expect(text.length).toBe(9000)
|
||||
|
||||
@@ -20,7 +20,7 @@ function entry(overrides: Partial<AutomationHostCatalogEntry> = {}): AutomationH
|
||||
return {
|
||||
stableRef: { authority: { kind: 'desktop' }, selector: { kind: 'self' } },
|
||||
owner: { authority: { kind: 'desktop' }, selector: { kind: 'self' } },
|
||||
stableKey: 'desktop:self',
|
||||
stableKey: 'host:desktop:self',
|
||||
label: 'This computer',
|
||||
authorityLabel: 'Desktop',
|
||||
kind: 'self',
|
||||
@@ -39,7 +39,7 @@ function sshEntry(targetGeneration: number): AutomationHostCatalogEntry {
|
||||
authority: { kind: 'desktop' },
|
||||
selector: { kind: 'ssh', targetId: 'box', targetGeneration }
|
||||
},
|
||||
stableKey: 'desktop:ssh:box',
|
||||
stableKey: 'host:desktop:ssh:box',
|
||||
kind: 'ssh'
|
||||
})
|
||||
}
|
||||
@@ -82,13 +82,13 @@ describe('create destination resolution', () => {
|
||||
it('prefers the explicit selection and only then the active workspace', () => {
|
||||
const entries = [entry(), sshEntry(3)]
|
||||
expect(
|
||||
preselectAutomationCreateHost(entries, 'desktop:ssh:box', 'desktop:self')?.stableKey
|
||||
).toBe('desktop:ssh:box')
|
||||
expect(preselectAutomationCreateHost(entries, null, 'desktop:self')?.stableKey).toBe(
|
||||
'desktop:self'
|
||||
preselectAutomationCreateHost(entries, 'host:desktop:ssh:box', 'host:desktop:self')?.stableKey
|
||||
).toBe('host:desktop:ssh:box')
|
||||
expect(preselectAutomationCreateHost(entries, null, 'host:desktop:self')?.stableKey).toBe(
|
||||
'host:desktop:self'
|
||||
)
|
||||
// An unresolvable workspace host leaves the choice open rather than picking one.
|
||||
expect(preselectAutomationCreateHost(entries, null, 'desktop:ssh:gone')).toBeNull()
|
||||
expect(preselectAutomationCreateHost(entries, null, 'host:desktop:ssh:gone')).toBeNull()
|
||||
expect(preselectAutomationCreateHost(entries, null, null)).toBeNull()
|
||||
})
|
||||
})
|
||||
@@ -172,14 +172,14 @@ describe('offered create hosts', () => {
|
||||
it('does not blame the server for hosts another repair or none would fix', () => {
|
||||
// Unverified since disconnect: the repair is a reconnect, not an update.
|
||||
const unverified = entry({
|
||||
stableKey: 'desktop:ssh:cold',
|
||||
stableKey: 'host:desktop:ssh:cold',
|
||||
kind: 'ssh',
|
||||
querySupport: 'legacy-unscoped',
|
||||
scopeGap: 'target-unverified'
|
||||
})
|
||||
// Scoped but not yet hydrated: disabled, and no repair to name.
|
||||
const unhydrated = entry({
|
||||
stableKey: 'desktop:ssh:warm',
|
||||
stableKey: 'host:desktop:ssh:warm',
|
||||
kind: 'ssh',
|
||||
owner: null,
|
||||
catalogState: 'unhydrated'
|
||||
@@ -199,19 +199,19 @@ describe('sole create host', () => {
|
||||
}
|
||||
|
||||
it('states the only eligible host and never one of several', () => {
|
||||
expect(soleAutomationCreateHost([entry()], hydrated)?.stableKey).toBe('desktop:self')
|
||||
expect(soleAutomationCreateHost([entry()], hydrated)?.stableKey).toBe('host:desktop:self')
|
||||
expect(soleAutomationCreateHost([entry(), sshEntry(3)], hydrated)).toBeNull()
|
||||
// An orphan bucket, an unowned host, and a view-only host are not candidates at all.
|
||||
expect(
|
||||
soleAutomationCreateHost([entry(), entry({ stableKey: 'orphan', kind: 'orphan' })], hydrated)
|
||||
?.stableKey
|
||||
).toBe('desktop:self')
|
||||
).toBe('host:desktop:self')
|
||||
expect(
|
||||
soleAutomationCreateHost(
|
||||
[entry(), entry({ stableKey: 'legacy', querySupport: 'legacy-unscoped' })],
|
||||
hydrated
|
||||
)?.stableKey
|
||||
).toBe('desktop:self')
|
||||
).toBe('host:desktop:self')
|
||||
})
|
||||
|
||||
it('states nothing until the catalog has settled', () => {
|
||||
@@ -244,7 +244,7 @@ describe('create project mismatch', () => {
|
||||
addedAt: 1,
|
||||
worktreeBaseRef: 'main',
|
||||
...overrides
|
||||
} as Repo
|
||||
}
|
||||
}
|
||||
const desktopSelf = {
|
||||
authority: { kind: 'desktop' } as const,
|
||||
|
||||
@@ -68,9 +68,9 @@ describe('shouldHandleAutomationDetailTabArrowKey', () => {
|
||||
expect(shouldHandleAutomationDetailTabArrowKey(makeEvent({ target: editable }))).toBe(false)
|
||||
})
|
||||
|
||||
it('ignores keys when target is inside a modal dialog, menu, or listbox', () => {
|
||||
it.each(['dialog', 'menu', 'listbox'])('ignores keys inside a %s', (role) => {
|
||||
const dialog = document.createElement('div')
|
||||
dialog.setAttribute('role', 'dialog')
|
||||
dialog.setAttribute('role', role)
|
||||
const childButton = document.createElement('button')
|
||||
dialog.appendChild(childButton)
|
||||
document.body.appendChild(dialog)
|
||||
@@ -198,9 +198,9 @@ describe('shouldHandleAutomationDetailEscapeKey', () => {
|
||||
expect(shouldHandleAutomationDetailEscapeKey(makeEvent({ target: clearsValue }))).toBe(false)
|
||||
})
|
||||
|
||||
it('ignores Escape when target is inside a modal dialog, menu, or listbox', () => {
|
||||
it.each(['dialog', 'menu', 'listbox'])('ignores Escape inside a %s', (role) => {
|
||||
const dialog = document.createElement('div')
|
||||
dialog.setAttribute('role', 'dialog')
|
||||
dialog.setAttribute('role', role)
|
||||
const childButton = document.createElement('button')
|
||||
dialog.appendChild(childButton)
|
||||
document.body.appendChild(dialog)
|
||||
|
||||
+1
-1
@@ -49,7 +49,7 @@ beforeEach(async () => {
|
||||
})
|
||||
|
||||
describe('extra agent args capability gate', () => {
|
||||
it('refuses a create or move to a host without the capability before writing', async () => {
|
||||
it('refuses a create on a host without the capability before writing', async () => {
|
||||
const { createAutomationForDestination } = await client()
|
||||
getRuntimeEnvironmentStatus.mockResolvedValue(LEGACY_HOST)
|
||||
|
||||
|
||||
@@ -137,7 +137,7 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('automation host query controller', () => {
|
||||
it('advances catalog generations before fetching anything', async () => {
|
||||
it('syncs catalog generations and fetches the catalog host', async () => {
|
||||
const listScoped = vi.fn(() => Promise.resolve(emptyList()))
|
||||
const { controller } = createController(listScoped)
|
||||
expect(getAuthorityCatalogGeneration(RUNTIME)).toBe(0)
|
||||
|
||||
@@ -169,16 +169,15 @@ describe('automation host cache invalidation scope', () => {
|
||||
expect(cache.freshness(RUNTIME_SELF)).toBe('missing')
|
||||
})
|
||||
|
||||
it('evicts a departed entry and caps the retired pool', () => {
|
||||
it('evicts departed entries and rejects work captured before retirement', () => {
|
||||
const cache = createCache({ retiredLimit: 1 })
|
||||
cache.commit(cache.beginRequest(DESKTOP_SELF), { rows: [row('a')] })
|
||||
cache.commit(cache.beginRequest(RUNTIME_SELF), { rows: [row('b')] })
|
||||
const stale = cache.beginRequest(RUNTIME_SELF)
|
||||
cache.evict(hostStableKey(DESKTOP_SELF))
|
||||
cache.evict(hostStableKey(RUNTIME_SELF))
|
||||
expect(cache.keys()).toEqual([])
|
||||
// The revived entry keeps its advanced generation, so nothing captured before eviction commits.
|
||||
const stale = cache.beginRequest(RUNTIME_SELF)
|
||||
cache.invalidate(RUNTIME_SELF)
|
||||
cache.beginRequest(RUNTIME_SELF)
|
||||
expect(cache.commit(stale, { rows: [] })).toBe(false)
|
||||
})
|
||||
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import type { RuntimeStatus } from '../../../../shared/runtime-types'
|
||||
import { createCompatibleRuntimeStatusResponse } from '@/runtime/runtime-compatibility-test-fixture'
|
||||
import { AUTOMATION_LIST_HOST_SCOPE_RUNTIME_CAPABILITY } from '../../../../shared/protocol-version'
|
||||
import {
|
||||
buildAutomationHostCatalogSource,
|
||||
@@ -8,6 +10,14 @@ import {
|
||||
type AutomationCatalogSshSource
|
||||
} from './automation-host-catalog-source'
|
||||
|
||||
function status(overrides: Partial<RuntimeStatus> = {}): RuntimeStatus {
|
||||
const response = createCompatibleRuntimeStatusResponse()
|
||||
if (!response.ok) {
|
||||
throw new Error(response.error.message)
|
||||
}
|
||||
return { ...response.result, ...overrides }
|
||||
}
|
||||
|
||||
function runtime(
|
||||
overrides: Partial<AutomationCatalogRuntimeSource> = {}
|
||||
): AutomationCatalogRuntimeSource {
|
||||
@@ -32,7 +42,7 @@ describe('automation host catalog source', () => {
|
||||
it('treats a never-probed environment as loading, not as down', () => {
|
||||
expect(runtimeAuthorityHealth(runtime())).toBe('loading')
|
||||
expect(runtimeAuthorityHealth(runtime({ status: { status: null } }))).toBe('unavailable')
|
||||
expect(runtimeAuthorityHealth(runtime({ status: { status: {} as never } }))).toBe('fresh')
|
||||
expect(runtimeAuthorityHealth(runtime({ status: { status: status() } }))).toBe('fresh')
|
||||
})
|
||||
|
||||
it('assumes scoped support until the capability set is actually known', () => {
|
||||
@@ -40,14 +50,14 @@ describe('automation host catalog source', () => {
|
||||
// guessing legacy here would only discard owners on a modern host.
|
||||
expect(runtimeQuerySupport(runtime())).toBe('scoped')
|
||||
expect(runtimeQuerySupport(runtime({ status: { status: null } }))).toBe('scoped')
|
||||
expect(
|
||||
runtimeQuerySupport(runtime({ status: { status: { capabilities: [] } as never } }))
|
||||
).toBe('legacy-unscoped')
|
||||
expect(runtimeQuerySupport(runtime({ status: { status: status({ capabilities: [] }) } }))).toBe(
|
||||
'legacy-unscoped'
|
||||
)
|
||||
expect(
|
||||
runtimeQuerySupport(
|
||||
runtime({
|
||||
status: {
|
||||
status: { capabilities: [AUTOMATION_LIST_HOST_SCOPE_RUNTIME_CAPABILITY] } as never
|
||||
status: status({ capabilities: [AUTOMATION_LIST_HOST_SCOPE_RUNTIME_CAPABILITY] })
|
||||
}
|
||||
})
|
||||
)
|
||||
|
||||
@@ -605,16 +605,4 @@ describe('automation host diagnostics bookkeeping', () => {
|
||||
byStableKey: {}
|
||||
})
|
||||
})
|
||||
|
||||
it('never copies an automation, a prompt, or a name into a counter', () => {
|
||||
const diagnostics = createAutomationHostDiagnostics()
|
||||
diagnostics.recordResponse({
|
||||
authorityKey: 'a',
|
||||
stableKey: 'k1',
|
||||
rows: 3,
|
||||
durationMs: 12,
|
||||
approxSerializedChars: 900
|
||||
})
|
||||
expect(JSON.stringify(diagnostics.snapshot())).not.toMatch(/prompt|automation-|secret/i)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -45,7 +45,7 @@ describe('execution health', () => {
|
||||
expect(resolveSshExecutionHealth('unhydrated', 'connected', 'disconnected')).toBe('unknown')
|
||||
})
|
||||
|
||||
it('maps every SSH status onto a distinct execution state', () => {
|
||||
it('maps reported SSH statuses and absent status to execution health', () => {
|
||||
expect(resolveSshExecutionHealth('authoritative', 'connected', undefined)).toBe('connected')
|
||||
expect(resolveSshExecutionHealth('authoritative', 'reconnecting', undefined)).toBe('connecting')
|
||||
expect(resolveSshExecutionHealth('authoritative', 'deploying-relay', undefined)).toBe(
|
||||
|
||||
@@ -55,8 +55,6 @@ const SCOPED_AUTHORITIES = AUTHORITY_COUNT / 2
|
||||
const HOST_COUNT = AUTHORITY_COUNT * ENTRIES_PER_AUTHORITY
|
||||
const AUTOMATION_COUNT = HOST_COUNT * AUTOMATIONS_PER_HOST
|
||||
const SSH_TARGET_GENERATION = 3
|
||||
// Doc 417: a refresh at this size must not block the renderer for a frame budget's worth of work.
|
||||
const LONG_TASK_BUDGET_MS = 50
|
||||
|
||||
function authorityAt(index: number): AutomationAuthorityRef {
|
||||
return { kind: 'runtime', environmentId: `env-${index}`, pairingRevision: index + 1 }
|
||||
@@ -230,31 +228,6 @@ async function roundTrip<T>(environmentId: string, value: () => T): Promise<T> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Longest gap between successive macrotasks: a synchronous block anywhere in the
|
||||
* refresh delays the next timer by its own duration, which is the only way to
|
||||
* observe "no long task" rather than to assert it about one function.
|
||||
*/
|
||||
function watchLongTasks(): () => number {
|
||||
let worst = 0
|
||||
let last = performance.now()
|
||||
let running = true
|
||||
const tick = (): void => {
|
||||
if (!running) {
|
||||
return
|
||||
}
|
||||
const at = performance.now()
|
||||
worst = Math.max(worst, at - last)
|
||||
last = at
|
||||
setTimeout(tick, 0)
|
||||
}
|
||||
setTimeout(tick, 0)
|
||||
return () => {
|
||||
running = false
|
||||
return worst
|
||||
}
|
||||
}
|
||||
|
||||
function harness(): {
|
||||
cache: AutomationHostCache
|
||||
refresh: (options?: { force?: boolean }) => Promise<void>
|
||||
@@ -378,15 +351,6 @@ describe('one refresh of 50 hosts carrying 1,000 automations', () => {
|
||||
expect(snap.totals.rows).toBe(AUTOMATION_COUNT)
|
||||
expect(perHost).toBe(AUTOMATION_COUNT)
|
||||
})
|
||||
|
||||
it('does no synchronous work long enough to drop a frame', async () => {
|
||||
const { refresh } = harness()
|
||||
const stop = watchLongTasks()
|
||||
|
||||
await refresh()
|
||||
|
||||
expect(stop()).toBeLessThan(LONG_TASK_BUDGET_MS)
|
||||
})
|
||||
})
|
||||
|
||||
describe('relay cost the request pool cannot see', () => {
|
||||
@@ -428,7 +392,7 @@ describe('relay cost the request pool cannot see', () => {
|
||||
})
|
||||
|
||||
describe('the commit fence under real concurrency', () => {
|
||||
it('commits nothing from an authority that re-paired while its answer was in flight', async () => {
|
||||
it('commits nothing from an authority invalidated while its answer was in flight', async () => {
|
||||
const { cache, refresh } = harness()
|
||||
// One modern and one old server, so both the per-entry and the fan-out arm
|
||||
// are fenced out while the other 40 hosts keep landing around them.
|
||||
|
||||
@@ -209,16 +209,4 @@ describe('automation list empty state', () => {
|
||||
expect(state.kind).toBe('host-empty')
|
||||
expect(state.title).toBe('No automations on web-01')
|
||||
})
|
||||
|
||||
it('keeps each empty string exclusive to its own condition', () => {
|
||||
const titles = [
|
||||
resolveAutomationListEmptyState(input()).title,
|
||||
resolveAutomationListEmptyState(input({ resolution: ALL_HOSTS })).title,
|
||||
resolveAutomationListEmptyState(input({ searchActive: true, hostRowCount: 2 })).title,
|
||||
resolveAutomationListEmptyState(
|
||||
input({ resolution: hostResolution({ entry: entry({ authorityHealth: 'stale-error' }) }) })
|
||||
).title
|
||||
]
|
||||
expect(new Set(titles).size).toBe(4)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -79,7 +79,9 @@ describe('automation search row fields', () => {
|
||||
})
|
||||
|
||||
it('indexes external jobs by provider, target host, and workdir', () => {
|
||||
const [entry] = buildExternalAutomationListEntries([makeScopedExternalManager()])
|
||||
const manager = makeScopedExternalManager()
|
||||
manager.manager.jobs[0]!.workdir = '/srv/sweep-project'
|
||||
const [entry] = buildExternalAutomationListEntries([manager])
|
||||
if (!entry) {
|
||||
throw new Error('fixture produced no external entry')
|
||||
}
|
||||
@@ -88,6 +90,7 @@ describe('automation search row fields', () => {
|
||||
expect(fields.agent).toBe('OpenClaw')
|
||||
expect(fields.host).toBe('This computer')
|
||||
expect(fields.prompt).toBe('Sweep')
|
||||
expect(fields.project).toBe('/srv/sweep-project')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -131,14 +134,14 @@ describe('automation search row index', () => {
|
||||
})
|
||||
|
||||
it('fingerprints identical content identically across a refresh tick', () => {
|
||||
const build = (): ReturnType<typeof buildAutomationSearchRowSources> =>
|
||||
const build = (nextRunAt: number): ReturnType<typeof buildAutomationSearchRowSources> =>
|
||||
buildAutomationSearchRowSources(
|
||||
[makeAutomationListRow({ automation: makeAutomation({ nextRunAt: Date.now() }) })],
|
||||
[makeAutomationListRow({ automation: makeAutomation({ nextRunAt }) })],
|
||||
{ repoMap }
|
||||
)
|
||||
// Why: nextRunAt churns on every tick and must not invalidate the index.
|
||||
expect(buildAutomationListSearchRowFingerprint(build())).toBe(
|
||||
buildAutomationListSearchRowFingerprint(build())
|
||||
expect(buildAutomationListSearchRowFingerprint(build(100))).toBe(
|
||||
buildAutomationListSearchRowFingerprint(build(200))
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
@@ -68,7 +68,7 @@ describe('buildAutomationRunContextForRepo', () => {
|
||||
buildAutomationRunContextForRepo({
|
||||
repoId: 'repo-builder',
|
||||
repos: [repo('repo-builder')],
|
||||
projectHostSetups: [setup({ setupState: 'setting-up' })]
|
||||
projectHostSetups: [setup({ hostId: 'local', setupState: 'setting-up' })]
|
||||
})
|
||||
).toBeNull()
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ describe('command token scanner', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('extracts path basenames without allocating path segment arrays', () => {
|
||||
it('extracts basenames from Windows and POSIX paths', () => {
|
||||
expect(getCommandTokenPathBasename('C:\\Program Files\\Orca\\codex.cmd')).toBe('codex.cmd')
|
||||
expect(getCommandTokenPathBasename('/usr/local/bin/omp')).toBe('omp')
|
||||
})
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { claudeBackgroundArgs } from './claude-background-run-isolation'
|
||||
import { afterEach, describe, expect, it, vi } from 'vitest'
|
||||
import {
|
||||
COMMIT_MESSAGE_AGENT_SPECS,
|
||||
@@ -26,26 +25,6 @@ afterEach(() => {
|
||||
})
|
||||
|
||||
describe('COMMIT_MESSAGE_AGENT_SPECS', () => {
|
||||
it('exposes the installed local agents as commit-message agents', () => {
|
||||
const ids = listCommitMessageAgentIds().sort()
|
||||
expect(ids).toEqual([
|
||||
'amp',
|
||||
'antigravity',
|
||||
'claude',
|
||||
'codex',
|
||||
'copilot',
|
||||
'cursor',
|
||||
'dsh',
|
||||
'jcode',
|
||||
'kimi',
|
||||
'muse',
|
||||
'omp',
|
||||
'opencode',
|
||||
'opencode2',
|
||||
'pi'
|
||||
])
|
||||
})
|
||||
|
||||
it('uses the expected defaults for core agents', () => {
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.claude?.defaultModelId).toBe('sonnet')
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.codex?.defaultModelId).toBe('gpt-5.6-terra')
|
||||
@@ -106,28 +85,6 @@ describe('COMMIT_MESSAGE_AGENT_SPECS', () => {
|
||||
}
|
||||
})
|
||||
|
||||
it('lists Copilot hosted CLI models even when account policy filters the picker', () => {
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.copilot?.defaultModelId).toBe('gpt-5.4')
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.copilot?.models.map((m) => m.id)).toEqual([
|
||||
'auto',
|
||||
'claude-haiku-4.5',
|
||||
'claude-sonnet-4.5',
|
||||
'claude-sonnet-4.6',
|
||||
'claude-opus-4.5',
|
||||
'claude-opus-4.6',
|
||||
'claude-opus-4.6-fast',
|
||||
'claude-opus-4.7',
|
||||
'gpt-4.1',
|
||||
'gpt-5-mini',
|
||||
'gpt-5.2',
|
||||
'gpt-5.2-codex',
|
||||
'gpt-5.3-codex',
|
||||
'gpt-5.4',
|
||||
'gpt-5.4-mini',
|
||||
'gpt-5.5'
|
||||
])
|
||||
})
|
||||
|
||||
it('treats disabled default agents as unavailable for implicit Source Control AI choices', () => {
|
||||
expect(resolveCommitMessageAgentChoice(null, 'codex', ['codex'])).toBe('claude')
|
||||
expect(resolveCommitMessageAgentChoice(null, null, ['claude'])).toBeNull()
|
||||
@@ -174,7 +131,7 @@ describe('COMMIT_MESSAGE_AGENT_SPECS', () => {
|
||||
expect(listCommitMessageAgentIds()).not.toContain(CUSTOM_AGENT_ID)
|
||||
})
|
||||
|
||||
it('orders Codex models by version descending to match the official picker', () => {
|
||||
it('orders seeded Codex models by version descending', () => {
|
||||
const ids = COMMIT_MESSAGE_AGENT_SPECS.codex?.models.map((m) => m.id)
|
||||
expect(ids).toEqual([
|
||||
'gpt-5.6-terra',
|
||||
@@ -215,7 +172,9 @@ describe('buildArgs (Claude)', () => {
|
||||
'haiku',
|
||||
'--permission-mode',
|
||||
'plan',
|
||||
...claudeBackgroundArgs()
|
||||
'--strict-mcp-config',
|
||||
'--settings',
|
||||
'{"disableAllHooks":true}'
|
||||
])
|
||||
})
|
||||
|
||||
@@ -235,7 +194,9 @@ describe('buildArgs (Claude)', () => {
|
||||
'plan',
|
||||
'--effort',
|
||||
'high',
|
||||
...claudeBackgroundArgs()
|
||||
'--strict-mcp-config',
|
||||
'--settings',
|
||||
'{"disableAllHooks":true}'
|
||||
])
|
||||
})
|
||||
|
||||
@@ -296,7 +257,15 @@ describe('buildArgs (Jcode)', () => {
|
||||
const args = spec.buildArgs({ prompt: 'name this branch', model: 'claude-haiku-4-5' })
|
||||
const runIndex = args.indexOf('run')
|
||||
expect(runIndex).toBeGreaterThan(0)
|
||||
expect(args.slice(0, runIndex).every((arg) => arg.startsWith('--') || arg !== 'run')).toBe(true)
|
||||
expect(args.slice(0, runIndex)).toEqual([
|
||||
'--no-update',
|
||||
'--quiet',
|
||||
'--no-selfdev',
|
||||
'--tool-profile',
|
||||
'none',
|
||||
'--model',
|
||||
'claude-haiku-4-5'
|
||||
])
|
||||
expect(args.slice(runIndex)).toEqual(['run', '--json', 'name this branch'])
|
||||
})
|
||||
|
||||
@@ -385,7 +354,9 @@ describe('model discovery parsers', () => {
|
||||
'--output-format',
|
||||
'stream-json',
|
||||
'--verbose',
|
||||
...claudeBackgroundArgs()
|
||||
'--strict-mcp-config',
|
||||
'--settings',
|
||||
'{"disableAllHooks":true}'
|
||||
])
|
||||
const payload = JSON.parse(discovery?.stdinPayload ?? '') as {
|
||||
type?: string
|
||||
|
||||
@@ -24,7 +24,7 @@ describe('buildCommitMessagePrompt', () => {
|
||||
expect(prompt).not.toContain('Additional user prompt:')
|
||||
})
|
||||
|
||||
it('keeps a custom prompt in a separate bounded section', () => {
|
||||
it('keeps a custom prompt in a separate section', () => {
|
||||
const prompt = buildCommitMessagePrompt(
|
||||
{
|
||||
branch: null,
|
||||
|
||||
@@ -18,7 +18,7 @@ describe('OMP Source Control AI', () => {
|
||||
})
|
||||
}
|
||||
)
|
||||
it('delivers large diffs on stdin and keeps generation isolated from tools and extensions', () => {
|
||||
it('plans stdin delivery with tools and extensions disabled', () => {
|
||||
const spec = getCommitMessageAgentSpec('omp')
|
||||
expect(spec?.promptDelivery).toBe('stdin')
|
||||
if (!spec) {
|
||||
|
||||
@@ -6,7 +6,7 @@ import {
|
||||
} from './conversation-name-generation'
|
||||
|
||||
describe('conversation name generation', () => {
|
||||
it('bounds the first prompt in both the built-in prompt and template variable', () => {
|
||||
it('bounds the first prompt and includes it in the built-in prompt', () => {
|
||||
const firstPrompt = `Start ${'x'.repeat(5000)}`
|
||||
const clamped = clampConversationNameFirstPrompt(firstPrompt)
|
||||
expect(clamped).toHaveLength(4000)
|
||||
|
||||
@@ -218,10 +218,13 @@ describe('nameDarwinTerminals', () => {
|
||||
directory.entries = [
|
||||
{ name: 'gone', rdev: 0x10000009n, error: new Error('ENOENT') },
|
||||
{ name: 'denied', rdev: 0x10000009n, error: new Error('EACCES') },
|
||||
{ name: 'ttys009', rdev: 0x10000009n }
|
||||
{ name: 'cu.found', rdev: 0x10000009n }
|
||||
]
|
||||
|
||||
expect(await nameDarwinTerminals(darwinRow('16/9'), directory)).toBe(darwinRow('ttys009'))
|
||||
expect(await nameDarwinTerminals(darwinRow('16/9'), directory)).toBe(darwinRow('cu.found'))
|
||||
expect(directory.readPaths).toEqual(
|
||||
['ttys009', 'gone', 'denied', 'cu.found'].map((name) => join('/dev', name))
|
||||
)
|
||||
})
|
||||
|
||||
it('rejects directory open failures so the reader can fall back to ordinary tty ps', async () => {
|
||||
|
||||
@@ -62,7 +62,7 @@ function replayReadyAtMs(
|
||||
}
|
||||
|
||||
describe('grok startup trace replay (alternate-screen mode)', () => {
|
||||
it('delivers on the composer frame instead of waiting out the hard timeout', () => {
|
||||
it('reports readiness within the first second of the alternate-screen trace', () => {
|
||||
const readyAt = replayReadyAtMs('grok-composer-prompt', GROK_STARTUP_PTY_TRACE)
|
||||
expect(readyAt).not.toBeNull()
|
||||
expect(readyAt).toBeLessThan(1000)
|
||||
@@ -74,7 +74,7 @@ describe('grok startup trace replay (alternate-screen mode)', () => {
|
||||
expect(replayReadyAtMs('render-quiet-after-bracketed-paste', GROK_STARTUP_PTY_TRACE)).toBeNull()
|
||||
})
|
||||
|
||||
it('fires on the same frame that paints the composer box', () => {
|
||||
it('reports readiness on the frame that paints the composer box', () => {
|
||||
const composerFrame = GROK_STARTUP_PTY_TRACE.find((chunk) => chunk.data?.includes('❯'))
|
||||
expect(composerFrame).toBeDefined()
|
||||
expect(replayReadyAtMs('grok-composer-prompt', GROK_STARTUP_PTY_TRACE)).toBe(composerFrame?.t)
|
||||
@@ -82,7 +82,7 @@ describe('grok startup trace replay (alternate-screen mode)', () => {
|
||||
})
|
||||
|
||||
describe('grok startup trace replay (inline mode, no alternate screen)', () => {
|
||||
it('still delivers through the quiet window when the marker never anchors', () => {
|
||||
it('arms a quiet window before the inline trace reaches the modeled timeout', () => {
|
||||
// Why: inline grok emits no \x1b[?1049h, so the composer glyph never counts.
|
||||
// Anchoring the quiet window on the alt-screen switch too would leave this
|
||||
// launch with NO delivery path — orca-runtime drops the draft when readiness
|
||||
@@ -92,28 +92,9 @@ describe('grok startup trace replay (inline mode, no alternate screen)', () => {
|
||||
expect(readyAt).toBeLessThan(HARD_TIMEOUT_MS)
|
||||
})
|
||||
|
||||
it('matches the default signal exactly, so inline launches keep their old timing', () => {
|
||||
it('matches the default signal timing for the inline trace', () => {
|
||||
expect(replayReadyAtMs('grok-composer-prompt', GROK_INLINE_STARTUP_PTY_TRACE)).toBe(
|
||||
replayReadyAtMs('render-quiet-after-bracketed-paste', GROK_INLINE_STARTUP_PTY_TRACE)
|
||||
)
|
||||
})
|
||||
|
||||
it('reports the hard timeout, not a late marker, once the waiters have settled', () => {
|
||||
// Guards the model above: the real waiters resolve at 8s, so a marker landing
|
||||
// after that must not be reported as a delivery time.
|
||||
const lateMarker: GrokStartupTraceChunk[] = [
|
||||
{ t: 0, data: '\x1b[?1049h' },
|
||||
{ t: 8500, data: '\x1b[38;2;200;200;200m❯ ' }
|
||||
]
|
||||
expect(replayReadyAtMs('grok-composer-prompt', lateMarker)).toBeNull()
|
||||
})
|
||||
|
||||
it('records a startup with no alternate-screen switch', () => {
|
||||
// Guards the fixture itself: if a future re-recording captures alt-screen
|
||||
// output, the inline assertions above would silently stop testing inline.
|
||||
expect(GROK_INLINE_STARTUP_PTY_TRACE.some((chunk) => chunk.data?.includes('\x1b[?1049h'))).toBe(
|
||||
false
|
||||
)
|
||||
expect(GROK_INLINE_STARTUP_PTY_TRACE.some((chunk) => chunk.data?.includes('❯'))).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ import { TUI_AGENT_CONFIG } from './tui-agent-config'
|
||||
|
||||
describe('DSH first launch', () => {
|
||||
it.each(['darwin', 'linux', 'win32'] as const)(
|
||||
'selects the current workspace before pasting the task on %s',
|
||||
'plans the current workspace with task input deferred on %s',
|
||||
(platform) => {
|
||||
const plan = buildAgentStartupPlan({
|
||||
agent: 'dsh',
|
||||
|
||||
@@ -3,8 +3,9 @@ import emojiShortcodes from 'emojibase-data/en/shortcodes/emojibase.json'
|
||||
|
||||
async function importConfiguredCatalog() {
|
||||
const catalog = await import('./emoji-shortcode-catalog.js')
|
||||
catalog.setEmojiShortcodeDatasetLoader(() => emojiShortcodes)
|
||||
return catalog
|
||||
const loadDataset = vi.fn(() => emojiShortcodes)
|
||||
catalog.setEmojiShortcodeDatasetLoader(loadDataset)
|
||||
return { catalog, loadDataset }
|
||||
}
|
||||
|
||||
describe('emoji shortcode catalog laziness', () => {
|
||||
@@ -13,18 +14,21 @@ describe('emoji shortcode catalog laziness', () => {
|
||||
})
|
||||
|
||||
it('does not build the catalog when the shared module is imported', async () => {
|
||||
const catalog = await importConfiguredCatalog()
|
||||
const { catalog, loadDataset } = await importConfiguredCatalog()
|
||||
|
||||
expect(catalog.isEmojiShortcodeCatalogBuiltForTest()).toBe(false)
|
||||
expect(loadDataset).not.toHaveBeenCalled()
|
||||
|
||||
expect(catalog.getStandardEmojiShortcodeEntries().length).toBeGreaterThan(1000)
|
||||
expect(catalog.isEmojiShortcodeCatalogBuiltForTest()).toBe(true)
|
||||
const entries = catalog.getStandardEmojiShortcodeEntries()
|
||||
expect(entries).toContainEqual({ emoji: '🎉', shortcode: 'party' })
|
||||
expect(catalog.getStandardEmojiShortcodeEntries()).toBe(entries)
|
||||
expect(loadDataset).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('builds on first use and keeps the main process off the eager path', async () => {
|
||||
const catalog = await importConfiguredCatalog()
|
||||
it('loads once when replacing emoji and reuses the catalog', async () => {
|
||||
const { catalog, loadDataset } = await importConfiguredCatalog()
|
||||
|
||||
expect(catalog.replaceKnownEmojiWithShortcodes('ship \u{1F389}')).toBe('ship party ')
|
||||
expect(catalog.isEmojiShortcodeCatalogBuiltForTest()).toBe(true)
|
||||
expect(catalog.replaceKnownEmojiWithShortcodes('again 🎉')).toBe('again party ')
|
||||
expect(loadDataset).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,8 +2,7 @@ import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
buildServeSimKeyboardFramesForKey,
|
||||
buildServeSimKeyboardFramesForText,
|
||||
encodeServeSimKeyboardFrame,
|
||||
SERVE_SIM_KEYBOARD_MESSAGE_TAG
|
||||
encodeServeSimKeyboardFrame
|
||||
} from './emulator-keyboard-frame'
|
||||
|
||||
describe('serve-sim keyboard frames', () => {
|
||||
@@ -46,7 +45,7 @@ describe('serve-sim keyboard frames', () => {
|
||||
it('encodes serve-sim keyboard messages with the binary keyboard tag', () => {
|
||||
const frame = encodeServeSimKeyboardFrame({ type: 'down', usage: 4 })
|
||||
|
||||
expect(frame[0]).toBe(SERVE_SIM_KEYBOARD_MESSAGE_TAG)
|
||||
expect(frame[0]).toBe(0x06)
|
||||
expect(JSON.parse(new TextDecoder().decode(frame.subarray(1)))).toEqual({
|
||||
type: 'down',
|
||||
usage: 4
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
EPHEMERAL_SETUP_TERMINAL_WORKTREE_ID_PREFIX,
|
||||
brandEphemeralSetupTerminalWorktreeId,
|
||||
isEphemeralSetupTerminalWorktreeId
|
||||
} from './ephemeral-setup-terminal-worktree-id'
|
||||
@@ -8,7 +7,7 @@ import {
|
||||
describe('ephemeral setup terminal worktree id', () => {
|
||||
it('brands a panel id with the ephemeral prefix', () => {
|
||||
expect(brandEphemeralSetupTerminalWorktreeId('feature-wall-orchestration-skill-terminal')).toBe(
|
||||
`${EPHEMERAL_SETUP_TERMINAL_WORKTREE_ID_PREFIX}feature-wall-orchestration-skill-terminal`
|
||||
'ephemeral-setup-terminal:feature-wall-orchestration-skill-terminal'
|
||||
)
|
||||
})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user