mirror of
https://github.com/stablyai/orca.git
synced 2026-10-30 16:47:34 +00:00
test: remove redundant renderer and shared checks and strengthen assertions (#33625)
Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
+1
-1
@@ -166,7 +166,7 @@ describe('getAutomationRunHistoryArrowTarget', () => {
|
||||
).toBe(run1)
|
||||
})
|
||||
|
||||
it('defaults to index 0 on ArrowDown when nothing was selected', () => {
|
||||
it('moves down from the first run when nothing was selected', () => {
|
||||
expect(
|
||||
getAutomationRunHistoryArrowTarget({
|
||||
runs,
|
||||
|
||||
@@ -132,7 +132,7 @@ describe('automation run output snapshot buffer', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('owns the exact UTF-16 tail of one oversized chunk', () => {
|
||||
it('retains the exact UTF-16 tail of one oversized chunk', () => {
|
||||
const buffer = createAutomationRunOutputSnapshotBuffer()
|
||||
const retained = `\ude00${'A'.repeat(256 * 1024 - 2)}\ud83d`
|
||||
|
||||
|
||||
@@ -143,7 +143,7 @@ describe('automation run view state', () => {
|
||||
).toMatchObject({ availability: 'metadata', actionLabel: 'View run', canOpen: false })
|
||||
})
|
||||
|
||||
it('keeps skipped or missing-workspace runs as metadata-only history', () => {
|
||||
it('keeps runs without a workspace as metadata-only history', () => {
|
||||
expect(
|
||||
getAutomationRunViewState({
|
||||
run: makeRun({ workspaceId: null, terminalSessionId: null }),
|
||||
|
||||
@@ -112,6 +112,7 @@ describe('listScopedAutomations', () => {
|
||||
await expect(listScopedAutomations(RUNTIME, { kind: 'self' })).rejects.toThrow(
|
||||
'runtime_environment_revision_changed'
|
||||
)
|
||||
expect(callRuntimeRpc).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('does not query a host that never advertised host scope', async () => {
|
||||
@@ -125,10 +126,10 @@ describe('listScopedAutomations', () => {
|
||||
|
||||
// An unreachable host proves nothing about its version, so it must not be reported as too old.
|
||||
it('propagates an unreachable authority instead of calling it incompatible', async () => {
|
||||
const { listScopedAutomations, AutomationHostScopeUnsupportedError } = await client()
|
||||
const { listScopedAutomations } = await client()
|
||||
getRuntimeEnvironmentStatus.mockRejectedValue(new Error('runtime_unavailable'))
|
||||
await expect(listScopedAutomations(RUNTIME, { kind: 'self' })).rejects.not.toBeInstanceOf(
|
||||
AutomationHostScopeUnsupportedError
|
||||
await expect(listScopedAutomations(RUNTIME, { kind: 'self' })).rejects.toThrow(
|
||||
'runtime_unavailable'
|
||||
)
|
||||
})
|
||||
})
|
||||
@@ -136,19 +137,24 @@ describe('listScopedAutomations', () => {
|
||||
describe('capability probe dedupe', () => {
|
||||
it('shares one in-flight probe across concurrent calls to the same incarnation', async () => {
|
||||
const { listScopedAutomations } = await client()
|
||||
getRuntimeEnvironmentStatus.mockImplementation(async () => {
|
||||
await new Promise((resolve) => setTimeout(resolve, 0))
|
||||
return ALL_CAPABILITIES
|
||||
let completeProbe = (_status: typeof ALL_CAPABILITIES): void => {}
|
||||
const probe = new Promise<typeof ALL_CAPABILITIES>((resolve) => {
|
||||
completeProbe = resolve
|
||||
})
|
||||
getRuntimeEnvironmentStatus.mockReturnValue(probe)
|
||||
callRuntimeRpc.mockResolvedValue({ automations: [], items: [], orphanCount: 0 })
|
||||
await Promise.all([
|
||||
const requests = [
|
||||
listScopedAutomations(RUNTIME, { kind: 'self' }),
|
||||
listScopedAutomations(RUNTIME, { kind: 'orphan' })
|
||||
])
|
||||
]
|
||||
expect(getRuntimeEnvironmentStatus).toHaveBeenCalledTimes(1)
|
||||
expect(callRuntimeRpc).not.toHaveBeenCalled()
|
||||
completeProbe(ALL_CAPABILITIES)
|
||||
await Promise.all(requests)
|
||||
expect(getRuntimeEnvironmentStatus).toHaveBeenCalledTimes(1)
|
||||
})
|
||||
|
||||
it('never re-asks about a capability the incarnation already confirmed', async () => {
|
||||
it('caches confirmed list capabilities and re-probes mutations', async () => {
|
||||
const { listScopedAutomations, updateAutomationForOwner } = await client()
|
||||
getRuntimeEnvironmentStatus.mockResolvedValue(ALL_CAPABILITIES)
|
||||
callRuntimeRpc.mockResolvedValue({
|
||||
@@ -159,7 +165,7 @@ describe('capability probe dedupe', () => {
|
||||
})
|
||||
await listScopedAutomations(RUNTIME, { kind: 'self' })
|
||||
await listScopedAutomations(RUNTIME, { kind: 'orphan' })
|
||||
// A different capability confirmed by the same status answer is also cached.
|
||||
expect(getRuntimeEnvironmentStatus).toHaveBeenCalledTimes(1)
|
||||
await updateAutomationForOwner(SSH_OWNER, 'a1', { enabled: false })
|
||||
// Mutations re-probe because in-place runtime replacement can invalidate capabilities under the same pairing.
|
||||
expect(getRuntimeEnvironmentStatus).toHaveBeenCalledTimes(2)
|
||||
@@ -325,11 +331,9 @@ describe('orphan-fenced mutations', () => {
|
||||
|
||||
// An unreachable host is a retry, not an upgrade prompt — the orphan arm inherits this.
|
||||
it('propagates an unreachable authority instead of calling it incompatible', async () => {
|
||||
const { deleteOrphanAutomation, AutomationHostScopeUnsupportedError } = await client()
|
||||
const { deleteOrphanAutomation } = await client()
|
||||
getRuntimeEnvironmentStatus.mockRejectedValue(new Error('runtime_unavailable'))
|
||||
await expect(deleteOrphanAutomation(RUNTIME, 'a1')).rejects.not.toBeInstanceOf(
|
||||
AutomationHostScopeUnsupportedError
|
||||
)
|
||||
await expect(deleteOrphanAutomation(RUNTIME, 'a1')).rejects.toThrow('runtime_unavailable')
|
||||
})
|
||||
|
||||
it('routes a desktop orphan over the local runtime target, unprobed', async () => {
|
||||
@@ -385,22 +389,13 @@ describe('orphan-fenced mutations', () => {
|
||||
})
|
||||
|
||||
// Keep orphan and owned read-only history arms equally unprobed.
|
||||
it('probes on the orphan history read exactly as often as the owned read does', async () => {
|
||||
it('does not probe either owned or orphan history reads', async () => {
|
||||
const { listAutomationRunsForOwner, listOrphanAutomationRuns } = await client()
|
||||
callRuntimeRpc.mockResolvedValue({ runs: [] })
|
||||
await listAutomationRunsForOwner(SSH_OWNER, 'a1')
|
||||
const ownedProbes = getRuntimeEnvironmentStatus.mock.calls.length
|
||||
getRuntimeEnvironmentStatus.mockClear()
|
||||
expect(getRuntimeEnvironmentStatus).not.toHaveBeenCalled()
|
||||
await listOrphanAutomationRuns(RUNTIME, 'a1')
|
||||
expect(getRuntimeEnvironmentStatus.mock.calls.length).toBe(ownedProbes)
|
||||
})
|
||||
|
||||
it('cannot be handed an owner precondition — the fence is not a parameter', async () => {
|
||||
const { updateOrphanAutomation, ORPHAN_OWNER_PRECONDITION } = await client()
|
||||
callRuntimeRpc.mockResolvedValue({ automation: { id: 'a1' } })
|
||||
await updateOrphanAutomation(DESKTOP, 'a1', { enabled: false })
|
||||
expect(callRuntimeRpc.mock.calls[0]?.[2]?.expectedOwner).toEqual(ORPHAN_OWNER_PRECONDITION)
|
||||
expect(updateOrphanAutomation.length).toBe(3)
|
||||
expect(getRuntimeEnvironmentStatus).not.toHaveBeenCalled()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -54,6 +54,29 @@ describe('automation usage model', () => {
|
||||
unavailableMessage: null
|
||||
}
|
||||
}),
|
||||
makeRun({
|
||||
id: 'run-3',
|
||||
createdAt: 3,
|
||||
dispatchedAt: 3,
|
||||
usage: {
|
||||
status: 'known',
|
||||
provider: 'claude',
|
||||
model: 'sonnet',
|
||||
inputTokens: 200,
|
||||
outputTokens: 700,
|
||||
cacheReadTokens: null,
|
||||
cacheWriteTokens: 50,
|
||||
reasoningOutputTokens: null,
|
||||
totalTokens: 900,
|
||||
estimatedCostUsd: 0.0042,
|
||||
estimatedCostSource: 'api_equivalent',
|
||||
providerSessionId: 'session-3',
|
||||
attribution: 'provider_session_time_window',
|
||||
collectedAt: 3,
|
||||
unavailableReason: null,
|
||||
unavailableMessage: null
|
||||
}
|
||||
}),
|
||||
makeRun({
|
||||
id: 'run-2',
|
||||
usage: {
|
||||
@@ -78,16 +101,16 @@ describe('automation usage model', () => {
|
||||
])
|
||||
|
||||
expect(summary).toEqual({
|
||||
knownRuns: 1,
|
||||
knownRuns: 2,
|
||||
unavailableRuns: 1,
|
||||
inputTokens: 1000,
|
||||
outputTokens: 300,
|
||||
cacheTokens: 400,
|
||||
inputTokens: 1200,
|
||||
outputTokens: 1000,
|
||||
cacheTokens: 450,
|
||||
reasoningOutputTokens: 50,
|
||||
totalTokens: 1350,
|
||||
estimatedCostUsd: 0.0042,
|
||||
totalTokens: 2250,
|
||||
estimatedCostUsd: 0.0084,
|
||||
lastRunStatus: 'completed',
|
||||
lastRunAt: 1
|
||||
lastRunAt: 3
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -99,11 +99,15 @@ describe('engine scope errors', () => {
|
||||
).toBe(EXTERNAL_AUTOMATION_SCOPE_CODES.targetHidden)
|
||||
})
|
||||
|
||||
it('turns a hidden-target rejection into its own copy, not the generic note', () => {
|
||||
it('preserves the hidden-target scope code', () => {
|
||||
const gate = externalAutomationScopeGateFromError(
|
||||
new ExternalAutomationScopeError(EXTERNAL_AUTOMATION_SCOPE_CODES.targetHidden)
|
||||
)
|
||||
expect(gate?.status).toBe('not-listed')
|
||||
expect(gate).toEqual({
|
||||
status: 'not-listed',
|
||||
probeOwner: null,
|
||||
code: EXTERNAL_AUTOMATION_SCOPE_CODES.targetHidden
|
||||
})
|
||||
})
|
||||
|
||||
it('leaves unrelated failures alone so they are not relabelled as scope limits', () => {
|
||||
|
||||
@@ -49,6 +49,10 @@ describe('external automation scope keys', () => {
|
||||
it('escapes components so a hostile ID cannot forge another key', () => {
|
||||
const forged = externalAutomationJobKey(local, 'job|extra')
|
||||
expect(forged).not.toBe(externalAutomationActionKey(local, 'job', 'run'))
|
||||
expect(forged).not.toBe(externalAutomationJobKey(local, 'job%7Cextra'))
|
||||
expect(externalAutomationActionKey(local, 'job|extra', 'run')).not.toBe(
|
||||
externalAutomationActionKey(local, 'job%7Cextra', 'run')
|
||||
)
|
||||
expect(forged.split('|')).toHaveLength(4)
|
||||
})
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ import { join } from 'node:path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import {
|
||||
getEphemeralVmRuntimeFeatureStorePath,
|
||||
featureIdentity,
|
||||
restoreRuntimeFeatureList,
|
||||
MAX_EPHEMERAL_VM_RUNTIME_FEATURE_STORE_FILE_BYTES
|
||||
} from './ephemeral-vm-runtime-feature-store'
|
||||
@@ -302,13 +301,6 @@ describe('runtime feature restoration scaling', () => {
|
||||
createdAt: runtime.createdAt,
|
||||
recipeCheckoutMode: 'provisioned-root' as const
|
||||
}))
|
||||
for (const runtime of runtimes) {
|
||||
expect(
|
||||
features.find((entry) => featureIdentity(entry) === featureIdentity(runtime))
|
||||
).toBeDefined()
|
||||
}
|
||||
expect(reads).toBe(500_500)
|
||||
reads = 0
|
||||
const restored = restoreRuntimeFeatureList(runtimes, features)
|
||||
expect(reads).toBe(1000)
|
||||
expect(restored.map((runtime) => runtime.id)).toEqual(runtimes.map((runtime) => runtime.id))
|
||||
|
||||
@@ -35,7 +35,7 @@ function repo(overrides: Partial<Repo> & Pick<Repo, 'id' | 'path'>): Repo {
|
||||
badgeColor: '#000',
|
||||
addedAt: 0,
|
||||
...overrides
|
||||
} as Repo
|
||||
}
|
||||
}
|
||||
|
||||
function state(overrides: Partial<FolderWorkspaceHostState> = {}): FolderWorkspaceHostState {
|
||||
|
||||
@@ -22,7 +22,7 @@ describe('resolveOuterWrapperForegroundProcess', () => {
|
||||
expect(resolveOuterWrapperForegroundProcess(pi, barePi, [barePi])).toBe('pi')
|
||||
})
|
||||
|
||||
it('leaves a cross-group agent (codex) untouched even under a deeper same-name child', () => {
|
||||
it('keeps Codex identity beneath a shell parent', () => {
|
||||
const codex = { agent: 'codex' as const, processName: 'codex' }
|
||||
expect(
|
||||
resolveOuterWrapperForegroundProcess(
|
||||
|
||||
@@ -5,7 +5,7 @@ import { pickTuiAgent } from './tui-agent-selection'
|
||||
|
||||
describe('Freebuff terminal launches', () => {
|
||||
it.each(['darwin', 'linux', 'win32'] as const)(
|
||||
'delivers task text through the interactive terminal on %s',
|
||||
'plans task text as a follow-up to the interactive launch on %s',
|
||||
(platform) => {
|
||||
const prompt = '--help\nFix "quoted" paths and $HOME handling'
|
||||
const plan = buildAgentStartupPlan({
|
||||
|
||||
@@ -203,18 +203,6 @@ describe('buildGitBranchLineTotalDiffArgs', () => {
|
||||
'--'
|
||||
])
|
||||
})
|
||||
|
||||
it('never asks for --cached or -C, which would change the measured range', () => {
|
||||
const args = buildGitBranchLineTotalDiffArgs(MERGE_BASE)
|
||||
expect(args).not.toContain('--cached')
|
||||
expect(args).not.toContain('-C')
|
||||
expect(args.at(-1)).toBe('--')
|
||||
})
|
||||
|
||||
it('exposes a finite timeout budget so a huge branch cannot block the status response', () => {
|
||||
expect(GIT_BRANCH_LINE_TOTAL_TIMEOUT_MS).toBeGreaterThan(0)
|
||||
expect(Number.isFinite(GIT_BRANCH_LINE_TOTAL_TIMEOUT_MS)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
describe('computeGitBranchLineTotal', () => {
|
||||
|
||||
@@ -1,20 +1,12 @@
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import {
|
||||
encodeGitCheckIgnorePaths,
|
||||
GIT_CHECK_IGNORE_STDIN_ARGS,
|
||||
parseGitCheckIgnorePaths,
|
||||
splitGitCheckIgnorePathsByStdinBytes
|
||||
} from './git-check-ignore-stdio'
|
||||
|
||||
describe('git check-ignore stdio', () => {
|
||||
it('uses the NUL-delimited stdin command shape', () => {
|
||||
expect(GIT_CHECK_IGNORE_STDIN_ARGS).toEqual([
|
||||
'-c',
|
||||
'core.quotePath=false',
|
||||
'check-ignore',
|
||||
'-z',
|
||||
'--stdin'
|
||||
])
|
||||
it('encodes exact paths as NUL-delimited stdin records', () => {
|
||||
expect(encodeGitCheckIgnorePaths(['dist/bundle.js', 'line\nbreak.txt', '-leading.txt'])).toBe(
|
||||
'dist/bundle.js\0line\nbreak.txt\0-leading.txt\0'
|
||||
)
|
||||
|
||||
@@ -8,13 +8,13 @@ function listSnapshot(records: string[]): string {
|
||||
return `${records.join('\0')}\0`
|
||||
}
|
||||
|
||||
function getGitArgs(call: unknown[]): string[] {
|
||||
return call[0] as string[]
|
||||
}
|
||||
type GitCommandRunner = Parameters<typeof createGitConfigSnapshotRunner>[0]
|
||||
|
||||
function countCalls(runGit: ReturnType<typeof vi.fn>, expectedArgs: string[]): number {
|
||||
return runGit.mock.calls.filter((call) => {
|
||||
const args = getGitArgs(call)
|
||||
function countCalls(
|
||||
runGit: ReturnType<typeof vi.fn<GitCommandRunner>>,
|
||||
expectedArgs: string[]
|
||||
): number {
|
||||
return runGit.mock.calls.filter(([args]) => {
|
||||
return (
|
||||
args.length === expectedArgs.length && args.every((arg, index) => arg === expectedArgs[index])
|
||||
)
|
||||
@@ -31,7 +31,7 @@ function createDeferred<T>(): { promise: Promise<T>; resolve: (value: T) => void
|
||||
|
||||
describe('createGitConfigSnapshotRunner', () => {
|
||||
it('serves many config --get lookups from one config --list -z call', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot([
|
||||
'branch.main.remote\norigin',
|
||||
'branch.main.merge\nrefs/heads/main',
|
||||
@@ -40,16 +40,22 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
}))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
|
||||
await runner(['config', '--get', 'branch.main.remote'])
|
||||
await runner(['config', '--get', 'branch.main.merge'])
|
||||
await runner(['config', '--get', 'remote.pushDefault'])
|
||||
await expect(runner(['config', '--get', 'branch.main.remote'])).resolves.toEqual({
|
||||
stdout: 'origin'
|
||||
})
|
||||
await expect(runner(['config', '--get', 'branch.main.merge'])).resolves.toEqual({
|
||||
stdout: 'refs/heads/main'
|
||||
})
|
||||
await expect(runner(['config', '--get', 'remote.pushDefault'])).resolves.toEqual({
|
||||
stdout: 'fork'
|
||||
})
|
||||
|
||||
expect(countCalls(runGit, ['config', '--list', '-z'])).toBe(1)
|
||||
expect(runGit.mock.calls.filter((call) => getGitArgs(call)[1] === '--get')).toHaveLength(0)
|
||||
expect(runGit.mock.calls.filter(([args]) => args[1] === '--get')).toHaveLength(0)
|
||||
})
|
||||
|
||||
it('returns branch and remote values from a representative snapshot', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot([
|
||||
'branch.feature.remote\norigin',
|
||||
'branch.feature.merge\nrefs/heads/feature',
|
||||
@@ -70,7 +76,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
it('passes remote commands through unchanged', async () => {
|
||||
const runGit = vi.fn(async (args: string[]) => ({ stdout: args.join(' ') }))
|
||||
const runGit = vi.fn<GitCommandRunner>(async (args: string[]) => ({ stdout: args.join(' ') }))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
|
||||
await expect(runner(['remote'])).resolves.toEqual({ stdout: 'remote' })
|
||||
@@ -83,18 +89,18 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
it('case-folds the requested section and key', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot(['remote.pushdefault\nfork'])
|
||||
}))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
|
||||
await expect(runner(['config', '--get', 'remote.pushDefault'])).resolves.toEqual({
|
||||
await expect(runner(['config', '--get', 'REMOTE.pushDefault'])).resolves.toEqual({
|
||||
stdout: 'fork'
|
||||
})
|
||||
})
|
||||
|
||||
it('preserves subsections with dots in lookup keys', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot(['branch.feature.x.merge\nrefs/heads/feature.x'])
|
||||
}))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
@@ -105,7 +111,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
it('returns the last multivar value for config --get', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot([
|
||||
'branch.main.merge\nrefs/heads/old',
|
||||
'branch.main.merge\nrefs/heads/new'
|
||||
@@ -119,7 +125,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
it('parses valueless boolean keys without corrupting adjacent records', async () => {
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot([
|
||||
'remote.origin.mirror',
|
||||
'remote.origin.url\ngit@example.com:org/repo.git'
|
||||
@@ -137,7 +143,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
|
||||
it('rejects an absent key from a loaded snapshot instead of returning empty success', async () => {
|
||||
// Missing keys must reject like config --get, without respawning the command this snapshot coalesces.
|
||||
const runGit = vi.fn(async () => ({
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => ({
|
||||
stdout: listSnapshot(['branch.main.remote\norigin'])
|
||||
}))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
@@ -147,8 +153,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
)
|
||||
expect(countCalls(runGit, ['config', '--list', '-z'])).toBe(1)
|
||||
expect(
|
||||
runGit.mock.calls.filter((call) => {
|
||||
const args = getGitArgs(call)
|
||||
runGit.mock.calls.filter(([args]) => {
|
||||
return args[0] === 'config' && args[1] === '--get'
|
||||
})
|
||||
).toHaveLength(0)
|
||||
@@ -156,7 +161,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
|
||||
it('single-flights concurrent first config --get lookups', async () => {
|
||||
const snapshot = createDeferred<{ stdout: string }>()
|
||||
const runGit = vi.fn(async () => await snapshot.promise)
|
||||
const runGit = vi.fn<GitCommandRunner>(async () => await snapshot.promise)
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
|
||||
const lookups = Promise.all([
|
||||
@@ -184,7 +189,7 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
it('falls back to real config --get after snapshot fetch failure', async () => {
|
||||
const runGit = vi.fn(async (args: string[]) => {
|
||||
const runGit = vi.fn<GitCommandRunner>(async (args: string[]) => {
|
||||
if (args[0] === 'config' && args[1] === '--list') {
|
||||
throw new Error('snapshot failed')
|
||||
}
|
||||
@@ -203,11 +208,11 @@ describe('createGitConfigSnapshotRunner', () => {
|
||||
})
|
||||
|
||||
expect(countCalls(runGit, ['config', '--list', '-z'])).toBe(1)
|
||||
expect(runGit.mock.calls.filter((call) => getGitArgs(call)[1] === '--get')).toHaveLength(2)
|
||||
expect(runGit.mock.calls.filter(([args]) => args[1] === '--get')).toHaveLength(2)
|
||||
})
|
||||
|
||||
it('passes non-config commands through', async () => {
|
||||
const runGit = vi.fn(async (args: string[]) => ({ stdout: args.join(' ') }))
|
||||
const runGit = vi.fn<GitCommandRunner>(async (args: string[]) => ({ stdout: args.join(' ') }))
|
||||
const runner = createGitConfigSnapshotRunner(runGit)
|
||||
|
||||
await expect(runner(['rev-parse', '--abbrev-ref', 'HEAD@{u}'])).resolves.toEqual({
|
||||
|
||||
Reference in New Issue
Block a user