diff --git a/config/reliability-gates.jsonc b/config/reliability-gates.jsonc index de29a74b232..9fdc4a4407d 100644 --- a/config/reliability-gates.jsonc +++ b/config/reliability-gates.jsonc @@ -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." diff --git a/config/scripts/ci-shard-timings.json b/config/scripts/ci-shard-timings.json index 2df7c624a09..249e45e31cb 100644 --- a/config/scripts/ci-shard-timings.json +++ b/config/scripts/ci-shard-timings.json @@ -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, diff --git a/mobile/src/components/CodexResetCreditAction.test.ts b/mobile/src/components/CodexResetCreditAction.test.ts deleted file mode 100644 index 55ed91711f5..00000000000 --- a/mobile/src/components/CodexResetCreditAction.test.ts +++ /dev/null @@ -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()) - }) -}) diff --git a/mobile/src/components/drag-reorder-positions.test.ts b/mobile/src/components/drag-reorder-positions.test.ts index a62545a41c5..014fac91ffe 100644 --- a/mobile/src/components/drag-reorder-positions.test.ts +++ b/mobile/src/components/drag-reorder-positions.test.ts @@ -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', () => { diff --git a/mobile/src/components/use-new-worktree-drawer-navigation.test.ts b/mobile/src/components/use-new-worktree-drawer-navigation.test.ts deleted file mode 100644 index dc0d8e5151b..00000000000 --- a/mobile/src/components/use-new-worktree-drawer-navigation.test.ts +++ /dev/null @@ -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 -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('source') - - act(() => nav.current.transitionDrawer('form')) - expect(nav.current.drawerView).toBe('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('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('form') - expect(nav.current.formSheetVisible).toBe(true) - expect(nav.current.formSheetInteractive).toBe(true) - }) -}) diff --git a/mobile/src/files/MobileMarkdownPreviewImage.test.tsx b/mobile/src/files/MobileMarkdownPreviewImage.test.tsx index dc43cc7abfd..a0a8bb37203 100644 --- a/mobile/src/files/MobileMarkdownPreviewImage.test.tsx +++ b/mobile/src/files/MobileMarkdownPreviewImage.test.tsx @@ -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')) diff --git a/mobile/src/session/MobileQueuedMessageScrollList.test.tsx b/mobile/src/session/MobileQueuedMessageScrollList.test.tsx deleted file mode 100644 index d955839d89c..00000000000 --- a/mobile/src/session/MobileQueuedMessageScrollList.test.tsx +++ /dev/null @@ -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( - - {() => 'queued body'} - - ) - }) - 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) -}) diff --git a/mobile/src/session/mobile-dictation-disabled-controls.test.tsx b/mobile/src/session/mobile-dictation-disabled-controls.test.tsx index 3c226f75be0..f59cb52411f 100644 --- a/mobile/src/session/mobile-dictation-disabled-controls.test.tsx +++ b/mobile/src/session/mobile-dictation-disabled-controls.test.tsx @@ -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 - 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 = { diff --git a/mobile/src/session/mobile-session-connection-retry.test.tsx b/mobile/src/session/mobile-session-connection-retry.test.tsx deleted file mode 100644 index 05ca77d2954..00000000000 --- a/mobile/src/session/mobile-session-connection-retry.test.tsx +++ /dev/null @@ -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 - -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[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" - }) - }) -}) diff --git a/mobile/src/session/mobile-session-route.test.ts b/mobile/src/session/mobile-session-route.test.ts index 061af6d1568..3dfbcc3165a 100644 --- a/mobile/src/session/mobile-session-route.test.ts +++ b/mobile/src/session/mobile-session-route.test.ts @@ -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() diff --git a/mobile/src/session/mobile-structured-agent-prompts-free-text.test.ts b/mobile/src/session/mobile-structured-agent-prompts-free-text.test.ts index 5d50efe23dc..950672cc3c7 100644 --- a/mobile/src/session/mobile-structured-agent-prompts-free-text.test.ts +++ b/mobile/src/session/mobile-structured-agent-prompts-free-text.test.ts @@ -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)! diff --git a/mobile/src/session/native-chat/input/use-mobile-native-chat-queued-edit-focus.test.tsx b/mobile/src/session/native-chat/input/use-mobile-native-chat-queued-edit-focus.test.tsx index afa12b94d94..2afa78903dc 100644 --- a/mobile/src/session/native-chat/input/use-mobile-native-chat-queued-edit-focus.test.tsx +++ b/mobile/src/session/native-chat/input/use-mobile-native-chat-queued-edit-focus.test.tsx @@ -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() - }) }) diff --git a/mobile/src/session/native-chat/mobile-native-chat-merger-oracle.test.ts b/mobile/src/session/native-chat/mobile-native-chat-merger-oracle.test.ts index 0ccef42ae0f..d0f7b928f97 100644 --- a/mobile/src/session/native-chat/mobile-native-chat-merger-oracle.test.ts +++ b/mobile/src/session/native-chat/mobile-native-chat-merger-oracle.test.ts @@ -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')]) diff --git a/mobile/src/session/native-chat/mobile-native-chat-noise.test.ts b/mobile/src/session/native-chat/mobile-native-chat-noise.test.ts index a579a9a3e69..0c2fee7e19c 100644 --- a/mobile/src/session/native-chat/mobile-native-chat-noise.test.ts +++ b/mobile/src/session/native-chat/mobile-native-chat-noise.test.ts @@ -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', '\nx'))).toBe(true) - expect(isNoiseMessage(msg('user', '\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', 'ping'))).toBe(true) - expect(isNoiseMessage(msg('user', 'status update'))).toBe(true) - }) - it('keeps real user messages', () => { expect(isNoiseMessage(msg('user', 'make it work for codex'))).toBe(false) expect(isNoiseMessage(msg('user', ' 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', 'done'), - msg('assistant', 'hi') - ]) - expect(out.map((m) => m.role)).toEqual(['user', 'assistant']) - }) }) diff --git a/mobile/src/session/native-chat/transcript/use-mobile-native-chat-pinch-gesture.test.ts b/mobile/src/session/native-chat/transcript/use-mobile-native-chat-pinch-gesture.test.ts index 770ac1d8cc7..a7666ee51a9 100644 --- a/mobile/src/session/native-chat/transcript/use-mobile-native-chat-pinch-gesture.test.ts +++ b/mobile/src/session/native-chat/transcript/use-mobile-native-chat-pinch-gesture.test.ts @@ -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() - 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', () => { diff --git a/mobile/src/source-control/use-mobile-conflict-runners.test.ts b/mobile/src/source-control/use-mobile-conflict-runners.test.ts index 8ae59493276..ce1037fa719 100644 --- a/mobile/src/source-control/use-mobile-conflict-runners.test.ts +++ b/mobile/src/source-control/use-mobile-conflict-runners.test.ts @@ -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, diff --git a/mobile/src/tasks/mobile-agent-catalog.test.ts b/mobile/src/tasks/mobile-agent-catalog.test.ts deleted file mode 100644 index b9e1e1123fd..00000000000 --- a/mobile/src/tasks/mobile-agent-catalog.test.ts +++ /dev/null @@ -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') - }) -}) diff --git a/src/main/agent-launch/agent-launch-decided-mode-contract.test.ts b/src/main/agent-launch/agent-launch-decided-mode-contract.test.ts deleted file mode 100644 index 6d0fe5f8436..00000000000 --- a/src/main/agent-launch/agent-launch-decided-mode-contract.test.ts +++ /dev/null @@ -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) - }) -}) diff --git a/src/main/browser/cdp/commands/cdp-print-to-pdf.test.ts b/src/main/browser/cdp/commands/cdp-print-to-pdf.test.ts index abcf76ccf21..200a96efab9 100644 --- a/src/main/browser/cdp/commands/cdp-print-to-pdf.test.ts +++ b/src/main/browser/cdp/commands/cdp-print-to-pdf.test.ts @@ -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() diff --git a/src/main/browser/cookies/client-route/client-route-cookie-import-source-store.test.ts b/src/main/browser/cookies/client-route/client-route-cookie-import-source-store.test.ts index d99beca73e8..b706d90e5b3 100644 --- a/src/main/browser/cookies/client-route/client-route-cookie-import-source-store.test.ts +++ b/src/main/browser/cookies/client-route/client-route-cookie-import-source-store.test.ts @@ -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', diff --git a/src/main/browser/guest-lifecycle/manager/browser-manager-grab-mode.test.ts b/src/main/browser/guest-lifecycle/manager/browser-manager-grab-mode.test.ts index 67f01bde8b6..387021b26f8 100644 --- a/src/main/browser/guest-lifecycle/manager/browser-manager-grab-mode.test.ts +++ b/src/main/browser/guest-lifecycle/manager/browser-manager-grab-mode.test.ts @@ -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) - }) }) }) diff --git a/src/main/runtime/rpc/methods/orchestration-worker-start-mode.test.ts b/src/main/runtime/rpc/methods/orchestration-worker-start-mode.test.ts deleted file mode 100644 index 06e2718810c..00000000000 --- a/src/main/runtime/rpc/methods/orchestration-worker-start-mode.test.ts +++ /dev/null @@ -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[0]['params'] - settings?: Parameters[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' - ) - }) -}) diff --git a/src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx b/src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx deleted file mode 100644 index e2740e43f65..00000000000 --- a/src/renderer/src/components/browser-pane/annotate/BrowserAnnotationSendMenuContent.test.tsx +++ /dev/null @@ -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 -} - -vi.mock('@/components/editor/ReviewNotesSendMenuContent', () => ({ - ReviewNotesSendMenuContent: function ReviewNotesSendMenuContent(props: Record) { - 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> - if (typeof element.type === 'function') { - const Component = element.type as (props: Record) => 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( - - ) - - 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 - }) - }) -}) diff --git a/src/renderer/src/components/github-item-dialog/load-item-details/work-item-details-issue-target.test.ts b/src/renderer/src/components/github-item-dialog/load-item-details/work-item-details-issue-target.test.ts index 3bfdbec9adf..44b63d85f15 100644 --- a/src/renderer/src/components/github-item-dialog/load-item-details/work-item-details-issue-target.test.ts +++ b/src/renderer/src/components/github-item-dialog/load-item-details/work-item-details-issue-target.test.ts @@ -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 }) diff --git a/src/renderer/src/components/settings/agents/launch/ZcodeCliSetupSection.test.tsx b/src/renderer/src/components/settings/agents/launch/ZcodeCliSetupSection.test.tsx deleted file mode 100644 index c6f19164c8f..00000000000 --- a/src/renderer/src/components/settings/agents/launch/ZcodeCliSetupSection.test.tsx +++ /dev/null @@ -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 - }) => ( -
- {command} -

{description}

-
- ) -})) -vi.mock('../../section-layout/SearchableSetting', () => ({ - SearchableSetting: ({ children }: { children: React.ReactNode }) =>
{children}
-})) - -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() - 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() - 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') - }) -}) diff --git a/src/renderer/src/components/settings/shortcuts/keybinding-diagnostic-text.test.ts b/src/renderer/src/components/settings/shortcuts/keybinding-diagnostic-text.test.ts index 5a3aa32c0c2..e9aabe0cd0e 100644 --- a/src/renderer/src/components/settings/shortcuts/keybinding-diagnostic-text.test.ts +++ b/src/renderer/src/components/settings/shortcuts/keybinding-diagnostic-text.test.ts @@ -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') diff --git a/src/renderer/src/components/settings/terminal/appearance/TerminalContrastSetting.test.tsx b/src/renderer/src/components/settings/terminal/appearance/TerminalContrastSetting.test.tsx index 6a62b064a27..83bb651cf0b 100644 --- a/src/renderer/src/components/settings/terminal/appearance/TerminalContrastSetting.test.tsx +++ b/src/renderer/src/components/settings/terminal/appearance/TerminalContrastSetting.test.tsx @@ -32,19 +32,6 @@ function mount(initial: number | undefined = undefined): ReturnType { - 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' })) diff --git a/src/renderer/src/components/task-page/task-page-initial-selection-scaling.test.tsx b/src/renderer/src/components/task-page/task-page-initial-selection-scaling.test.tsx index 80412adbd3c..80c91dda2f3 100644 --- a/src/renderer/src/components/task-page/task-page-initial-selection-scaling.test.tsx +++ b/src/renderer/src/components/task-page/task-page-initial-selection-scaling.test.tsx @@ -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[] = [ { diff --git a/src/renderer/src/lib/agent-ready-wait.test.ts b/src/renderer/src/lib/agent-ready-wait.test.ts deleted file mode 100644 index 2c413a61349..00000000000 --- a/src/renderer/src/lib/agent-ready-wait.test.ts +++ /dev/null @@ -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' - }) - }) -}) diff --git a/src/renderer/src/lib/react-commit-cascade-observer.test.ts b/src/renderer/src/lib/react-commit-cascade-observer.test.ts index f2704433f61..1d8efb136ae 100644 --- a/src/renderer/src/lib/react-commit-cascade-observer.test.ts +++ b/src/renderer/src/lib/react-commit-cascade-observer.test.ts @@ -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 - ) - }) -}) diff --git a/src/renderer/src/store/react-commit-cascade-write-probe.test.ts b/src/renderer/src/store/react-commit-cascade-write-probe.test.ts index 5928adf0361..c811fb30403 100644 --- a/src/renderer/src/store/react-commit-cascade-write-probe.test.ts +++ b/src/renderer/src/store/react-commit-cascade-write-probe.test.ts @@ -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()( - withEditorBufferRecords( - withReactCommitCascadeWriteProbe((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) - }) })