test: remove 44 low-value test declarations (#37969)

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
This commit is contained in:
OrcaWin
2026-11-03 15:39:24 -08:00
committed by GitHub
co-authored by OrcaWin
parent c46e84bcc4
commit d4e6e464ab
31 changed files with 7 additions and 992 deletions
+3 -11
View File
@@ -14646,7 +14646,7 @@
"oracle": "A quarter-circle Claude task title authorizes without a provider lookup only on the exact PTY incarnation carrying verified managed-Claude launch identity; the same title in a bare pane, with an unverified launch hint, or after PTY incarnation replacement is refused while current Claude activity remains a working signal. Fresh explicit state plus ordinary PowerShell plus confirmed recognized agent is sendable on the same PTY. Confirmed shell/non-agent, unavailable confirmation, PTY exit, handle rebind, or a callback PTY mismatch returns a refusal or not-writable result and writes zero bytes.",
"commands": [
"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/quarter-circle-title-send-authorization.test.ts",
"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty/local-pty-provider-foreground-process.test.ts src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx"
"pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty/local-pty-provider-foreground-process.test.ts src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts"
],
"testFiles": [
"src/main/runtime/quarter-circle-title-send-authorization.test.ts",
@@ -14658,8 +14658,7 @@
"src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts",
"src/main/providers/windows-console-attached-processes.test.ts",
"src/main/daemon/pty-subprocess.test.ts",
"src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts",
"src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx"
"src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts"
],
"assertionRefs": [
{
@@ -14721,13 +14720,6 @@
{
"file": "src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts",
"assertions": ["selected active-agent note sends retain guarded paste and submit routing"]
},
{
"file": "src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx",
"assertions": [
"browser annotation send content routes through review-notes send so existing agent sessions remain selectable",
"both browser annotation send surfaces wire the shared menu content"
]
}
],
"evidenceRuns": [
@@ -14745,7 +14737,7 @@
"runner": "local",
"platform": "macos",
"command": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty-provider-foreground-process.test.ts src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/providers/windows-pty-job-membership.test.ts src/main/daemon/daemon-foreground-confirmation-protocol.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx",
"currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty/local-pty-provider-foreground-process.test.ts src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx",
"currentCommand": "pnpm exec vitest run --config config/vitest.config.ts src/main/runtime/orca-runtime.test.ts src/main/runtime/rpc/terminal-send.test.ts src/main/ipc/pty/pty-runtime-kill-and-exit.test.ts src/main/providers/agent-foreground-process.test.ts src/main/providers/local-pty/local-pty-provider-foreground-process.test.ts src/main/daemon/pty-subprocess-foreground-degraded-scan.test.ts src/main/providers/windows-console-attached-processes.test.ts src/main/daemon/pty-subprocess.test.ts src/renderer/src/lib/active-agent-note-send-explicit-target.test.ts",
"result": "passed",
"durationSeconds": 13.74,
"summary": "Twelve focused test files passed (1351 tests, 1 skipped), covering runtime confirmation and PTY revalidation, guarded RPC zero-write behavior, PTY controller routing, local/daemon fresh scans, exact ConPTY membership, and unchanged renderer note routing."
-5
View File
@@ -950,7 +950,6 @@
"src/main/agent-hooks/wsl-opencode-settings-lifetime.test.ts": 1951,
"src/main/agent-hooks/wsl-opencode-settings.test.ts": 1364,
"src/main/agent-launch/agent-launch-account-env.test.ts": 958,
"src/main/agent-launch/agent-launch-decided-mode-contract.test.ts": 38,
"src/main/agent-launch/agent-launch-executor-cancel.test.ts": 1455,
"src/main/agent-launch/agent-launch-executor.test.ts": 1098,
"src/main/agent-launch/agent-launch-legacy-host-policy.test.ts": 1028,
@@ -5660,7 +5659,6 @@
"src/main/runtime/rpc/methods/orchestration-worker-mode-opacity.test.ts": 5585,
"src/main/runtime/rpc/methods/orchestration-worker-release-incarnation-fallback.test.ts": 5246,
"src/main/runtime/rpc/methods/orchestration-worker-start-mode-selection.test.ts": 5749,
"src/main/runtime/rpc/methods/orchestration-worker-start-mode.test.ts": 851,
"src/main/runtime/rpc/methods/orchestration-worker-start-registered-agent.test.ts": 1426,
"src/main/runtime/rpc/methods/orchestration/agent-message-command-contract.test.ts": 6968,
"src/main/runtime/rpc/methods/orchestration/cli-runtime-boundary.test.ts": 5671,
@@ -7376,7 +7374,6 @@
"src/renderer/src/components/browser-pane/ClientHostedBrowserPagePane.popup-notices.test.tsx": 6196,
"src/renderer/src/components/browser-pane/ClientHostedBrowserPagePane.test.tsx": 6541,
"src/renderer/src/components/browser-pane/ReopenBrowserPageOnServerButton.test.tsx": 497,
"src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx": 275,
"src/renderer/src/components/browser-pane/annotate/GrabConfirmationSheet.test.ts": 261,
"src/renderer/src/components/browser-pane/annotate/MarkupOverlay.test.tsx": 1124,
"src/renderer/src/components/browser-pane/annotate/browser-annotation-output.test.ts": 74,
@@ -8865,7 +8862,6 @@
"src/renderer/src/components/settings/voice/VoicePane.test.tsx": 1042,
"src/renderer/src/components/settings/voice/VoiceSpeechModelSection.test.tsx": 503,
"src/renderer/src/components/settings/general/WorkspaceDirectorySetting.test.tsx": 1982,
"src/renderer/src/components/settings/agents/launch/ZcodeCliSetupSection.test.tsx": 818,
"src/renderer/src/components/settings/accounts/usage/ZcodePlanAccountsSection.test.tsx": 1002,
"src/renderer/src/components/settings/accounts/sign-in/account-add-cancel-target.test.ts": 217,
"src/renderer/src/components/settings/accounts/usage/accounts-pane-opencode-credentials.test.ts": 519,
@@ -10352,7 +10348,6 @@
"src/renderer/src/lib/agent-paste-draft-submit-retry.test.ts": 315,
"src/renderer/src/lib/agent-paste-draft.test.ts": 445,
"src/renderer/src/lib/agent-picker-search.test.ts": 265,
"src/renderer/src/lib/agent-ready-wait.test.ts": 119,
"src/renderer/src/lib/agent-resume-launch-target.test.ts": 3911,
"src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-after-failure.test.ts": 870,
"src/renderer/src/lib/agent-session/launch/structured-agent-session-launch-close-race.test.ts": 983,
@@ -1,71 +0,0 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { describe, expect, it, vi } from 'vitest'
import { CodexResetCreditAction } from './CodexResetCreditAction'
import { feedback } from '../theme/mobile-theme'
import { findAllByHostType, findByHostType } from '../test-support/react-test-renderer-host-nodes'
vi.mock('react-native', () => ({
ActivityIndicator: 'ActivityIndicator',
Pressable: 'Pressable',
StyleSheet: { create: (styles: unknown) => styles, hairlineWidth: 1 },
Text: 'Text',
View: 'View'
}))
vi.mock('lucide-react-native', () => ({ RotateCcw: 'RotateCcw' }))
const summary = {
availableCount: 1,
availabilityLabel: '1 reset available',
expiryLabel: 'Expires in 5d'
}
function renderAction(busy: boolean, disabled: boolean): ReactTestRenderer {
let renderer: ReactTestRenderer | null = null
act(() => {
renderer = create(
createElement(CodexResetCreditAction, {
summary,
scopeLabel: 'dev@example.com on the host',
busy,
disabled,
onPress: vi.fn()
})
)
})
if (!renderer) {
throw new Error('Reset action did not render')
}
return renderer
}
describe('CodexResetCreditAction', () => {
it('exposes a 44pt touch target and enabled accessibility state', () => {
const renderer = renderAction(false, false)
const button = findByHostType(renderer.root, 'Pressable')
expect(button.props.accessibilityLabel).toBe('Use Codex rate-limit reset')
expect(button.props.accessibilityState).toEqual({ busy: false, disabled: false })
expect(button.props.accessibilityHint).toContain('dev@example.com on the host')
expect(button.props.hitSlop).toBe(8)
expect(button.props.style({ pressed: false })[0]).toMatchObject({ minHeight: 44 })
act(() => renderer.unmount())
})
it('announces progress and visually dims a busy disabled action', () => {
const renderer = renderAction(true, true)
const button = findByHostType(renderer.root, 'Pressable')
const text = findAllByHostType(renderer.root, 'Text').map((node) =>
node.children.filter((child) => typeof child === 'string').join('')
)
expect(button.props.accessibilityLabel).toBe('Resetting Codex rate limits')
expect(button.props.accessibilityState).toEqual({ busy: true, disabled: true })
expect(button.props.style({ pressed: false })[1]).toMatchObject({
opacity: feedback.disabledOpacity
})
expect(text).toContain('Resetting…')
act(() => renderer.unmount())
})
})
@@ -1,7 +1,6 @@
import { describe, expect, it } from 'vitest'
import {
clampDragReorderIndex,
dragReorderLayout,
dragReorderTarget,
dragReorderPositionsFromKeys,
@@ -10,18 +9,6 @@ import {
} from './drag-reorder-positions'
describe('drag reorder positions', () => {
it('round-trips keys through positions', () => {
const keys = ['escape', 'tab', 'enter']
expect(orderedKeysFromDragReorderPositions(dragReorderPositionsFromKeys(keys))).toEqual(keys)
})
it('clamps drag indexes to the list bounds', () => {
expect(clampDragReorderIndex(-2, 3)).toBe(0)
expect(clampDragReorderIndex(1, 3)).toBe(1)
expect(clampDragReorderIndex(7, 3)).toBe(2)
expect(clampDragReorderIndex(0, 0)).toBe(0)
})
it('shifts intermediate rows down when dragging a row later', () => {
const positions = dragReorderPositionsFromKeys(['a', 'b', 'c', 'd'])
expect(orderedKeysFromDragReorderPositions(moveDragReorderKey(positions, 'a', 2))).toEqual([
@@ -41,12 +28,6 @@ describe('drag reorder positions', () => {
'c'
])
})
it('returns the same positions for no-op or unknown moves', () => {
const positions = dragReorderPositionsFromKeys(['a', 'b'])
expect(moveDragReorderKey(positions, 'a', 0)).toBe(positions)
expect(moveDragReorderKey(positions, 'missing', 1)).toBe(positions)
})
})
it('projects a thousand variable-height rows and all row lookups with linear reads', () => {
@@ -1,76 +0,0 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import {
useNewWorktreeDrawerNavigation,
type NewWorktreeDrawerView
} from './use-new-worktree-drawer-navigation'
type Nav = ReturnType<typeof useNewWorktreeDrawerNavigation>
const mounted: ReactTestRenderer[] = []
function renderNavigation(modalVisible: boolean): { current: Nav } {
const handle: { current: Nav | null } = { current: null }
function Probe(props: { modalVisible: boolean }) {
handle.current = useNewWorktreeDrawerNavigation(props.modalVisible)
return null
}
act(() => {
mounted.push(create(createElement(Probe, { modalVisible })))
})
return {
get current() {
if (!handle.current) {
throw new Error('Navigation did not mount')
}
return handle.current
}
}
}
describe('useNewWorktreeDrawerNavigation', () => {
beforeEach(() => vi.useFakeTimers())
afterEach(() => {
for (const renderer of mounted.splice(0)) {
act(() => renderer.unmount())
}
vi.useRealTimers()
})
// The shared native Modal stays mounted; a transition rendering no sheet leaves a transparent window that swallows taps until the timer fires.
it('shows the form sheet for the whole transition, even if the queued timer never lands', () => {
const nav = renderNavigation(true)
act(() => nav.current.openSourceDrawer())
expect(nav.current.drawerView).toBe<NewWorktreeDrawerView>('source')
act(() => nav.current.transitionDrawer('form'))
expect(nav.current.drawerView).toBe<NewWorktreeDrawerView>('transition')
expect(nav.current.formSheetVisible).toBe(true)
expect(nav.current.formSheetInteractive).toBe(false)
})
it('keeps the form pinned under a picker instead of swapping it out', () => {
const nav = renderNavigation(true)
act(() => nav.current.transitionDrawer('agent'))
act(() => {
vi.advanceTimersByTime(500)
})
expect(nav.current.drawerView).toBe<NewWorktreeDrawerView>('agent')
expect(nav.current.formSheetVisible).toBe(true)
expect(nav.current.formSheetInteractive).toBe(false)
})
it('hands the form back interactive once the transition lands', () => {
const nav = renderNavigation(true)
act(() => nav.current.openSourceDrawer())
act(() => nav.current.transitionDrawer('form'))
act(() => {
vi.advanceTimersByTime(500)
})
expect(nav.current.drawerView).toBe<NewWorktreeDrawerView>('form')
expect(nav.current.formSheetVisible).toBe(true)
expect(nav.current.formSheetInteractive).toBe(true)
})
})
@@ -34,24 +34,6 @@ const props = {
alt: 'Architecture'
}
it('shows the loaded image and expands it in the existing image viewer', async () => {
loader.mockResolvedValue('data:image/png;base64,cG5n')
await act(async () => {
tree = create(createElement(MobileMarkdownPreviewImage, props))
})
const image = tree!.root.find((node) => String(node.type) === 'Image')
expect(image.props.source.uri).toBe('data:image/png;base64,cG5n')
expect(tree!.root.find((node) => String(node.type) === 'Image').props.style.aspectRatio).toBe(
600 / 220
)
await act(async () =>
tree!.root.find((node) => String(node.type) === 'Pressable').props.onPress()
)
expect(tree!.root.find((node) => String(node.type) === 'ImageViewer').props.uri).toBe(
'data:image/png;base64,cG5n'
)
})
it('retries a refused image without hiding the surrounding document', async () => {
loader
.mockRejectedValueOnce(new Error('Unable to reach the desktop filesystem'))
@@ -1,73 +0,0 @@
import { useRef } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, expect, it, vi } from 'vitest'
import { findAllByHostType, findByHostType } from '../test-support/react-test-renderer-host-nodes'
import { MobileEdgeFade } from '../components/MobileEdgeFade'
import { colors, spacing } from '../theme/mobile-theme'
import { MobileQueuedMessageScrollList } from './MobileQueuedMessageScrollList'
vi.mock('react-native', () => ({
Platform: { OS: 'ios' },
StyleSheet: { create: (styles: unknown) => styles },
View: 'View'
}))
vi.mock('react-native-reanimated', () => ({
default: { ScrollView: 'ScrollView' },
useAnimatedRef: () => useRef(null),
useSharedValue: (value: unknown) => useRef({ value }).current
}))
let renderer: ReactTestRenderer | null = null
afterEach(() => act(() => renderer?.unmount()))
it('keeps the queue edge cues, colors and dimensions with independent gradient references', () => {
act(() => {
renderer = create(
<MobileQueuedMessageScrollList messageIds={['a']} newestIsPersons={false}>
{() => 'queued body'}
</MobileQueuedMessageScrollList>
)
})
const tree = renderer!
const scroll = findByHostType(tree.root, 'ScrollView')
const fades = () => tree.root.findAllByType(MobileEdgeFade)
expect(fades()).toHaveLength(0)
act(() => scroll.props.onLayout({ nativeEvent: { layout: { height: 160 } } }))
act(() => scroll.props.onContentSizeChange(0, 220))
expect(fades().map((node) => node.props.edge)).toEqual(['bottom'])
act(() => scroll.props.onScroll({ nativeEvent: { contentOffset: { y: 24 } } }))
expect(fades().map((node) => node.props.edge)).toEqual(['top', 'bottom'])
const ids = fades().map((fade) => {
const overlay = findByHostType(fade, 'View')
expect(overlay.props.pointerEvents).toBe('none')
expect(Object.assign({}, ...overlay.props.style)).toMatchObject({
position: 'absolute',
left: 0,
right: 0,
height: spacing.lg
})
const gradient = findByHostType(fade, 'LinearGradient')
expect(findByHostType(fade, 'Rect').props.fill).toBe(`url(#${gradient.props.id})`)
return gradient.props.id
})
expect(new Set(ids).size).toBe(2)
expect(
fades().map((fade) =>
findAllByHostType(fade, 'Stop').map((node) => [node.props.stopColor, node.props.stopOpacity])
)
).toEqual([
[
[colors.bgPanel, 1],
[colors.bgPanel, 0]
],
[
[colors.bgPanel, 0],
[colors.bgPanel, 1]
]
])
act(() => scroll.props.onScroll({ nativeEvent: { contentOffset: { y: 60 } } }))
expect(fades().map((node) => node.props.edge)).toEqual(['top'])
act(() => scroll.props.onContentSizeChange(0, 100))
act(() => scroll.props.onScroll({ nativeEvent: { contentOffset: { y: 0 } } }))
expect(fades()).toHaveLength(0)
})
@@ -9,42 +9,6 @@ vi.mock('react-native', () => ({
vi.mock('lucide-react-native', () => ({ ImagePlus: 'ImagePlus', Mic: 'Mic' }))
import { MobileTerminalInputActions } from './MobileTerminalInputActions'
it('removes the disabled microphone while keeping image attachment available', async () => {
const attach = vi.fn()
const props = {
canSend: true,
isAttaching: false,
dictation: { isStarting: false, isRecording: false, isProcessing: false },
dictationMode: 'toggle',
dictationEnabled: false,
buttonStyle: {},
activeButtonStyle: {},
disabledButtonStyle: {},
onAttachImage: attach,
onAttachFile: vi.fn(),
onDictationToggle: vi.fn(),
onDictationPressIn: vi.fn(),
onDictationPressOut: vi.fn(),
onDictationCancel: vi.fn()
}
let renderer!: ReturnType<typeof create>
await act(async () => {
renderer = create(createElement(MobileTerminalInputActions, props))
})
const buttons = () => renderer.root.findAll((node) => String(node.type) === 'Pressable')
expect(buttons().map((b) => b.props.accessibilityLabel)).toEqual(['Attach a photo'])
await act(async () => buttons()[0]!.props.onPress())
expect(attach).toHaveBeenCalledOnce()
await act(async () =>
renderer.update(createElement(MobileTerminalInputActions, { ...props, dictationEnabled: true }))
)
expect(buttons().map((b) => b.props.accessibilityLabel)).toEqual([
'Attach a photo',
'Start voice dictation'
])
await act(async () => renderer.unmount())
})
it('keeps the microphone able to stop a recording while the connection is down', async () => {
const idle = { isStarting: false, isRecording: false, isProcessing: false }
const props = {
@@ -1,79 +0,0 @@
import { createElement } from 'react'
import { act, create } from 'react-test-renderer'
import { describe, expect, it, vi } from 'vitest'
import type { ForceReconnect } from '../transport/rpc-client-context-contract'
vi.mock('react-native', () => ({ Platform: { OS: 'web' } }))
vi.mock('../platform/use-reduced-motion', () => ({ useReducedMotionEnabled: () => null }))
vi.mock('../layout/use-shell-side-rail', () => ({
useShellSideRail: () => false,
useDirectionPadAvailable: () => false
}))
import { useMobileSessionPresentation } from './use-mobile-session-presentation'
type Presentation = ReturnType<typeof useMobileSessionPresentation>
function present(forceReconnectHost: ForceReconnect): Presentation {
const scope = {
created: undefined,
worktreeId: 'wt-1',
router: { setParams: () => {} },
insets: { top: 0, bottom: 0, left: 0, right: 0 },
connState: 'reconnecting',
client: null,
reconnectAttempts: 20,
lastConnectedAt: null,
terminalsLoaded: false,
activeHandle: null,
creating: false,
creatingBrowser: false,
creatingMarkdown: false,
keyboardHeight: 0,
terminalKeyboardMetrics: new Map(),
toastOpacityRef: { current: 1 },
hostEndpoint: null,
initialSessionAutoCreateRef: { current: null },
terminalFrameRef: { current: null },
handleCreateTerminal: () => Promise.resolve(),
visibleTabs: [],
forceReconnectHost
}
type Scope = Parameters<typeof useMobileSessionPresentation>[0]
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: the presentation hook reads only these members of the session scope; the rest of the controller is unreachable from it.
const sessionScope = scope as unknown as Scope
const read: { value: Presentation | null } = { value: null }
function Probe(): null {
read.value = useMobileSessionPresentation(sessionScope)
return null
}
act(() => {
create(createElement(Probe))
})
if (read.value === null) {
throw new Error('the hook did not run')
}
return read.value
}
describe("the session header's tap to retry", () => {
it('is not offered on the page, and the status says what is wrong without promising a tap', () => {
const { showConnectionRetry, connectionEscalated, terminalSummary } = present(null)
expect({ showConnectionRetry, connectionEscalated, terminalSummary }).toEqual({
showConnectionRetry: false,
connectionEscalated: true,
terminalSummary: "Can't reach desktop"
})
})
it('is still offered natively', () => {
const { showConnectionRetry, connectionEscalated, terminalSummary } = present(() =>
Promise.resolve()
)
expect({ showConnectionRetry, connectionEscalated, terminalSummary }).toEqual({
showConnectionRetry: true,
connectionEscalated: true,
terminalSummary: "Can't reach desktop — tap to retry"
})
})
})
@@ -66,12 +66,6 @@ describe('mobile session route', () => {
})
})
it('omits an absent workspace name instead of sending an empty param', () => {
expect(
mobileSessionRouteTarget({ hostId: 'host-1', worktreeId: 'repo::/tmp/wt' }).params
).toEqual({ hostId: 'host-1', worktreeId: 'repo::/tmp/wt' })
})
it('mounts the host, then opens the session over its list', () => {
const harness = navigationHarness({ index: 0, routes: [{ name: 'index' }] })
const push = vi.fn()
@@ -25,17 +25,6 @@ function prompt(freeTextInput?: AgentJournalFreeTextInput): StructuredQuestionIt
}
describe('mobile structured free-text questions', () => {
it('projects editor input metadata onto the existing question card', () => {
const freeTextInput = {
allowEmpty: true,
multiline: true,
initialValue: 'draft',
placeholder: 'Edit here'
}
expect(projectStructuredQuestion(prompt(freeTextInput))?.freeTextInput).toEqual(freeTextInput)
expect(projectStructuredQuestion(prompt())?.freeTextInput).toBeUndefined()
})
it('accepts empty and whitespace text only for the matching allowed prompt', () => {
const current = prompt({ allowEmpty: true })
const projected = projectStructuredQuestion(current)!
@@ -64,11 +64,4 @@ describe('useMobileNativeChatQueuedEditFocus', () => {
})
expect(focus).not.toHaveBeenCalled()
})
it('passes no Edit through when the cards offer none', async () => {
await act(async () => {
renderer = create(createElement(Harness, {}))
})
expect(latest!.editQueuedMessage).toBeUndefined()
})
})
@@ -2,7 +2,6 @@ import { describe, expect, it } from 'vitest'
import type { NativeChatMessage } from '../../../../src/shared/native-chat/native-chat-types'
import {
applyAppend,
boundNativeChatWindow,
createNativeChatMerger,
mergeNativeChatMessages,
replaceList
@@ -54,13 +53,6 @@ describe('mobile stateful merger — oracle vs pure merge', () => {
expect(after[after.length - 1]).toBe(tail)
})
it('bounds the window to the most-recent tail', () => {
const long = Array.from({ length: 10 }, (_, i) => msg(`m${i}`))
expect(boundNativeChatWindow(long, 3).map((m) => m.id)).toEqual(['m7', 'm8', 'm9'])
expect(boundNativeChatWindow(long, 0)).toBe(long)
expect(boundNativeChatWindow(long, 20)).toBe(long)
})
it('bounds live appends and rebuilds the cached indexes for the retained tail', () => {
const merger = createNativeChatMerger()
replaceList(merger, [msg('a'), msg('b'), msg('c')])
@@ -1,8 +1,5 @@
import { describe, expect, it } from 'vitest'
import {
isNoiseMessage,
stripNoiseMessages
} from '../../../../src/shared/native-chat/native-chat-noise'
import { isNoiseMessage } from '../../../../src/shared/native-chat/native-chat-noise'
import type { NativeChatMessage } from '../../../../src/shared/native-chat/native-chat-types'
function msg(
@@ -20,25 +17,6 @@ function msg(
}
describe('isNoiseMessage', () => {
it('flags task-notification and system-reminder user turns', () => {
expect(isNoiseMessage(msg('user', '<task-notification>\n<task-id>x</task-id>'))).toBe(true)
expect(isNoiseMessage(msg('user', '<system-reminder>\nbe careful'))).toBe(true)
expect(
isNoiseMessage(
msg(
'user',
'Caveat: The messages below were generated by the user while running local commands'
)
)
).toBe(true)
expect(isNoiseMessage(msg('user', '[Request interrupted by user]'))).toBe(true)
})
it('flags inter-agent harness turns (teammate/agent messages)', () => {
expect(isNoiseMessage(msg('user', '<teammate-message>ping</teammate-message>'))).toBe(true)
expect(isNoiseMessage(msg('user', '<agent-message>status update'))).toBe(true)
})
it('keeps real user messages', () => {
expect(isNoiseMessage(msg('user', 'make it work for codex'))).toBe(false)
expect(isNoiseMessage(msg('user', '<bash-brothers> is my band'))).toBe(false)
@@ -60,13 +38,4 @@ describe('isNoiseMessage', () => {
).toBe(false)
}
})
it('stripNoiseMessages removes only the noise', () => {
const out = stripNoiseMessages([
msg('user', 'hello'),
msg('user', '<task-notification>done'),
msg('assistant', 'hi')
])
expect(out.map((m) => m.role)).toEqual(['user', 'assistant'])
})
})
@@ -1,7 +1,7 @@
import { createElement } from 'react'
import { act, create } from 'react-test-renderer'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { FONT_SCALE_STEP, quantizeFontScale } from './mobile-native-chat-message-text'
import { quantizeFontScale } from './mobile-native-chat-message-text'
const handlers: { start?: () => void; update?: (e: { scale: number }) => void } = {}
@@ -34,14 +34,6 @@ describe('quantizeFontScale', () => {
expect(quantizeFontScale(0.1)).toBe(0.8)
expect(quantizeFontScale(Number.NaN)).toBe(1)
})
it('collapses a full-range pinch to at most one commit per step', () => {
const committed = new Set<number>()
for (let i = 0; i <= 600; i++) {
committed.add(quantizeFontScale(0.7 + i * 0.002))
}
expect(committed.size).toBeLessThanOrEqual(Math.round(1 / FONT_SCALE_STEP) + 1)
})
})
describe('useMobileNativeChatPinchGesture', () => {
@@ -40,19 +40,7 @@ async function run(
return shown
}
const goneRow = { path: 'gone.txt', resolveActionId: 'resolve:gone.txt' }
describe('useMobileConflictRunners', () => {
it('sends the chosen resolution for the row to the host', async () => {
const sendGitRequest = vi.fn(async () => ({ ok: true }))
const shown = await run(sendGitRequest, (r) => r.resolveConflict(goneRow, 'keep_deletion'))
expect(shown).toBeNull()
expect(sendGitRequest).toHaveBeenCalledWith('git.resolveConflict', {
filePath: 'gone.txt',
resolution: 'keep_deletion'
})
})
it('shows Git’s refusal when the host reports Complete merge failed in its reply', async () => {
const sendGitRequest = vi.fn(async () => ({
success: false,
@@ -1,27 +0,0 @@
import { describe, expect, it } from 'vitest'
import { TUI_AGENT_CONFIG } from '../../../src/shared/agent-launch/catalog/tui-agent-config'
import { TUI_AGENT_DISPLAY_NAMES } from '../../../src/shared/agent-launch/catalog/tui-agent-display-names'
import { TUI_AGENT_AUTO_PICK_ORDER } from '../../../src/shared/agent-launch/catalog/tui-agent-selection'
import { MOBILE_AGENT_CATALOG } from './mobile-agent-catalog'
describe('mobile agent catalog', () => {
it('follows desktop auto-pick order and covers every configured TUI agent', () => {
expect(MOBILE_AGENT_CATALOG.map((agent) => agent.id)).toEqual([...TUI_AGENT_AUTO_PICK_ORDER])
expect(new Set(MOBILE_AGENT_CATALOG.map((agent) => agent.id))).toEqual(
new Set(Object.keys(TUI_AGENT_CONFIG))
)
})
it('labels every agent with the desktop display name', () => {
for (const entry of MOBILE_AGENT_CATALOG) {
expect(entry.label).toBe(TUI_AGENT_DISPLAY_NAMES[entry.id])
}
})
it('keeps Claude Agent Teams in the catalog without a favicon domain', () => {
const teams = MOBILE_AGENT_CATALOG.find((agent) => agent.id === 'claude-agent-teams')
expect(teams).toBeDefined()
expect(teams).not.toHaveProperty('faviconDomain')
})
})
@@ -1,33 +0,0 @@
import { describe, expect, it, vi } from 'vitest'
import type { AgentLaunchExecution } from './agent-launch-executor'
import type { AgentLaunchModeReceipt } from '../../shared/agent-launch/contracts/agent-launch-intent'
import type { AgentLaunchSurfaceFactory } from './agent-launch-surface-factories'
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: only the execution's type is checked; nothing runs it.
const runtime = {} as AgentLaunchExecution['runtime']
const decidedMode: AgentLaunchModeReceipt = {
mode: 'terminal',
preferred: 'terminal',
reason: 'user_default',
detail: 'Started a terminal agent, the default for new agent tabs in your settings.'
}
describe('a caller-decided launch mode', () => {
it('cannot be combined with the pre-flight inputs it replaces', () => {
const intent = {
agent: 'claude' as const,
target: { kind: 'existing' as const, worktree: 'wt' }
}
const surfaces: AgentLaunchSurfaceFactory = {
createStructuredSession: vi.fn(),
createTerminalAgent: vi.fn()
}
const accepts = (execution: AgentLaunchExecution) => execution
// @ts-expect-error a decided mode already settled what terminalOnly would force
accepts({ runtime, intent, surfaces, decidedMode, terminalOnly: true })
// @ts-expect-error a decided mode already settled what the caller's chat support would downgrade
accepts({ runtime, intent, surfaces, decidedMode, callerRendersStructured: false })
expect(accepts({ runtime, intent, surfaces, decidedMode }).decidedMode).toBe(decidedMode)
expect(accepts({ runtime, intent, surfaces, terminalOnly: true }).terminalOnly).toBe(true)
})
})
@@ -1,20 +1,7 @@
import { describe, it, expect, vi, afterEach } from 'vitest'
import { buildPrintToPdfOptions, CdpPdfStreamStore } from './cdp-print-to-pdf'
const DEFAULT_MARGIN_INCHES = 1 / 2.54
import { CdpPdfStreamStore } from './cdp-print-to-pdf'
const TTL_MS = 5 * 60 * 1000
describe('buildPrintToPdfOptions', () => {
it('defaults omitted margin sides to 1cm when any side is set', () => {
expect(buildPrintToPdfOptions({ marginTop: 0.25 }).margins).toEqual({
top: 0.25,
bottom: DEFAULT_MARGIN_INCHES,
left: DEFAULT_MARGIN_INCHES,
right: DEFAULT_MARGIN_INCHES
})
})
})
describe('CdpPdfStreamStore', () => {
afterEach(() => {
vi.useRealTimers()
@@ -52,22 +52,6 @@ describe('clientRouteCookieImportSources', () => {
expect(clientRouteCookieImportSources('env-a')).toEqual({ default: chromeSource })
})
it('replaces the source on re-import of the same jar', () => {
recordClientRouteCookieImportSource({
environmentId: 'env-a',
profileId: 'default',
source: chromeSource
})
const edge = { browserFamily: 'edge' as const, importedAt: 2_000 }
recordClientRouteCookieImportSource({
environmentId: 'env-a',
profileId: 'default',
source: edge
})
expect(clientRouteCookieImportSources('env-a')).toEqual({ default: edge })
})
it('tolerates a corrupt store file by starting empty', () => {
recordClientRouteCookieImportSource({
environmentId: 'env-a',
@@ -67,11 +67,5 @@ describe('browserManager grab operations', () => {
expect(selection.kind).toBe('cancelled')
expect(selection.opId).toBe('op-1')
})
it('returns false if injection fails', async () => {
guestExecuteJavaScriptMock.mockRejectedValue(new Error('Injection failed'))
const result = await browserManager.setGrabMode('tab-1', true, guest)
expect(result).toBe(false)
})
})
})
@@ -1,80 +0,0 @@
/** Launch mode follows settings, with explicit fallback reasons; unsupported preference must not refuse ordinary worker-start. */
import { EVERY_AGENT_CHAT } from '../../../../shared/native-chat/every-agent-chat.test-fixture'
import { describe, expect, it } from 'vitest'
import {
decideWorkerStartMode,
downgradeWorkerStartModeForHost
} from './orchestration-worker-start-mode'
import type { AgentLaunchModeReceipt as WorkerStartModeReceipt } from '../../../../shared/agent-launch/contracts/agent-launch-intent'
const STRUCTURED_DEFAULT = {
nativeChatProviders: EVERY_AGENT_CHAT
}
function decide(
overrides: {
params?: Parameters<typeof decideWorkerStartMode>[0]['params']
settings?: Parameters<typeof decideWorkerStartMode>[0]['settings']
} = {}
): WorkerStartModeReceipt {
return decideWorkerStartMode({
params: { agent: 'claude', ...overrides.params },
settings: overrides.settings === undefined ? STRUCTURED_DEFAULT : overrides.settings
})
}
describe('worker start mode from the user default', () => {
it.each(['claude', 'codex'] as const)('starts a local %s worker structured', (agent) => {
expect(decide({ params: { agent } })).toMatchObject({
mode: 'structured',
preferred: 'structured',
reason: 'user_default'
})
})
it.each([
['the agent is set to CLI', { ...STRUCTURED_DEFAULT, nativeChatProviders: { claude: false } }],
['the agent has no saved choice', {}],
['no settings at all', null]
])('starts a terminal worker when %s', (_name, settings) => {
expect(decide({ settings })).toMatchObject({
mode: 'terminal',
preferred: 'terminal',
reason: 'user_default'
})
})
})
describe('a structured default this dispatch cannot honour', () => {
it.each([
['a remote --on', { on: 'server-1' }, 'remote_execution_host'],
['an existing --terminal', { terminal: 'term_1' }, 'reused_terminal'],
['a non-structured agent', { agent: 'cursor' }, 'agent_without_structured_session']
])('falls back to a terminal worker for %s', (_name, params, reason) => {
const receipt = decide({ params: { agent: 'claude', ...params } })
expect(receipt).toMatchObject({ mode: 'terminal', preferred: 'structured', reason })
// Never a silent fallback: the receipt states the default AND why it did not apply.
expect(receipt.detail).toContain('Your default is a structured chat session')
})
})
describe('the executing host settles what the client cannot', () => {
it.each([
['wsl', 'wsl_execution_runtime'],
['remote', 'remote_execution_host'],
['agent', 'structured_unsupported_on_host']
] as const)('downgrades on a %s refusal', (reason, expected) => {
expect(downgradeWorkerStartModeForHost(decide(), { supported: false, reason })).toMatchObject({
mode: 'terminal',
preferred: 'structured',
reason: expected
})
})
it('downgrades on a refusal that names no reason', () => {
expect(downgradeWorkerStartModeForHost(decide(), { supported: false }).reason).toBe(
'structured_unsupported_on_host'
)
})
})
@@ -1,98 +0,0 @@
import React from 'react'
import { describe, expect, it, vi } from 'vitest'
import { BrowserAnnotationSendMenuContent } from './BrowserAnnotationSendMenuContent'
type ReactElementLike = {
type: unknown
props: Record<string, unknown>
}
vi.mock('@/components/editor/ReviewNotesSendMenuContent', () => ({
ReviewNotesSendMenuContent: function ReviewNotesSendMenuContent(props: Record<string, unknown>) {
return { type: 'ReviewNotesSendMenuContent', props }
}
}))
function expand(node: unknown): unknown {
if (node == null || typeof node === 'string' || typeof node === 'number') {
return node
}
if (Array.isArray(node)) {
return node.map((entry) => expand(entry))
}
if (!React.isValidElement(node)) {
if (typeof node === 'object' && 'props' in node) {
const element = node as ReactElementLike
return {
...element,
props: {
...element.props,
children: expand(element.props.children)
}
}
}
return node
}
const element = node as React.ReactElement<Record<string, unknown>>
if (typeof element.type === 'function') {
const Component = element.type as (props: Record<string, unknown>) => unknown
return expand(Component(element.props))
}
return {
type: element.type,
props: {
...element.props,
children: expand(element.props.children)
}
}
}
function findByType(node: unknown, type: string): ReactElementLike {
if (node && typeof node === 'object' && 'type' in node) {
const element = node as ReactElementLike
if (element.type === type) {
return element
}
const children = element.props.children
if (Array.isArray(children)) {
for (const child of children) {
try {
return findByType(child, type)
} catch {
// Continue searching siblings.
}
}
} else if (children) {
return findByType(children, type)
}
}
throw new Error(`Unable to find ${type}`)
}
describe('BrowserAnnotationSendMenuContent', () => {
it('forwards annotation content and delivery callbacks to the review notes menu', () => {
const onPromptDelivered = vi.fn()
const onPromptHandedOff = vi.fn()
const tree = expand(
<BrowserAnnotationSendMenuContent
worktreeId="wt-1"
groupId="group-1"
prompt="browser annotation prompt"
includePageDetails={false}
onIncludePageDetailsChange={vi.fn()}
onPromptDelivered={onPromptDelivered}
onPromptHandedOff={onPromptHandedOff}
/>
)
expect(findByType(tree, 'ReviewNotesSendMenuContent').props).toMatchObject({
worktreeId: 'wt-1',
groupId: 'group-1',
prompt: 'browser annotation prompt',
promptDelivery: 'submit-after-ready',
launchSource: 'notes_send',
onPromptDelivered,
onPromptHandedOff
})
})
})
@@ -49,24 +49,6 @@ describe('issue detail cache repository identity', () => {
}
)
it('keeps RPC detail caches bound to the addressed repository', () => {
const sourceContext: TaskSourceContext = {
kind: 'task-source',
provider: 'github',
projectId: 'project-1',
hostId: 'runtime:env-1',
repoId: 'runtime-repo'
}
const args = { ...keyArgs, ownerRepo: ORIGIN, sourceContext }
expect(getWorkItemDetailsCacheKey(args)).toBe(
getWorkItemDetailsCacheKey({ ...args, issueSourcePreference: 'upstream' })
)
expect(getWorkItemDetailsCacheKey(args)).not.toBe(
getWorkItemDetailsCacheKey({ ...args, ownerRepo: null })
)
})
it('invalidates both repository variants after a mutation', () => {
const originKey = getWorkItemDetailsCacheKey({ ...keyArgs, ownerRepo: ORIGIN })
const upstreamKey = getWorkItemDetailsCacheKey({ ...keyArgs, ownerRepo: UPSTREAM })
@@ -1,67 +0,0 @@
// @vitest-environment happy-dom
import '@testing-library/jest-dom/vitest'
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { ZcodeCliSetupSection } from './ZcodeCliSetupSection'
const mocks = vi.hoisted(() => ({ settings: { agentCmdOverrides: { zcode: '' } } }))
vi.mock('@/store/index', () => ({
useAppStore: (selector: (state: unknown) => unknown) => selector(mocks)
}))
vi.mock('../../../onboarding/OnboardingInlineCommandTerminal', () => ({
OnboardingInlineCommandTerminal: ({
command,
description
}: {
command: string
description: string
}) => (
<div data-testid="setup-terminal">
<output>{command}</output>
<p>{description}</p>
</div>
)
}))
vi.mock('../../section-layout/SearchableSetting', () => ({
SearchableSetting: ({ children }: { children: React.ReactNode }) => <div>{children}</div>
}))
beforeEach(() => {
mocks.settings.agentCmdOverrides.zcode = ''
})
afterEach(() => cleanup())
describe('ZCode CLI-owned sign-in setup', () => {
it.each([
['Z.AI browser sign-in', 'zcode login zai --no-browser'],
['BigModel browser sign-in', 'zcode login bigmodel --no-browser'],
['ZCode API-key setup', 'zcode']
])('delegates %s to the supported upstream CLI command', async (label, command) => {
render(<ZcodeCliSetupSection />)
fireEvent.click(screen.getByRole('button', { name: label }))
expect(await screen.findByTestId('setup-terminal')).toHaveTextContent(command)
expect(screen.getByRole('button', { name: 'Z.AI browser sign-in' })).toBeDisabled()
expect(screen.getByRole('button', { name: 'BigModel browser sign-in' })).toBeDisabled()
expect(screen.getByRole('button', { name: 'ZCode API-key setup' })).toBeDisabled()
if (label === 'ZCode API-key setup') {
expect(screen.getByText(/enter \/login.*masked prompt/)).toBeInTheDocument()
} else {
expect(screen.getByText(/authorization URL printed by ZCode/)).toBeInTheDocument()
}
fireEvent.click(screen.getByRole('button', { name: 'Close setup terminal' }))
expect(screen.queryByTestId('setup-terminal')).not.toBeInTheDocument()
expect(screen.getByRole('button', { name: label })).toBeEnabled()
})
it('preserves the configured CLI executable instead of inventing model flags', async () => {
mocks.settings.agentCmdOverrides.zcode = 'node "C:\\ZCode CLI\\zcode.cjs"'
render(<ZcodeCliSetupSection />)
fireEvent.click(screen.getByRole('button', { name: 'BigModel browser sign-in' }))
expect(await screen.findByTestId('setup-terminal')).toHaveTextContent(
'node "C:\\ZCode CLI\\zcode.cjs" login bigmodel --no-browser'
)
expect(screen.getByTestId('setup-terminal')).not.toHaveTextContent('--model')
})
})
@@ -2,11 +2,7 @@ import { afterEach, describe, expect, it } from 'vitest'
import { i18n } from '@/i18n/i18n'
import es from '@/i18n/locales/es.json'
import { keybindingFileDiagnostic } from '../../../../../shared/keybindings/keybinding-diagnostic-copy'
import { normalizeKeybinding } from '../../../../../shared/keybindings/normalization'
import {
keybindingDiagnosticText,
keybindingValidationErrorText
} from './keybinding-diagnostic-text'
import { keybindingDiagnosticText } from './keybinding-diagnostic-text'
const originalLanguage = i18n.language
@@ -15,31 +11,6 @@ afterEach(async () => {
})
describe('keybinding diagnostic text', () => {
it('translates a diagnostic and its nested Orca reason as whole sentences', async () => {
i18n.addResourceBundle('es', 'translation', es)
await i18n.changeLanguage('es')
const invalid = normalizeKeybinding('Shift+P')
if (invalid.ok) {
throw new Error('expected a validation failure')
}
const reason = es.settings.shortcuts.validation.modifierRequired
expect(keybindingValidationErrorText(invalid)).toBe(reason)
const diagnostic = keybindingFileDiagnostic(
{ severity: 'error', actionId: 'terminal.search' },
'shortcutIgnored',
{ actionId: 'terminal.search', reason: invalid.error },
invalid.errorCode
)
expect(diagnostic.message).toBe(
'Shortcut for "terminal.search" was ignored: Include at least one modifier key.'
)
expect(keybindingDiagnosticText(diagnostic)).toBe(
es.settings.shortcuts.diagnostics.shortcutIgnored
.replace('{{actionId}}', 'terminal.search')
.replace('{{reason}}', reason)
)
})
it('keeps verbatim reasons and falls back to the English message', async () => {
i18n.addResourceBundle('es', 'translation', es)
await i18n.changeLanguage('es')
@@ -32,19 +32,6 @@ function mount(initial: number | undefined = undefined): ReturnType<typeof vi.fn
}
describe('terminal contrast modes', () => {
it('lets users turn correction off and restore automatic without editing a number', () => {
const persist = mount()
expect(screen.getByRole('radio', { name: 'Automatic' }).getAttribute('aria-checked')).toBe(
'true'
)
expect(screen.queryByRole('spinbutton')).toBeNull()
fireEvent.click(screen.getByRole('radio', { name: 'Off' }))
expect(persist).toHaveBeenLastCalledWith({ terminalMinimumContrastRatio: 1 })
expect(screen.queryByRole('spinbutton')).toBeNull()
fireEvent.click(screen.getByRole('radio', { name: 'Automatic' }))
expect(persist).toHaveBeenLastCalledWith({ terminalMinimumContrastRatio: undefined })
})
it('restores the custom target when toggling through off and automatic', () => {
const persist = mount(7)
fireEvent.click(screen.getByRole('radio', { name: 'Off' }))
@@ -45,21 +45,6 @@ describe('task page initial repo selection', () => {
expect(reads).toBeLessThan(40_000)
})
it('retains preferred selection, missing-ID fallback, and explicit empty defaults', () => {
const repos: Repo[] = ['a', 'b'].map((id) => ({
id,
path: `/repos/${id}`,
displayName: id,
badgeColor: '',
addedAt: 0,
kind: 'git'
}))
expect(resolveSelection(repos, ['b'], 'a')).toEqual(['a'])
expect(resolveSelection(repos, ['missing'])).toEqual(['a', 'b'])
expect(resolveSelection(repos, [])).toEqual(['a', 'b'])
expect(resolveSelection(repos, ['missing', 'b', 'b'])).toEqual(['b'])
})
it('ignores persisted IDs for ineligible repos, including folder workspaces', () => {
const repos: Repo[] = [
{
@@ -1,43 +0,0 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { waitForAgentReady } from './agent-ready-wait'
import { useAppStore } from '@/store'
import { inspectRuntimeTerminalProcess } from '@/runtime/runtime-terminal-inspection'
vi.mock('@/store', () => ({
useAppStore: {
getState: vi.fn()
}
}))
vi.mock('@/runtime/runtime-terminal-inspection', () => ({
inspectRuntimeTerminalProcess: vi.fn()
}))
vi.mock('../../../shared/shell-process-detection', () => ({
isShellProcess: vi.fn(() => false)
}))
describe('waitForAgentReady', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.stubGlobal('window', { setTimeout })
vi.mocked(useAppStore.getState).mockReturnValue({
ptyIdsByTabId: { 'tab-1': ['pty-1'] },
runtimePaneTitlesByTabId: {},
tabsByWorktree: {},
settings: {}
} as never)
})
it('recognizes a Windows foreground process reported as a full executable path', async () => {
vi.mocked(inspectRuntimeTerminalProcess).mockResolvedValue({
foregroundProcess: String.raw`C:\Users\dev\AppData\Roaming\npm\claude.exe`,
hasChildProcesses: false
})
await expect(waitForAgentReady('tab-1', 'claude', { timeoutMs: 100 })).resolves.toEqual({
ready: true,
reason: 'foreground-match'
})
})
})
@@ -1,8 +1,6 @@
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import { resetReactCommitCascadeTelemetryForTests } from './react-commit-cascade-telemetry'
import {
REACT_COMMIT_CASCADE_INSTALL_CHECK_MS,
REACT_COMMIT_CASCADE_UNINSTALLED_BREADCRUMB,
installReactCommitCascadeObserver,
resetReactCommitCascadeObserverForTests
} from './react-commit-cascade-observer'
@@ -50,24 +48,3 @@ describe('installReactCommitCascadeObserver', () => {
expect(previous).toHaveBeenCalledTimes(1)
})
})
// Import/hoist changes can silently disable diagnostics; self-check exposes that in field reports.
describe('install self-check', () => {
// Failed hook assignments must arm self-check too.
it('breadcrumbs when the hook refuses the callback assignment', () => {
vi.useFakeTimers()
resetReactCommitCascadeObserverForTests()
const frozenHook = Object.freeze({ isDisabled: false, supportsFiber: true })
;(globalThis as { __REACT_DEVTOOLS_GLOBAL_HOOK__?: unknown }).__REACT_DEVTOOLS_GLOBAL_HOOK__ =
frozenHook
expect(() => installReactCommitCascadeObserver()).not.toThrow()
vi.advanceTimersByTime(REACT_COMMIT_CASCADE_INSTALL_CHECK_MS)
expect((frozenHook as { onCommitFiberRoot?: unknown }).onCommitFiberRoot).toBeUndefined()
expect(recordBreadcrumb).toHaveBeenCalledWith(
REACT_COMMIT_CASCADE_UNINSTALLED_BREADCRUMB,
undefined
)
})
})
@@ -1,14 +1,7 @@
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { create, type StoreApi, type UseBoundStore } from 'zustand'
import { withReactCommitCascadeWriteProbe } from './react-commit-cascade-write-probe'
import { withEditorBufferRecords } from './editor-buffer-record-lifecycle'
import type { EditorBufferRecords } from './slices/editor/buffers/editor-buffer-record'
import type { OpenFile } from './slices/editor/types/open-file'
import type { ReactCommitCascadeWriteBoundary } from '@/lib/react-commit-cascade-store-write-samples'
import {
EMPTY_EDITOR_BUFFER_VIEW_INDEX,
type EditorBufferViewIndex
} from './slices/editor/buffers/editor-buffer-views'
const { probe, noteWrite } = vi.hoisted(() => ({
probe: { armed: false },
@@ -45,33 +38,4 @@ describe('withReactCommitCascadeWriteProbe', () => {
expect(() => useProbedStore.setState({ ticks: 3 })).not.toThrow()
expect(useProbedStore.getState().ticks).toBe(3)
})
// Buffer middleware must preserve caller partials/write frames or cascade reports lose distinct write sites/keys.
it('sees each original partial and caller under the editor buffer middleware', () => {
type BufferedState = EditorBufferViewIndex & {
ticks: number
openFiles: OpenFile[]
editorBuffers: EditorBufferRecords
tick: () => void
}
const useBufferedStore = create<BufferedState>()(
withEditorBufferRecords(
withReactCommitCascadeWriteProbe<BufferedState>((set) => ({
ticks: 0,
openFiles: [],
editorBuffers: {},
...EMPTY_EDITOR_BUFFER_VIEW_INDEX,
tick: () => set({ ticks: 1 })
}))
)
)
probe.armed = true
useBufferedStore.getState().tick()
useBufferedStore.setState({ ticks: 2 })
expect(noteWrite.mock.calls.map(([, partial]) => partial)).toEqual([{ ticks: 1 }, { ticks: 2 }])
expect(noteWrite.mock.calls[1]?.[0]).toBe(useBufferedStore.setState)
expect(useBufferedStore.getState().ticks).toBe(2)
})
})